/* OSXIV - Overly Simple X Image Viewer */ #include #include #include #include #include #define DEBUG 0 int main(int argc, char** argv); int render(double zoom, double move_x, double move_y); int handle_events(); void cleanup(); #define DBG(fmt, ...) do { if (DEBUG) printf(fmt, __VA_ARGS__); } while (0) SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; SDL_Texture *texture = NULL; int main(int argc, char** argv) { if(argc < 2) { fprintf(stderr, "Please provide a filename (or '-' to read from stdin).\n"); return 1; } if(strcmp(argv[1], "-") && access(argv[1], F_OK ) == -1) { fprintf(stderr, "Filename doesnt exist.\n"); return 1; } SDL_Init(SDL_INIT_VIDEO); IMG_Init(IMG_INIT_PNG); atexit(cleanup); char* windowtitle = malloc(sizeof(char) * (9 + strlen(strcmp(argv[1], "-") ? argv[1] : "stdin"))); // +9 bcz "OSXIV - " sprintf(windowtitle, "OSXIV - %s", strcmp(argv[1], "-") ? argv[1] : "stdin"); SDL_DisplayMode dm; SDL_GetCurrentDisplayMode(0, &dm); window = SDL_CreateWindow( windowtitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w / 2, //w dm.h / 2, //h SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE ); free(windowtitle); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE); SDL_RWops* img; if(!strcmp(argv[1], "-")) img = SDL_RWFromFP(stdin, 0); else img = SDL_RWFromFile(argv[1], "rb"); texture = IMG_LoadTexture_RW(renderer, img, 0); if(!texture) { SDL_FreeRW(img); fprintf(stderr, "Problem while loading the image: (%s).\n", argv[1]); return 1; } SDL_FreeRW(img); if(handle_events()) { fprintf(stderr, "Event handling exception.\n"); return 1; } return 0; } int render(double zoom, double move_x, double move_y) { SDL_Rect src = {0}; SDL_Rect dst = {0}; int screen_h, screen_w; SDL_RenderClear(renderer); SDL_QueryTexture(texture, NULL, NULL, &src.w , &src.h); DBG("\nsrc w: %d h: %d x: %d y: %d\n", src.w, src.h, src.x, src.y); SDL_GetWindowSize(window, &dst.w, &dst.h); screen_h = dst.h; screen_w = dst.w; DBG("scr w: %d h: %d\n", screen_w, screen_h); /* APPLY ZOOM */ dst.h *= zoom; dst.w *= zoom; DBG("zoom: %f\n", zoom); /* REVERT IMAGE FILL */ double ratio = (double) src.w / src.h; if(dst.h >= dst.w / ratio) dst.h = dst.w / ratio; else dst.w = ratio * dst.h; /* CENTER IN SCREEN */ dst.x = (screen_w - dst.w) / 2; dst.y = (screen_h - dst.h) / 2; DBG("dst w: %d h: %d x: %d y: %d\n\n", dst.w, dst.h, dst.x, dst.y); /* APPLY MOVE */ dst.x -= move_x * dst.w; dst.y -= move_y * dst.h; DBG("Moved by x_perc: %f y_perc: %f\n", move_x, move_y); SDL_RenderCopy(renderer, texture, &src, &dst); SDL_RenderPresent(renderer); return 0; } int handle_events() { SDL_Event event; double zoom_multiplier = 0.1; // 10% double move_multipler = 0.1; // 10% double zoom = 1.0; // 100% initially double move_x = 0.0; // initial x pos (centered) double move_y = 0.0; // initial y pos (centered) while(SDL_WaitEvent(&event)) { //DBG("Event: 0x%x\n", event.type); switch(event.type) { case SDL_KEYDOWN: switch(event.key.keysym.sym) { case '+': // zoom in case 61: // + zoom += zoom_multiplier; render(zoom, move_x, move_y); break; case '-': // zoom out zoom -= zoom - zoom_multiplier < 0 ? 0 : zoom_multiplier; render(zoom, move_x, move_y); break; case 1073741906: // up arrow - move up move_y -= move_multipler / zoom; render(zoom, move_x, move_y); break; case 1073741905: // down arrow - move down move_y += move_multipler / zoom; render(zoom, move_x, move_y); break; case 1073741904: // left arrow - move left move_x -= move_multipler / zoom; render(zoom, move_x, move_y); break; case 1073741903: // right arrow - move right move_x += move_multipler / zoom; render(zoom, move_x, move_y); break; case 'q': exit(0); } break; case SDL_WINDOWEVENT: render(zoom, move_x, move_y); break; case SDL_QUIT: exit(0); } } return 1; } void cleanup() { SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); }