mivfx/main.c

457 行
12 KiB
C
Raw パーマリンク 通常表示 履歴

2023-12-18 18:25:07 +09:00
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
2023-10-24 12:16:55 +09:00
#include <stdio.h>
2023-12-18 18:25:07 +09:00
#include <stdbool.h>
#include <curl/curl.h>
2024-05-24 19:27:56 +09:00
#include <string.h>
#include <unistd.h>
2024-02-14 23:25:53 +09:00
#define DELAY_MS 50
2023-10-24 12:16:55 +09:00
2024-05-24 19:27:56 +09:00
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture = NULL;
bool quit = false;
2024-05-24 19:27:56 +09:00
bool hasdownloaded = false; // DDoSを避ける為
2024-04-07 15:16:52 +09:00
float aspectRatio;
2024-05-24 18:33:56 +09:00
int imgX = 10;
int imgY = 10;
2024-04-07 15:16:52 +09:00
int imgWidth;
int imgHeight;
int screenWidth;
int screenHeight;
int init = 0;
2024-05-24 19:27:56 +09:00
char *imgfilename;
char *imgurl;
SDL_Rect renderQuad;
float newWidth;
float newHeight;
2024-05-02 20:21:50 +09:00
// マウス
int mouseX = 10;
int mouseY = 10;
int drag = 0;
2024-05-02 20:21:50 +09:00
2024-05-02 19:58:42 +09:00
// ズーム
float zoom = 1.0f;
// 回転
float angle = 0.0f;
2024-05-22 21:51:59 +09:00
// 反転
bool flippedH = false;
bool flippedV = false;
2024-05-24 19:27:56 +09:00
const char *sofname = "mivfx";
const char *version = "0.6.0";
2024-04-07 15:21:44 +09:00
2024-05-24 19:27:56 +09:00
bool dlfile(const char *url, const char *filename) {
CURL *curl = curl_easy_init();
if (!curl) {
return false;
}
2024-05-24 19:27:56 +09:00
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;
}
2024-05-24 19:27:56 +09:00
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;
2024-05-24 18:33:56 +09:00
else if (angle == 270.0f) angle = -90.0f;
else if (angle == -180.0f) angle = 180.0f;
2024-05-22 21:24:19 +09:00
imgWidth = h;
imgHeight = w;
aspectRatio = (float)imgWidth / imgHeight;
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
SDL_RenderClear(renderer);
2024-05-24 18:33:56 +09:00
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;
2024-05-22 21:51:59 +09:00
} else if (e.key.keysym.sym == SDLK_e) {
// GIFアニメーションの停止・続き、0.7.0から追加する予定
} else if (e.key.keysym.sym == SDLK_r) {
angle -= 90.0f;
2024-05-22 21:24:19 +09:00
rotateWindow(imgWidth, imgHeight);
} else if (e.key.keysym.sym == SDLK_t) {
angle += 90.0f;
2024-05-22 21:24:19 +09:00
rotateWindow(imgWidth, imgHeight);
2024-05-22 21:51:59 +09:00
} else if (e.key.keysym.sym == SDLK_y) {
SDL_RenderClear(renderer);
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
2024-05-22 21:51:59 +09:00
2024-05-24 18:33:56 +09:00
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
2024-05-22 21:51:59 +09:00
flippedV = !flippedV;
SDL_RenderPresent(renderer);
} else if (e.key.keysym.sym == SDLK_u) {
SDL_RenderClear(renderer);
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
2024-05-22 21:51:59 +09:00
2024-05-24 18:33:56 +09:00
SDL_SetWindowSize(window, imgWidth + (imgX * 2), imgHeight + (imgY * 2));
RenderCopy(renderQuad);
2024-05-22 21:51:59 +09:00
flippedH = !flippedH;
SDL_RenderPresent(renderer);
} else if (e.key.keysym.sym == SDLK_o) {
2024-05-24 19:27:56 +09:00
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;
}
2024-05-22 21:51:59 +09:00
} else if (e.key.keysym.sym == SDLK_p) {
// 画像をrsync|sftp|http postで使って共有する、0.7.0から追加する予定
}
2024-05-02 20:21:50 +09:00
} 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);
2024-05-24 18:33:56 +09:00
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 };
2024-05-02 20:21:50 +09:00
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
2024-05-02 20:21:50 +09:00
SDL_RenderPresent(renderer);
}
2024-05-02 19:58:42 +09:00
} else if (e.type == SDL_MOUSEWHEEL) {
2024-05-24 18:33:56 +09:00
int curWidth = imgWidth;
int curHeight = imgHeight;
2024-05-02 19:58:42 +09:00
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;
2024-05-02 19:58:42 +09:00
float minLimit = 50.0f;
// 画像は50x50以下じゃ駄目
2024-05-24 18:33:56 +09:00
if (newWidth < minLimit) {
2024-05-02 19:58:42 +09:00
newWidth = minLimit;
2024-05-24 18:33:56 +09:00
newHeight = curHeight;
} else if (newHeight < minLimit) {
printf("%d\n", curWidth);
newWidth = curWidth;
2024-05-02 19:58:42 +09:00
newHeight = minLimit;
}
// テキスチャーのレンダーリングサイズの設定
SDL_RenderClear(renderer);
2024-05-24 18:33:56 +09:00
imgWidth = (int)newWidth;
imgHeight = (int)newHeight;
imgX = (windowWidth - imgWidth) / 2;
imgY = (windowHeight - imgHeight) / 2;
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
2024-05-02 19:58:42 +09:00
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
2024-05-02 19:58:42 +09:00
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;
// 縦横比を変わらずに新しい大きさの算数
2024-04-07 15:16:52 +09:00
float newAspectRatio = (float)newWidth / newHeight;
int scaledWidth, scaledHeight;
2024-04-07 15:16:52 +09:00
if (newAspectRatio != aspectRatio) {
2024-05-02 18:36:43 +09:00
// 画像よりウィンドウの方が広い場合
scaledHeight = angle == 90 || angle == -90 ? newWidth : newHeight;
2024-04-07 15:16:52 +09:00
scaledHeight = newHeight;
scaledWidth = (int)(scaledHeight * aspectRatio);
} else {
// 画像よりウィンドウの方が高い場合
scaledWidth = angle == 90 || angle == -90 ? newHeight : newWidth;
scaledHeight = angle == 90 || angle == -90 ? newWidth : newHeight;
2024-04-07 15:16:52 +09:00
}
// 画像は50x50以下じゃ駄目
int minWidth = 50;
int minHeight = 50;
if (scaledWidth < minWidth) scaledWidth = minWidth;
if (scaledHeight < minHeight) scaledHeight = minHeight;
// 大きすぎの場合もふざけんな
if (scaledWidth >= (screenWidth-20)) scaledWidth = screenWidth-20;
2024-05-02 18:36:43 +09:00
if (scaledHeight >= (screenHeight-20)) scaledHeight = screenHeight-20;
imgWidth = scaledWidth;
imgHeight = scaledHeight;
2024-05-02 19:42:10 +09:00
// テキスチャーのレンダーリングサイズの設定
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
2024-05-24 18:33:56 +09:00
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) {
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
2024-05-02 19:42:10 +09:00
SDL_RenderClear(renderer);
RenderCopy(renderQuad);
2024-05-24 18:33:56 +09:00
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);
}
2024-05-24 18:33:56 +09:00
SDL_Rect renderQuad = { imgX, imgY, imgWidth, imgHeight };
RenderCopy(renderQuad);
2024-05-24 18:33:56 +09:00
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);
}
2024-05-24 19:27:56 +09:00
int main(int argc, char *argv[]) {
2023-12-18 18:25:07 +09:00
if (argc < 2) {
usage();
2023-12-18 18:25:07 +09:00
return 1;
2023-10-24 12:16:55 +09:00
}
2023-12-18 18:25:07 +09:00
// SDL2とSDL2_imageの初期設定
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDLを初期設定出来なかった%s\n", SDL_GetError());
return 1;
2023-10-24 12:16:55 +09:00
}
2023-12-18 18:25:07 +09:00
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
printf("SDL_imageを初期設定出来なかった%s\n", SDL_GetError());
SDL_Quit();
2023-10-24 12:16:55 +09:00
return 1;
}
2024-05-24 19:27:56 +09:00
const char *imgfile = argv[1];
// URLの場合、仮にダウンロードして
bool isurl = strncmp(imgfile, "http://", 7) == 0 ||
strncmp(imgfile, "https://", 8) == 0;
2024-05-24 19:27:56 +09:00
imgfile = isurl ? fromurl(argv[1], "/tmp") : argv[1];
if (imgfile == NULL) {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
2023-12-18 18:25:07 +09:00
// 画像の読込
2024-05-24 19:27:56 +09:00
SDL_Surface *imgsurface = IMG_Load(imgfile);
2023-12-18 18:25:07 +09:00
if (imgsurface == NULL) {
printf("画像の読込に失敗:%s\n", IMG_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
2023-10-24 12:16:55 +09:00
return 1;
}
2023-12-18 18:25:07 +09:00
// 画像の大きさの受取
2024-04-07 15:16:52 +09:00
imgWidth = imgsurface->w;
imgHeight = imgsurface->h;
aspectRatio = (float)imgWidth / imgHeight;
2023-12-18 18:25:07 +09:00
// 画面の大きさの受取
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
2024-04-07 15:16:52 +09:00
screenWidth = DM.w;
screenHeight = DM.h;
2023-12-18 18:25:07 +09:00
// ウィンドウの大きさの設定
2024-04-07 15:16:52 +09:00
int windowWidth = (imgWidth >= (screenWidth-20)) ? screenWidth-20 : imgWidth;
int windowHeight = (imgHeight >= (screenHeight-20)) ? screenHeight-20 : imgHeight;
2023-12-18 18:25:07 +09:00
// ウィンドウの作成
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
);
2023-12-18 18:25:07 +09:00
if (window == NULL) {
printf("ウィンドウの作成に失敗:%s\n", SDL_GetError());
SDL_Quit();
2023-10-24 12:16:55 +09:00
return 1;
}
2023-12-18 18:25:07 +09:00
// レンダーの作成
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
printf("レンダーの作成に失敗:%s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
2023-10-24 12:16:55 +09:00
return 1;
}
2023-12-18 18:25:07 +09:00
texture = SDL_CreateTextureFromSurface(renderer, imgsurface);
SDL_FreeSurface(imgsurface);
if (texture == NULL) {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
2023-10-24 12:16:55 +09:00
2023-12-18 18:25:07 +09:00
// メインループ
SDL_Event e;
while (!quit) {
// イベント
while (SDL_PollEvent(&e) != 0) {
windowevent(e);
2024-02-14 23:25:53 +09:00
}
2023-10-24 12:16:55 +09:00
2024-02-14 23:25:53 +09:00
// 休ませる
SDL_Delay(DELAY_MS);
2023-10-24 12:16:55 +09:00
}
// 掃除
2023-12-18 18:25:07 +09:00
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
2023-10-24 12:16:55 +09:00
return 0;
}