// imgv, a simple SDL-based image viewer for the Ben Nanonote // Version 0.2.1 // Last edited by Fernando Carello 2010-05-24 // #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define SCREENWIDTH 320 #define SCREENHEIGHT 240 #define SCREENBPP 32 #define SMOOTHING_OFF 0 #define SMOOTHING_ON 1 #define PANSTEP 40 #define ZOOMSTEP 0.05 int main(int argc, char *argv[]) { SDL_Surface *screen = NULL, *scaled_img = NULL, *temp_img = NULL, *picture = NULL; SDL_Event event; SDL_Rect picturePortion, screenPortion; int imgWidth, imgHeight, smoothing = SMOOTHING_ON, fPressed, zPressed, iPressed, oPressed, alreadyFit, pixelFit, lPressed, rPressed, leftPressed, rightPressed, upPressed, downPressed; char sFilename[255] = "\0", sVersion[] = "0.2.1"; double scale_x = 1.0, scale_y = 1.0, scale = 1.0; atexit(SDL_Quit); // Process command line if (argc != 2) { fprintf (stderr, "\n imgv v%s. Syntax: imgv \n\n Hotkeys:\n 'f' fit to screen\n 'z' zoom at pixel level\n 'i' zoom in 'o' zoom out\n 'l' rotate left 'r' rotate right\n 'arrows' pan 'ESC' quit\n\n", sVersion); exit (1); } strncpy (sFilename, argv[1], 254); // Initialize the SDL library if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "\n Couldn't initialize SDL: %s\n\n", SDL_GetError()); exit(1); } // Load Picture temp_img = IMG_Load(sFilename); if (temp_img == (SDL_Surface *) (NULL)) { fprintf(stderr, "\n Couldn't load image file %s: %s\n\n", sFilename, SDL_GetError()); exit (1); } // Set video mode screen = SDL_SetVideoMode (SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWACCEL); if (screen == (SDL_Surface *) (NULL)) { fprintf(stderr, "Couldn't set %dx%dx%d video mode: %s\n\n", SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SDL_GetError()); exit(1); } // Can't stand the useless arrow... Ben has no pointing device SDL_ShowCursor(SDL_DISABLE); // Convert picture in same format as video framebuffer, to optimize blit performances picture = SDL_DisplayFormat (temp_img); if (picture == (SDL_Surface *) (NULL)) { fprintf(stderr, "\n Internal error from DisplayFormat\n\n"); exit (1); } SDL_FreeSurface (temp_img); imgWidth = picture->w; imgHeight = picture->h; // Starting point (default view): uniform scaling to best screen fit, keep aspect ratio scale_x = (double) (SCREENWIDTH) / (double) (imgWidth); scale_y = (double) (SCREENHEIGHT) / (double) (imgHeight); if (scale_y < scale_x) scale = scale_y; else scale = scale_x; scaled_img = zoomSurface (picture, scale, scale, SMOOTHING_ON); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from zoomSurface()\n\n"); exit (1); } screenPortion.x = 0; // destination coordinates: origin screenPortion.y = 0; picturePortion.x = 0; picturePortion.y = 0; picturePortion.w = (Uint16) imgWidth; picturePortion.h = (Uint16) imgHeight; // off-cycle: first image drawing SDL_FillRect(screen, NULL, 0); // draw background color (black) SDL_BlitSurface(scaled_img, &picturePortion, screen, &screenPortion); SDL_Flip(screen); leftPressed = FALSE; rightPressed = FALSE; upPressed = FALSE; downPressed = FALSE; fPressed = FALSE; zPressed = FALSE; lPressed = FALSE; rPressed = FALSE; iPressed = FALSE; oPressed = FALSE; pixelFit = FALSE; alreadyFit = TRUE; while(1) { if (SDL_WaitEvent( &event )) { // We only process SDL_KEYDOWN and SDL_KEYUP events switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_LEFT: leftPressed = TRUE; break; case SDLK_RIGHT: rightPressed = TRUE; break; case SDLK_DOWN: downPressed = TRUE; break; case SDLK_f: fPressed = TRUE; break; case SDLK_z: zPressed = TRUE; break; case SDLK_i: iPressed = TRUE; break; case SDLK_o: oPressed = TRUE; break; case SDLK_l: lPressed = TRUE; break; case SDLK_r: rPressed = TRUE; break; case SDLK_UP: upPressed = TRUE; break; case SDLK_ESCAPE: if (picture) SDL_FreeSurface (picture); if (scaled_img) SDL_FreeSurface (scaled_img); if (screen) SDL_FreeSurface (screen); exit(0); default: break; } break; case SDL_KEYUP: switch (event.key.keysym.sym) { case SDLK_LEFT: leftPressed = FALSE; break; case SDLK_RIGHT: rightPressed = FALSE; break; case SDLK_DOWN: downPressed = FALSE; break; case SDLK_UP: upPressed = FALSE; break; case SDLK_f: fPressed = FALSE; break; case SDLK_z: zPressed = FALSE; break; case SDLK_i: iPressed = FALSE; break; case SDLK_o: oPressed = FALSE; break; case SDLK_l: lPressed = FALSE; break; case SDLK_r: rPressed = FALSE; break; default: break; } break; } // end of switch (event.type) // Process commands if (fPressed && !alreadyFit) { // Fit image to screen if (scaled_img != (SDL_Surface *) (NULL)) SDL_FreeSurface (scaled_img); // since zoomSurface() creates a new surface every time alreadyFit = TRUE; pixelFit = FALSE; scale_x = (double) (SCREENWIDTH) / (double) (imgWidth); scale_y = (double) (SCREENHEIGHT) / (double) (imgHeight); if (scale_y < scale_x) scale = scale_y; else scale = scale_x; picturePortion.x = 0; picturePortion.y = 0; picturePortion.w = (Uint16) imgWidth; picturePortion.h = (Uint16) imgHeight; scaled_img = zoomSurface (picture, scale, scale, smoothing); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from zoomSurface()\n\n"); exit (1); } } if (zPressed && !pixelFit) { // Zoom at 1:1 (100% zoom / actual pixels) if (scaled_img != (SDL_Surface *) (NULL)) SDL_FreeSurface (scaled_img); alreadyFit = FALSE; pixelFit = TRUE; picturePortion.w = (Uint16) SCREENWIDTH; picturePortion.h = (Uint16) SCREENHEIGHT; scale = 1.0; scaled_img = SDL_ConvertSurface (picture, picture->format, picture->flags); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from ConvertSurface()\n\n"); exit (1); } } if (iPressed) { // Zoom in if (scaled_img != (SDL_Surface *) (NULL)) SDL_FreeSurface (scaled_img); alreadyFit = FALSE; pixelFit = FALSE; scale += ZOOMSTEP; picturePortion.w = (Uint16) ((double) (imgWidth) * scale); if ( (picturePortion.w - picturePortion.x) >= imgWidth ) picturePortion.w = imgWidth - picturePortion.x; if (picturePortion.w < 1) picturePortion.w = 1; picturePortion.h = (Uint16) ((double) (imgHeight) * scale); if ( (picturePortion.h - picturePortion.y) >= imgHeight ) picturePortion.h = imgHeight - picturePortion.y; if (picturePortion.h < 1) picturePortion.h = 1; scaled_img = zoomSurface (picture, scale, scale, smoothing); //scaled_img = rotozoomSurface (picture, 0, scale, SMOOTHING_ON); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from zoomSurface()\n\n"); exit (1); } } if (oPressed) { // Zoom out if (scaled_img != (SDL_Surface *) (NULL)) SDL_FreeSurface (scaled_img); alreadyFit = FALSE; pixelFit = FALSE; scale -= ZOOMSTEP; if (scale <= 0.0) scale = 0.01; picturePortion.w = (Uint16) ((double) (imgWidth) * scale); if ( (picturePortion.w - picturePortion.x) >= imgWidth) picturePortion.w = imgWidth - picturePortion.x; if (picturePortion.w < 1) picturePortion.w = 1; picturePortion.h = (Uint16) ((double) (imgHeight) * scale); if ( (picturePortion.h - picturePortion.y) >= imgHeight ) picturePortion.h = imgHeight - picturePortion.y; if (picturePortion.h < 1) picturePortion.h = 1; scaled_img = zoomSurface (picture, scale, scale, smoothing); //scaled_img = rotozoomSurface (picture, 0, scale, SMOOTHING_ON); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from zoomSurface()\n\n"); exit (1); } } if (lPressed) { // Rotate left 90° if (scaled_img != (SDL_Surface *) (NULL)) temp_img = scaled_img; else { fprintf (stderr, "\n Error: NULL scaled_img\n\n"); exit (1); } alreadyFit = FALSE; scaled_img = rotozoomSurface (temp_img, -90, 1.0, SMOOTHING_OFF); SDL_FreeSurface (temp_img); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from rotozoomSurface()\n\n"); exit (1); } } if (rPressed) { // Rotate right 90° if (scaled_img != (SDL_Surface *) (NULL)) temp_img = scaled_img; else { fprintf (stderr, "\n Error: NULL scaled_img\n\n"); exit (1); } alreadyFit = FALSE; scaled_img = rotozoomSurface (temp_img, 90, 1.0, SMOOTHING_OFF); SDL_FreeSurface (temp_img); if (scaled_img == (SDL_Surface *) (NULL)) { fprintf (stderr, "\n Error from rotozoomSurface()\n\n"); exit (1); } } if (leftPressed) { picturePortion.x -= PANSTEP; if (picturePortion.x < 0) picturePortion.x = 0; alreadyFit = FALSE; } if (rightPressed) { picturePortion.x += PANSTEP; if (picturePortion.x >= imgWidth) picturePortion.x = (Sint16) (imgWidth - 1); alreadyFit = FALSE; } if (upPressed) { picturePortion.y -= PANSTEP; if (picturePortion.y < 0) picturePortion.y = 0; alreadyFit = FALSE; } if (downPressed) { picturePortion.y += PANSTEP; if (picturePortion.y >= imgHeight) picturePortion.y = (Sint16) (imgHeight - 1); alreadyFit = FALSE; } SDL_FillRect(screen, (SDL_Rect *) NULL, 0); // draw background color (black) SDL_BlitSurface(scaled_img, &picturePortion, screen, &screenPortion); SDL_Flip(screen); } // end of if(SDL_WaitEvent()) } // end of while(1) return 0; }