Root/sdl-imageviewer.c

1// imgv, a simple SDL-based image viewer for the Ben Nanonote
2// Version 0.3.0
3// Last edited by Fernando Carello <fcarello@libero.it> 2010-05-24
4// Last edited by Niels Kummerfeldt <niels.kummerfeldt@tuhh.de> 2010-10-19
5//
6#include <stdlib.h>
7#include <unistd.h>
8#include <SDL/SDL.h>
9#include <SDL/SDL_image.h>
10#include <SDL/SDL_rotozoom.h>
11#include <SDL/SDL_ttf.h>
12
13#define TRUE 1
14#define FALSE 0
15#define SCREENWIDTH 320
16#define SCREENHEIGHT 240
17#define SCREENBPP 32
18#define SMOOTHING_OFF 0
19#define SMOOTHING_ON 1
20#define PANSTEP 40
21#define ZOOMSTEP 1.2
22#define SLIDESHOWTIMEOUT 1000 * 5
23#define VERSION "0.3.0"
24
25void quit()
26{
27    TTF_Quit();
28    SDL_Quit();
29
30    exit(1);
31}
32
33SDL_Surface *initScreen()
34{
35    // Initialize the SDL library
36    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
37    {
38        fprintf(stderr, "\n Couldn't initialize SDL: %s\n\n", SDL_GetError());
39        quit();
40    }
41
42    // Set video mode
43    SDL_Surface *screen = SDL_SetVideoMode(SCREENWIDTH, SCREENHEIGHT, SCREENBPP,
44                                           SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWACCEL);
45    if (screen == (SDL_Surface *) (NULL))
46    {
47        fprintf(stderr, "Couldn't set %dx%dx%d video mode: %s\n\n", SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SDL_GetError());
48        quit();
49    }
50
51    // Can't stand the useless arrow... Ben has no pointing device
52    SDL_ShowCursor(SDL_DISABLE);
53
54    TTF_Init();
55
56    return screen;
57}
58
59SDL_Surface *loadImage(char *filename)
60{
61    // Load Picture
62    SDL_Surface *tmp = IMG_Load(filename);
63    if (tmp == (SDL_Surface *) (NULL))
64    {
65        fprintf(stderr, "\n Couldn't load image file %s: %s\n\n", filename, SDL_GetError());
66        quit();
67    }
68
69    // Auto rotate image to fit screen
70    //if (tmp->w > SCREENWIDTH || tmp->h > SCREENHEIGHT) {
71    // if (tmp->h > tmp->w * 1.1) {
72    // SDL_Surface *t = rotateSurface90Degrees(tmp, 3);
73    // SDL_FreeSurface(tmp);
74    // tmp = t;
75    // }
76    //}
77
78    // Convert picture in same format as video framebuffer, to optimize blit performances
79    SDL_Surface *picture = SDL_DisplayFormat(tmp);
80    if (picture == (SDL_Surface *) (NULL))
81    {
82        fprintf(stderr, "\n Internal error from DisplayFormat\n\n");
83        quit();
84    }
85    SDL_FreeSurface(tmp);
86
87    return picture;
88}
89
90void pan(SDL_Surface *image, SDL_Rect *pos, int dx, int dy)
91{
92    if (image->w > SCREENWIDTH) {
93        pos->x += dx;
94        if (pos->x < 0) {
95            pos->x = 0;
96        }
97        if (pos->x >= image->w - SCREENWIDTH) {
98            pos->x = (Sint16) (image->w - SCREENWIDTH);
99        }
100    } else {
101        pos->x = 0;
102    }
103    if (image->h > SCREENHEIGHT) {
104        pos->y += dy;
105        if (pos->y < 0) {
106            pos->y = 0;
107        }
108        if (pos->y >= image->h - SCREENHEIGHT) {
109            pos->y = (Sint16) (image->h - SCREENHEIGHT);
110        }
111    } else {
112        pos->y = 0;
113    }
114}
115
116SDL_Surface *zoomIn(SDL_Surface *image, SDL_Rect *pos, double *scale)
117{
118    *scale *= ZOOMSTEP;
119
120    SDL_Surface *result = zoomSurface(image, *scale, *scale, SMOOTHING_ON);
121    if (result == (SDL_Surface *) (NULL))
122    {
123        fprintf(stderr, "\n Error from zoomSurface()\n\n");
124        quit();
125    }
126
127    pos->x *= ZOOMSTEP;
128    int dx = SCREENWIDTH * (ZOOMSTEP-1) * 0.5;
129    pos->y *= ZOOMSTEP;
130    int dy = SCREENHEIGHT * (ZOOMSTEP-1) * 0.5;
131    pan(result, pos, dx, dy);
132
133    return result;
134}
135
136SDL_Surface *zoomOut(SDL_Surface *image, SDL_Rect *pos, double *scale)
137{
138    *scale /= ZOOMSTEP;
139
140    SDL_Surface *result = zoomSurface(image, *scale, *scale, SMOOTHING_ON);
141    if (result == (SDL_Surface *) (NULL))
142    {
143        fprintf(stderr, "\n Error from zoomSurface()\n\n");
144        quit();
145    }
146
147    pos->x += SCREENWIDTH * (1-ZOOMSTEP) * 0.5;
148    pos->x /= ZOOMSTEP;
149    pos->y += SCREENHEIGHT * (1-ZOOMSTEP) * 0.5;
150    pos->y /= ZOOMSTEP;
151    pan(result, pos, 0, 0);
152
153    return result;
154}
155
156SDL_Surface *zoomFit(SDL_Surface *image, SDL_Rect *pos, double *scale)
157{
158    pos->x = 0;
159    pos->y = 0;
160    double scale_x = (double) (SCREENWIDTH) / (double) (image->w);
161    double scale_y = (double) (SCREENHEIGHT) / (double) (image->h);
162    if (scale_y < scale_x) {
163        *scale = scale_y;
164    } else {
165        *scale = scale_x;
166    }
167
168    SDL_Surface *result = zoomSurface(image, *scale, *scale, SMOOTHING_ON);
169    if (result == (SDL_Surface *) (NULL))
170    {
171        fprintf(stderr, "\n Error from zoomSurface()\n\n");
172        quit();
173    }
174
175    return result;
176}
177
178SDL_Surface *zoom100(SDL_Surface *image, SDL_Rect *pos, double *scale)
179{
180    SDL_Surface *result = SDL_ConvertSurface(image, image->format, image->flags);
181    if (result == (SDL_Surface *) (NULL))
182    {
183        fprintf(stderr, "\n Error from ConvertSurface()\n\n");
184        quit();
185    }
186
187    if (*scale < 1.0) {
188        pos->x /= *scale;
189        pos->y /= *scale;
190        pos->x -= SCREENWIDTH * (1-(1 / *scale)) * 0.5;
191        pos->y -= SCREENHEIGHT * (1-(1 / *scale)) * 0.5;
192    } else {
193        pos->x += SCREENWIDTH * (1-*scale) * 0.5;
194        pos->y += SCREENHEIGHT * (1-*scale) * 0.5;
195        pos->x /= *scale;
196        pos->y /= *scale;
197    }
198    pan(result, pos, 0, 0);
199    *scale = 1.0;
200
201    return result;
202}
203
204SDL_Surface *drawFileName(char *filename, TTF_Font *font, int slideShow)
205{
206    if(font) {
207        SDL_Color foregroundColor = { 0, 0, 0, 0 };
208        SDL_Color backgroundColor = { 200, 200, 200, 0 };
209
210        char text[strlen(filename)+4];
211        strcpy(text, filename);
212        if (slideShow) {
213            strcat(text, " >>");
214        }
215        return TTF_RenderText_Shaded(font, text, foregroundColor, backgroundColor);
216    }
217    return NULL;
218}
219
220void drawImage(SDL_Surface *image, SDL_Rect *pos, SDL_Surface *screen, SDL_Surface *filename)
221{
222    SDL_FillRect(screen, (SDL_Rect *) NULL, 0); // draw background color (black)
223
224    SDL_Rect screenPos;
225    if (image->w < SCREENWIDTH) {
226        screenPos.x = (SCREENWIDTH - image->w) / 2;
227    } else {
228        screenPos.x = 0;
229    }
230    if (image->h < SCREENHEIGHT) {
231        screenPos.y = (SCREENHEIGHT - image->h) / 2;
232    } else {
233        screenPos.y = 0;
234    }
235    SDL_BlitSurface(image, pos, screen, &screenPos);
236
237    if(filename) {
238        SDL_Rect textLocation = { 0, 0, 0, 0 };
239        if (filename->w > SCREENWIDTH) {
240            textLocation.x = SCREENWIDTH - filename->w;
241        }
242        SDL_BlitSurface(filename, NULL, screen, &textLocation);
243    }
244
245    SDL_Flip(screen);
246}
247
248Uint32 timerCallback(Uint32 interval, void *param)
249{
250    param = NULL;
251    SDL_Event event;
252    SDL_KeyboardEvent keyEvent;
253
254    keyEvent.type = SDL_KEYDOWN;
255    keyEvent.keysym.unicode = 0;
256    keyEvent.keysym.scancode = 0;
257    keyEvent.keysym.mod = 0;
258    keyEvent.keysym.sym = SDLK_n;
259
260    event.type = SDL_KEYDOWN;
261    event.key = keyEvent;
262
263    SDL_PushEvent(&event);
264
265    return interval;
266}
267
268int main(int argc, char *argv[])
269{
270    SDL_Surface *screen = NULL,
271                *image = NULL,
272                *scaledImage = NULL,
273                *name = NULL;
274    SDL_Rect picturePortion;
275    TTF_Font *font = NULL;
276    double scale = 1.0;
277    int currentImageNumber = 1,
278                 showFileName = TRUE,
279                 runSlideShow = FALSE,
280                 isRunning = TRUE;
281    SDL_TimerID slideShowTimer = 0;
282
283    // Process command line
284    if (argc < 2) {
285        fprintf(stderr, "\n"
286            " imgv v%s. Syntax: imgv <image files>\n\n"
287            " Hotkeys:\n"
288            " 'f' fit to screen\n"
289            " 'z' zoom at pixel level\n"
290            " 'i' zoom in 'o' zoom out\n"
291            " 'l' rotate left 'r' rotate right\n"
292            " 'n' next image 'p' previous image\n"
293            " 'd' show / hide file name\n"
294            " 's' start / stop slide show\n"
295            " 'arrows' pan 'ESC' quit\n\n", VERSION);
296        exit(0);
297    }
298
299    screen = initScreen();
300
301    font = TTF_OpenFont("font.ttf", 11);
302    if (font == (TTF_Font *) (NULL)) {
303        font = TTF_OpenFont("/usr/share/imgv/font.ttf", 11);
304    }
305    if (font == (TTF_Font *) (NULL)) {
306        font = TTF_OpenFont("/usr/share/fonts/ttf-dejavu/DejaVuSans.ttf", 11);
307    }
308
309    picturePortion.w = SCREENWIDTH;
310    picturePortion.h = SCREENHEIGHT;
311
312    image = loadImage(argv[1]);
313    if (image->w < SCREENWIDTH && image->h < SCREENHEIGHT) {
314        scaledImage = zoom100(image, &picturePortion, &scale);
315    } else {
316        scaledImage = zoomFit(image, &picturePortion, &scale);
317    }
318    name = drawFileName(argv[currentImageNumber], font, runSlideShow);
319    drawImage(scaledImage, &picturePortion, screen, name);
320
321    do {
322        SDL_Event event;
323        if (SDL_WaitEvent(&event) && event.type == SDL_KEYDOWN) {
324            switch (event.key.keysym.sym) {
325                case SDLK_LEFT: // PAN LEFT
326                    pan(scaledImage, &picturePortion, -PANSTEP, 0);
327                    break;
328                case SDLK_RIGHT: // PAN RIGHT
329                    pan(scaledImage, &picturePortion, PANSTEP, 0);
330                    break;
331                case SDLK_UP: // PAN UP
332                    pan(scaledImage, &picturePortion, 0, -PANSTEP);
333                    break;
334                case SDLK_DOWN: // PAN DOWN
335                    pan(scaledImage, &picturePortion, 0, PANSTEP);
336                    break;
337                case SDLK_i: // ZOOM IN
338                    SDL_FreeSurface(scaledImage);
339                    scaledImage = zoomIn(image, &picturePortion, &scale);
340                    break;
341                case SDLK_o: // ZOOM OUT
342                    SDL_FreeSurface(scaledImage);
343                    scaledImage = zoomOut(image, &picturePortion, &scale);
344                    break;
345                case SDLK_f: // ZOOM TO FIT SCREEN
346                    SDL_FreeSurface(scaledImage);
347                    scaledImage = zoomFit(image, &picturePortion, &scale);
348                    break;
349                case SDLK_z: // ZOOM TO ORIGINAL SIZE
350                    SDL_FreeSurface(scaledImage);
351                    scaledImage = zoom100(image, &picturePortion, &scale);
352                    break;
353                case SDLK_l: // ROTATE LEFT
354                    {
355                        SDL_FreeSurface(scaledImage);
356                        SDL_Surface *tmp = rotateSurface90Degrees(image, 3);
357                        SDL_FreeSurface(image);
358                        image = tmp;
359                        scaledImage = zoomSurface(image, scale, scale, SMOOTHING_ON);
360                        int x = picturePortion.x;
361                        picturePortion.x = picturePortion.y + SCREENHEIGHT/2 - SCREENWIDTH/2;
362                        picturePortion.y = scaledImage->h - x - SCREENHEIGHT/2 - SCREENWIDTH/2;
363                        pan(scaledImage, &picturePortion, 0, 0);
364                    }
365                    break;
366                case SDLK_r: // ROTATE RIGHT
367                    {
368                        SDL_FreeSurface(scaledImage);
369                        SDL_Surface *tmp = rotateSurface90Degrees(image, 1);
370                        SDL_FreeSurface(image);
371                        image = tmp;
372                        scaledImage = zoomSurface(image, scale, scale, SMOOTHING_ON);
373                        int x = picturePortion.x;
374                        picturePortion.x = scaledImage->w - picturePortion.y - SCREENWIDTH/2
375                                           - SCREENHEIGHT/2;
376                        picturePortion.y = x + SCREENWIDTH/2 - SCREENHEIGHT/2;
377                        pan(scaledImage, &picturePortion, 0, 0);
378                    }
379                    break;
380                case SDLK_n: // NEXT IMAGE
381                    if (currentImageNumber < argc-1) {
382                        ++currentImageNumber;
383
384                        SDL_FreeSurface(image);
385                        SDL_FreeSurface(scaledImage);
386                        SDL_FreeSurface(name);
387
388                        image = loadImage(argv[currentImageNumber]);
389                        if (image->w < SCREENWIDTH && image->h < SCREENHEIGHT) {
390                            scaledImage = zoom100(image, &picturePortion, &scale);
391                        } else {
392                            scaledImage = zoomFit(image, &picturePortion, &scale);
393                        }
394                        name = drawFileName(argv[currentImageNumber], font, runSlideShow);
395                    } else {
396                        if (runSlideShow) {
397                            SDL_RemoveTimer(slideShowTimer);
398                            runSlideShow = FALSE;
399                            name = drawFileName(argv[currentImageNumber], font, runSlideShow);
400                        }
401                    }
402                    break;
403                case SDLK_p: // PREVIOUS IMAGE
404                    if (currentImageNumber > 1) {
405                        --currentImageNumber;
406
407                        SDL_FreeSurface(image);
408                        SDL_FreeSurface(scaledImage);
409                        SDL_FreeSurface(name);
410
411                        image = loadImage(argv[currentImageNumber]);
412                        if (image->w < SCREENWIDTH && image->h < SCREENHEIGHT) {
413                            scaledImage = zoom100(image, &picturePortion, &scale);
414                        } else {
415                            scaledImage = zoomFit(image, &picturePortion, &scale);
416                        }
417                        name = drawFileName(argv[currentImageNumber], font, runSlideShow);
418                    }
419                    break;
420                case SDLK_s: // START / STOP SLIDESHOW
421                    runSlideShow = 1 - runSlideShow;
422                    name = drawFileName(argv[currentImageNumber], font, runSlideShow);
423                    if (runSlideShow) {
424                        slideShowTimer = SDL_AddTimer(SLIDESHOWTIMEOUT, timerCallback, NULL);
425                    } else {
426                        SDL_RemoveTimer(slideShowTimer);
427                    }
428                    break;
429                case SDLK_d: // SHOW / HIDE FILENAME
430                    showFileName = 1 - showFileName;
431                    break;
432                case SDLK_ESCAPE: // QUIT
433                case SDLK_q:
434                    isRunning = FALSE;
435                    break;
436                default:
437                    break;
438             } // end of switch (event.key.keysym.sym)
439        } // end of if(SDL_WaitEvent())
440        drawImage(scaledImage, &picturePortion, screen, showFileName ? name : 0);
441    } while(isRunning); // end of do
442
443    SDL_FreeSurface(image);
444    SDL_FreeSurface(scaledImage);
445    SDL_FreeSurface(screen);
446
447    TTF_CloseFont(font);
448    TTF_Quit();
449
450    SDL_Quit();
451
452    return 0;
453}
454
455

Archive Download this file

Branches:
master



interactive