#include #include #include #include #include #include #include #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; }