mivfx/main.c

457 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <stdbool.h>
#include <curl/curl.h>
#include <string.h>
#include <unistd.h>
#define DELAY_MS 50
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture = NULL;
bool quit = false;
bool hasdownloaded = false; // DDoSを避ける為
float aspectRatio;
int imgX = 10;
int imgY = 10;
int imgWidth;
int imgHeight;
int screenWidth;
int screenHeight;
int init = 0;
char *imgfilename;
char *imgurl;
SDL_Rect renderQuad;
float newWidth;
float newHeight;
// マウス
int mouseX = 10;
int mouseY = 10;
int drag = 0;
// ズーム
float zoom = 1.0f;
// 回転
float angle = 0.0f;
// 反転
bool flippedH = false;
bool flippedV = false;
const char *sofname = "mivfx";
const char *version = "0.6.0";
bool dlfile(const char *url, const char *filename) {
CURL *curl = curl_easy_init();
if (!curl) {
return false;
}
FILE *file = fopen(filename, "wb");
if (!file) {
return false;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
// Clownflareは面倒くさいわね・・・
curl_easy_setopt(
curl,
CURLOPT_USERAGENT,
"Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0"
);
// Pixivも結構面倒くさい
if (
strstr("s.pximg.net", url) == 0 ||
strstr("i.pximg.net", url) == 0
) {
curl_easy_setopt(curl, CURLOPT_REFERER, "https://www.pixiv.net/");
}
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
CURLcode res = curl_easy_perform(curl);
fclose(file);
if (res != CURLE_OK) {
remove(filename);
return false;
}
return true;
}
char *fromurl(char *imgfile, char *dir) {
char s[512], *p, *tokens[128];
char *last;
int i = 0;
imgurl = imgfile;
snprintf(s, sizeof(s), "%s", imgfile);
for (
(p = strtok_r(s, "/", &last));
p;
(p = strtok_r(NULL, "/", &last))
) {
if (i < 127) tokens[i++] = p;
}
tokens[i] = NULL;
imgfilename = tokens[i - 1];
char *res;
res = (char *)malloc(1024);
if (res == NULL) {
return NULL;
}
snprintf(res, 1024, "%s/%s", dir, imgfilename);
if (!dlfile(imgfile, res)) {
printf("画像をダウンロードに失敗。URL: %s\n", imgfile);
return NULL;
}
return res;
}
void RenderCopy(SDL_Rect renderQuad) {
SDL_RenderCopyEx(
renderer,
texture,
NULL,
&renderQuad,
angle,
NULL,
flippedV ? SDL_FLIP_VERTICAL : (flippedH ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE)
);
}
void rotateWindow(int w, int h) {
if (angle >= 360.0f) angle = 0.0f;
else if (angle <= -360.0f) angle = 0.0f;
else if (angle == 270.0f) angle = -90.0f;
else if (angle == -180.0f) angle = 180.0f;
imgWidth = h;
imgHeight = w;
aspectRatio = (float)imgWidth / imgHeight;
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_RenderClear(renderer);
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
SDL_RenderPresent(renderer);
}
void windowevent(SDL_Event e) {
int windowWidth, windowHeight;
SDL_GetWindowSize(window, &windowWidth, &windowHeight);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
if (e.type == SDL_QUIT) {
quit = true;
} else if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_q) {
quit = true;
} else if (e.key.keysym.sym == SDLK_e) {
// GIFアニメーションの停止・続き、0.7.0から追加する予定
} else if (e.key.keysym.sym == SDLK_r) {
angle -= 90.0f;
rotateWindow(imgWidth, imgHeight);
} else if (e.key.keysym.sym == SDLK_t) {
angle += 90.0f;
rotateWindow(imgWidth, imgHeight);
} else if (e.key.keysym.sym == SDLK_y) {
SDL_RenderClear(renderer);
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
flippedV = !flippedV;
SDL_RenderPresent(renderer);
} else if (e.key.keysym.sym == SDLK_u) {
SDL_RenderClear(renderer);
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
flippedH = !flippedH;
SDL_RenderPresent(renderer);
} else if (e.key.keysym.sym == SDLK_o) {
bool isurl = strncmp(imgurl, "http://", 7) == 0 ||
strncmp(imgurl, "https://", 8) == 0;
if (isurl && !hasdownloaded) {
char path[1024];
getcwd(path, 1024);
if (fromurl(imgurl, path) != NULL) puts("ダウンロード済み");
hasdownloaded = true;
}
} else if (e.key.keysym.sym == SDLK_p) {
// 画像をrsync|sftp|http postで使って共有する、0.7.0から追加する予定
}
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
if (e.button.button == SDL_BUTTON_LEFT) {
drag = 1;
SDL_GetMouseState(&mouseX, &mouseY);
}
} else if (e.type == SDL_MOUSEBUTTONUP) {
if (e.button.button == SDL_BUTTON_LEFT) {
drag = 0;
}
} else if (e.type == SDL_MOUSEMOTION) {
if (drag) {
int newMouseX, newMouseY;
SDL_GetMouseState(&newMouseX, &newMouseY);
SDL_RenderClear(renderer);
if (newWidth != 0.0f) imgWidth = (newWidth);
if (newHeight != 0.0f) imgHeight = (newHeight);
imgX = newMouseX - (imgWidth / 2);
imgY = newMouseY - (imgHeight / 2);
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
SDL_RenderPresent(renderer);
}
} else if (e.type == SDL_MOUSEWHEEL) {
int curWidth = imgWidth;
int curHeight = imgHeight;
float zoomSpeed = 0.1f;
if (e.wheel.y > 0) {
zoom += zoomSpeed;
} else if (e.wheel.y < 0) {
zoom -= zoomSpeed;
}
if (zoom < 0.1f) {
zoom = 0.1f;
}
// 画像のサイズが変わった場合
newWidth = (float)imgWidth * zoom;
newHeight = (float)imgHeight * zoom;
float minLimit = 50.0f;
// 画像は50x50以下じゃ駄目
if (newWidth < minLimit) {
newWidth = minLimit;
newHeight = curHeight;
} else if (newHeight < minLimit) {
printf("%d\n", curWidth);
newWidth = curWidth;
newHeight = minLimit;
}
// テキスチャーのレンダーリングサイズの設定
SDL_RenderClear(renderer);
imgWidth = (int)newWidth;
imgHeight = (int)newHeight;
imgX = (windowWidth - imgWidth) / 2;
imgY = (windowHeight - imgHeight) / 2;
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
SDL_RenderPresent(renderer);
} else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) {
SDL_RenderClear(renderer);
// ウィンドウのサイズが変わった場合
int newWidth = e.window.data1;
int newHeight = e.window.data2;
// 縦横比を変わらずに新しい大きさの算数
float newAspectRatio = (float)newWidth / newHeight;
int scaledWidth, scaledHeight;
if (newAspectRatio != aspectRatio) {
// 画像よりウィンドウの方が広い場合
scaledHeight = angle == 90 || angle == -90 ? newWidth : newHeight;
scaledHeight = newHeight;
scaledWidth = (int)(scaledHeight * aspectRatio);
} else {
// 画像よりウィンドウの方が高い場合
scaledWidth = angle == 90 || angle == -90 ? newHeight : newWidth;
scaledHeight = angle == 90 || angle == -90 ? newWidth : newHeight;
}
// 画像は50x50以下じゃ駄目
int minWidth = 50;
int minHeight = 50;
if (scaledWidth < minWidth) scaledWidth = minWidth;
if (scaledHeight < minHeight) scaledHeight = minHeight;
// 大きすぎの場合もふざけんな
if (scaledWidth >= (screenWidth-20)) scaledWidth = screenWidth-20;
if (scaledHeight >= (screenHeight-20)) scaledHeight = screenHeight-20;
imgWidth = scaledWidth;
imgHeight = scaledHeight;
// テキスチャーのレンダーリングサイズの設定
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
SDL_RenderPresent(renderer);
} else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_MOVED) {
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
SDL_RenderPresent(renderer);
} else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_EXPOSED) {
if (init == 1) return;
init = 1;
SDL_RenderClear(renderer);
if (
(imgWidth >= (screenWidth - 100)) &&
imgHeight >= (screenHeight - 100)
) {
imgWidth = (screenWidth - 100);
imgHeight = (screenHeight - 100);
} else if (
(imgWidth >= (screenWidth - 100)) &&
imgHeight <= (screenHeight - 100)
) {
imgWidth = (screenWidth - 100);
imgHeight = (imgWidth * aspectRatio);
} else if (
(imgWidth <= (screenWidth - 100)) &&
imgHeight >= (screenHeight - 100)
) {
imgHeight = (screenHeight - 100);
imgWidth = (imgHeight * aspectRatio);
}
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
RenderCopy(renderQuad);
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
SDL_RenderPresent(renderer);
}
}
void usage() {
printf("%s-%s\nusage: %s [file or url]\n", sofname, version, sofname);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
usage();
return 1;
}
// SDL2とSDL2_imageの初期設定
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDLを初期設定出来なかった%s\n", SDL_GetError());
return 1;
}
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
printf("SDL_imageを初期設定出来なかった%s\n", SDL_GetError());
SDL_Quit();
return 1;
}
const char *imgfile = argv[1];
// URLの場合、仮にダウンロードして
bool isurl = strncmp(imgfile, "http://", 7) == 0 ||
strncmp(imgfile, "https://", 8) == 0;
imgfile = isurl ? fromurl(argv[1], "/tmp") : argv[1];
if (imgfile == NULL) {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
// 画像の読込
SDL_Surface *imgsurface = IMG_Load(imgfile);
if (imgsurface == NULL) {
printf("画像の読込に失敗:%s\n", IMG_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// 画像の大きさの受取
imgWidth = imgsurface->w;
imgHeight = imgsurface->h;
aspectRatio = (float)imgWidth / imgHeight;
// 画面の大きさの受取
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
screenWidth = DM.w;
screenHeight = DM.h;
// ウィンドウの大きさの設定
int windowWidth = (imgWidth >= (screenWidth-20)) ? screenWidth-20 : imgWidth;
int windowHeight = (imgHeight >= (screenHeight-20)) ? screenHeight-20 : imgHeight;
// ウィンドウの作成
SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, "1");
window = SDL_CreateWindow(
"mivfx",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
windowWidth,
windowHeight,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
if (window == NULL) {
printf("ウィンドウの作成に失敗:%s\n", SDL_GetError());
SDL_Quit();
return 1;
}
// レンダーの作成
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
printf("レンダーの作成に失敗:%s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
texture = SDL_CreateTextureFromSurface(renderer, imgsurface);
SDL_FreeSurface(imgsurface);
if (texture == NULL) {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// メインループ
SDL_Event e;
while (!quit) {
// イベント
while (SDL_PollEvent(&e) != 0) {
windowevent(e);
}
// 休ませる
SDL_Delay(DELAY_MS);
}
// 掃除
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
return 0;
}