fbui | Framebuffer-based graphical environment |
| download: https://git.y1.nz/archives/fbui.tar.gz | |
| README | Files | Log | Refs |
libfbui/Viewer/main.c
1
2 /*=========================================================================
3 *
4 * fbview, an image viewer for FBUI (in-kernel framebuffer UI)
5 * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net
6 *
7 * This module is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This module is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this module; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * (See the file COPYING in the main directory of this archive for
22 * more details.)
23 *
24 *=======================================================================*/
25
26
27 /* Changes
28 *
29 * Sept 26, 2004: Updated for grayscale images.
30 * Dec 18, 2004: Updated for TIFFs.
31 * Jan 11, 2004: Fixed memory allocation bugs.
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <math.h>
39 #include <string.h>
40
41 #include "libfbui.h"
42
43 #include <jpeglib.h>
44 #include <tiffio.h>
45
46
47 typedef struct item {
48 struct item *next;
49 char *str;
50 } Item;
51
52
53
54 static unsigned char *buffer = NULL;
55 static unsigned long buflen=0;
56
57 unsigned char *get_buffer (unsigned long size)
58 {
59 if (!buffer) {
60 buffer = (JSAMPLE*) malloc (size);
61 if (!buffer)
62 FATAL ("failed to malloc image buffer\n");
63
64 buflen = size;
65 return buffer;
66 }
67 else
68 {
69 if (size < buflen)
70 return buffer;
71 else {
72 buffer = realloc (buffer, size);
73 return buffer;
74 }
75 }
76 }
77
78
79 static Item *file_list = NULL;
80
81 void append_item (char *str)
82 {
83 Item *nu = (Item*)malloc(sizeof(Item));
84 memset ((void*)nu,0,sizeof(Item));
85 nu->str = strdup (str);
86
87 Item *last=NULL;
88 last=file_list;
89 while(last) {
90 if (last->next)
91 last = last->next;
92 else
93 break;
94 }
95 if (!last)
96 file_list = nu;
97 else
98 last->next = nu;
99 }
100
101 char *nth_item (int n)
102 {
103 Item *item= file_list;
104
105 while (n--) {
106 if (item)
107 item = item->next;
108 if (!item)
109 break;
110 }
111
112 return item? item->str : NULL;
113 }
114
115
116 Font *pcf;
117 int target_w, target_h;
118 int available_height, text_height;
119
120 typedef struct
121 {
122 int dx, dy;
123 int e;
124 int j;
125 int sum;
126 }
127 BresenhamInfo;
128
129 void
130 bresenham_init (BresenhamInfo *bi, int target_size, int original_size)
131 {
132 if (!bi)
133 FATAL("null ptr param");
134 if (!target_size || !original_size)
135 FATAL("zero numeric param");
136 if (target_size > original_size)
137 FATAL("expansion requested");
138
139 bi->dx = original_size;
140 bi->dy = target_size;
141 bi->e = (bi->dy<<1) - bi->dx;
142 bi->j = 0;
143 bi->sum = 0; // diag
144 }
145
146
147 int
148 bresenham_get (BresenhamInfo *bi)
149 {
150 char done = 0;
151
152 if (!bi)
153 FATAL("null ptr param");
154
155 done = false;
156
157 int initial_j = bi->j;
158
159 while (bi->j <= bi->dx && !done)
160 {
161 if (bi->e >= 0)
162 {
163 done = true;
164 bi->e -= (bi->dx<<1);
165 }
166 bi->e += (bi->dy<<1);
167 ++bi->j;
168 }
169
170 int count = bi->j - initial_j;
171 bi->sum += count;
172 if (bi->sum > bi->dx)
173 {
174 int *i=0;
175 *i++;
176 }
177 return count;
178 }
179
180
181 JSAMPLE * image_buffer;
182 unsigned long *image_buffer_long;
183 unsigned char *shrunken_image_buffer;
184 int image_height;
185 int image_width;
186 int image_ncomponents;
187 int image_orig_width, image_orig_height;
188
189 static int grayscale=0;
190
191 static int fileNum = 0;
192 static char *path = NULL;
193
194 extern int read_JPEG_file (char*);
195
196 static unsigned char bres_x_ary [3000];
197 static unsigned char bres_y_ary [3000];
198
199 static short win_w, win_h;
200 static char do_shrink=0;
201
202 void shrink_image (short target_w, short target_h);
203
204 void
205 rescale()
206 {
207 printf ("fbview: entered rescale()\n");
208 do_shrink=0;
209 target_w = image_width;
210 target_h = image_height > available_height ? available_height : image_height;
211
212 if (win_w < image_width || available_height < image_height)
213 {
214 do_shrink = 1;
215
216 double ratio = 0;
217 if (win_w < image_width) {
218 ratio = win_w / (double) image_width;
219 }
220 if (available_height < image_height) {
221 double r = available_height / (double) image_height;
222 if (ratio == 0 || r < ratio)
223 ratio = r;
224 }
225 target_w = image_width * ratio;
226 target_h = image_height * ratio;
227 }
228
229 if (do_shrink) {
230 shrink_image (target_w, target_h);
231 image_width = target_w;
232 image_height= target_h;
233 do_shrink = 0;
234 image_ncomponents = 3;
235 }
236 }
237
238 int
239 readnext (Display *dpy, Window *win)
240 {
241 path=NULL;
242 int result=0;
243
244 while (!result) {
245 image_width=0;
246 image_height=0;
247 image_ncomponents=0;
248
249 path = nth_item (fileNum++);
250 if (!path)
251 break;
252
253 if (image_buffer) {
254 image_buffer = NULL;
255 }
256 if (image_buffer_long) {
257 image_buffer_long = NULL;
258 }
259 if (shrunken_image_buffer) {
260 shrunken_image_buffer = NULL;
261 }
262
263 char *extension = path;
264 char *s = NULL;
265 while ((s = strchr (extension, '.'))) {
266 extension = s;
267 if (strchr (s+1, '.')) {
268 extension = s+1;
269 } else
270 break;
271 }
272 if (extension == path) {
273 fprintf (stderr, "fbview: invalid filename %s\n", path);
274 continue;
275 }
276
277 if (!strcmp (extension, ".jpg") ||
278 !strcmp (extension, ".JPG") ||
279 !strcmp (extension, ".jpeg") ||
280 !strcmp (extension, ".JPEG"))
281 {
282 result = read_JPEG_file (path);
283 if (result) {
284 printf ("JPEG information: %s, width %d height %d depth %d\n",
285 path,image_width,image_height,image_ncomponents*8);
286 if (image_ncomponents != 3 && image_ncomponents != 1)
287 result=0;
288 image_buffer_long = NULL;
289 image_orig_width = image_width;
290 image_orig_height = image_height;
291 }
292
293 }
294 else
295 if (!strcmp (extension, ".tif") ||
296 !strcmp (extension, ".TIF") ||
297 !strcmp (extension, ".tiff") ||
298 !strcmp (extension, ".TIFF"))
299 {
300 TIFF *tiff = TIFFOpen (path, "r");
301 if (tiff) {
302 unsigned long w, h;
303 unsigned short d, samples;
304 char ok = 1;
305
306 if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &w))
307 ok = 0;
308 if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &h))
309 ok = 0;
310 if (!TIFFGetField (tiff, TIFFTAG_BITSPERSAMPLE, &d))
311 ok = 0;
312 if (TIFFGetField (tiff, TIFFTAG_SAMPLESPERPIXEL, &samples))
313 d *= samples;
314
315 if (!ok) {
316 TIFFClose (tiff);
317 fprintf (stderr, "TIFF %s: missing dimensions or depth\n", path);
318 continue;
319 }
320
321 printf ("TIFF information: %s, width %lu height %lu depth %u\n",
322 path, w,h,d);
323
324 image_width = w;
325 image_height = h;
326 image_orig_width = image_width;
327 image_orig_height = image_height;
328 image_ncomponents = d / 8; // RGBA
329
330 image_buffer_long = (unsigned long*) get_buffer (w * h * 4);
331 if (!image_buffer_long) {
332 TIFFClose (tiff);
333 FATAL ("out of memory");
334 }
335
336 if (!TIFFReadRGBAImage (tiff, w, h, image_buffer_long, 1)) {
337 TIFFClose (tiff);
338 fprintf (stderr, "fbview: error reading %s\n", path);
339 }
340
341 image_buffer = NULL;
342
343 TIFFClose (tiff);
344 result = 1;
345 }
346 else
347 result = 0;
348 }
349 else
350 if (!strcmp (extension, ".nef") ||
351 !strcmp (extension, ".NEF"))
352 {
353 fprintf (stderr, "fbview: not supporting raw images yet: %s\n", path);
354 continue;
355 }
356 else
357 {
358 fprintf (stderr, "fbview: unsupported image extension in %s\n", path);
359 continue;
360 }
361 }
362
363 if (!path)
364 return 0;
365
366 if (result)
367 fbui_set_subtitle (dpy, win, path);
368
369 rescale();
370
371 return 1;
372 }
373
374
375 void printloading (Display *dpy, Window *win)
376 {
377 fbui_draw_string (dpy, win, pcf, 10, 10, "Loading...", RGB_WHITE);
378 fbui_flush (dpy, win);
379 }
380
381
382 void shrink_image (short target_w, short target_h)
383 {
384 BresenhamInfo b;
385
386 image_width = image_orig_width;
387 image_height = image_orig_height;
388
389 bresenham_init (&b, target_w, image_width);
390 int n=0, i, j, inc;
391 for (i=0; i<image_width; i+=inc) {
392 inc = bres_x_ary[n++] = bresenham_get(&b);
393 }
394 bresenham_init (&b, target_h, image_height);
395 n=0;
396 for (i=0; i<image_height; i+=inc) {
397 inc = bres_y_ary[n++] = bresenham_get(&b);
398 }
399
400 shrunken_image_buffer = malloc (target_w * target_h * 3);
401 if (!shrunken_image_buffer)
402 FATAL("out of memory");
403
404 /* shrink */
405 int yinc = 0;
406 int x, y;
407 for (y=0, j=0; j<image_height; j+=yinc, y++)
408 {
409 yinc = bres_y_ary [y];
410
411 int xinc = 0;
412
413 for(x=0, i=0; i<image_width; i+=xinc, x++)
414 {
415 xinc = bres_x_ary [x];
416
417 unsigned long r,g,b;
418 r=g=b=0;
419
420 /* collect a pixel average */
421 int k,l;
422 for (k=0; k<xinc; k++) {
423 for (l=0; l<yinc; l++) {
424 unsigned char *p = NULL;
425 unsigned long *p2 = NULL;
426
427 if (image_buffer) {
428 p = image_buffer + image_ncomponents * (i+k + (j+l)*image_width);
429 unsigned char pix=0;
430 if (image_ncomponents == 1) {
431 pix = *p;
432 r += pix;
433 g += pix;
434 b += pix;
435 } else {
436 /* 3 */
437 r += *p++;
438 g += *p++;
439 b += *p;
440 }
441 }
442 else if (image_buffer_long) {
443 // TIFFs are upside down
444 int yy = j + l;
445 if (yy >= image_height-1)
446 yy = image_height-1;
447
448 yy = (image_height-1) - yy;
449
450 p2 = image_buffer_long + i+k + yy*image_width;
451
452 unsigned long pix = *p2;
453 unsigned long r0, g0, b0;
454 register unsigned long m;
455 b0 = pix >> 16;
456 g0 = pix >> 8;
457 r0 = pix;
458 m = 0xff;
459 r0 &= m;
460 b0 &= m;
461 g0 &= m;
462 r += r0;
463 g += g0;
464 b += b0;
465 }
466 }
467 }
468 short factor = xinc * yinc;
469 r /= factor;
470 g /= factor;
471 b /= factor;
472
473 unsigned long ix = 3 * (x + y * target_w);
474
475 if (grayscale) {
476 short n = (r + g + b) / 3;
477 r = g = b = n;
478 }
479
480 shrunken_image_buffer [ix++] = r;
481 shrunken_image_buffer [ix++] = g;
482 shrunken_image_buffer [ix] = b;
483 }
484 }
485 }
486
487
488 int
489 main(int argc, char** argv)
490 {
491 int i,j;
492 Display *dpy;
493 Window *win;
494 char this_image_shrunken = 0;
495
496 path=NULL;
497 image_buffer=NULL;
498 image_buffer_long=NULL;
499 image_height=0;
500 image_width=0;
501 shrunken_image_buffer = NULL;
502
503 if (argc==1)
504 return 0;
505
506 pcf = font_new ();
507
508 if (!pcf_read (pcf, "timR12.pcf")) {
509 font_free (pcf);
510 pcf = NULL;
511 FATAL ("cannot load font");
512 }
513
514 text_height = pcf->ascent + pcf->descent;
515
516 /* XX
517 * To fix: If only one image file, we should open
518 * with dimensions of that file, plus room for text
519 */
520 long fg,bg;
521 fg = RGB_NOCOLOR;
522 bg = RGB_BLACK;
523
524 dpy = fbui_display_open ();
525 if (!dpy)
526 FATAL ("cannot open display");
527
528 /* get the maximal window */
529 image_width=dpy->width-1;
530 image_height=dpy->height-1;
531
532 win = fbui_window_open (dpy, image_width, image_height + 5 + text_height,
533 &win_w, &win_h,
534 9999,9999, // max wid/ht
535 0, 0,
536 &fg, &bg,
537 "fbview", "",
538 FBUI_PROGTYPE_APP,
539 false, // not requesting control
540 false, // therefore not autoplacing anything
541 -1,
542 true, // need keys
543 false, // not all motion
544 false, // not hidden
545 argc,argv);
546 if (!win)
547 FATAL ("cannot create window");
548
549 /* Parse file list */
550 i=1;
551 while (i<argc) {
552 char ch = *argv[i];
553 /* params used by FBUI lib will be truncated to zero length */
554 if (ch && ch != '-') {
555 printf ("param '%s'\n", argv[i]);
556 append_item (argv[i]);
557 }
558 i++;
559 }
560
561 fileNum = 0;
562
563 available_height = win_h - 5 - text_height;
564
565 printloading (dpy, win);
566
567 int result = readnext (dpy,win);
568
569 if (!result) {
570 fbui_display_close (dpy);
571 exit(0);
572 }
573
574 fbui_clear (dpy, win);
575 fbui_flush (dpy, win);
576
577 /* event loop */
578 char done=0;
579 while(!done) {
580 Event ev;
581 int err;
582 if ((err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL))) {
583 fbui_print_error (err);
584 continue;
585 }
586 printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type));
587
588 int num = ev.type;
589
590 if (ev.win != win)
591 FATAL ("got event for another window");
592
593 switch (num) {
594 case FBUI_EVENT_MOVE_RESIZE:
595 printf ("fbview got MR: %d %d\n", win_w, win_h);
596 if (win_w == ev.width && win_h && ev.height)
597 continue;
598 win_w = ev.width;
599 win_h = ev.height;
600 available_height = win_h - 5 - text_height;
601 if (image_buffer)
602 rescale ();
603 break;
604
605 case FBUI_EVENT_ENTER:
606 printf ("fbview got Enter\n");
607 continue;
608
609 case FBUI_EVENT_LEAVE:
610 printf ("fbview got Leave\n");
611 continue;
612
613 case FBUI_EVENT_MOTION: {
614 short x, y;
615
616 x = ev.x;
617 y = ev.y;
618
619 /* not used */
620 continue;
621 }
622
623 case FBUI_EVENT_KEY: {
624 short ch = fbui_convert_key (dpy, ev.key);
625
626 #if 0
627 if (ch)
628 printf ("viewer got key '%c' (0x%02x)\n", ch,ch);
629 #endif
630
631 if (ch == 'q' || ch == 'Q') {
632 done=1;
633 continue;
634 }
635 else if (ch == 'g' || ch == 'G') {
636 grayscale = !grayscale;
637 }
638 else
639 if (ch == ' ') {
640 if (this_image_shrunken)
641 free (shrunken_image_buffer);
642
643 shrunken_image_buffer = NULL;
644 this_image_shrunken = 0;
645
646 fbui_clear (dpy, win);
647 printloading (dpy, win);
648
649 int result= readnext (dpy,win);
650
651 if (!result) {
652 fbui_window_close (dpy, win);
653 exit(0);
654 }
655 }
656 else
657 continue;
658 }
659
660 case FBUI_EVENT_EXPOSE:
661 break;
662
663 default:
664 continue;
665 }
666
667 char expr [100];
668 char *tmp = path;
669 char *tmp2;
670 while ((tmp2 = strchr(tmp, '/'))) {
671 tmp = tmp2 + 1;
672 }
673 sprintf (expr, "%s (%d x %d, depth %d)", tmp,
674 image_orig_width, image_orig_height,
675 image_ncomponents * 8);
676 short w,a,d;
677 font_string_dims (pcf, expr, &w,&a,&d);
678 fbui_clear_area (dpy, win, 0, target_h+5, w, target_h+5 + text_height);
679 fbui_draw_string (dpy, win, pcf, 0, target_h + 5, expr, RGB_WHITE);
680
681 for (j=0; j<image_height; j++) {
682 if (image_ncomponents == 1 || grayscale) {
683 for(i=0; i<image_width; i++) {
684 unsigned long pix=0;
685 unsigned char *p = NULL;
686 unsigned long *p2 = NULL;
687
688 if (shrunken_image_buffer) {
689 p = shrunken_image_buffer + image_ncomponents*(i + j*image_width);
690 pix = *p++;
691 pix += *p++;
692 pix += *p;
693 pix /= 3;
694 pix |= (pix<<8) | (pix<<16);
695 }
696 else if (image_buffer) {
697 p = image_buffer + image_ncomponents*(i + j*image_width);
698 /* pixels are grayscale */
699 if (image_ncomponents == 1) {
700 pix = *p;
701 pix <<= 8;
702 pix |= *p;
703 pix <<= 8;
704 pix |= *p;
705 } else {
706 pix = *p++;
707 pix += *p++;
708 pix += *p;
709 pix /= 3;
710 pix |= (pix<<8) | (pix<<16);
711 }
712 }
713 else if (image_buffer_long) {
714 int yy = (image_height-1) - j;
715 p2= image_buffer_long + i + yy*image_width;
716 pix = *p2;
717 }
718
719 fbui_draw_point (dpy, win, i, j, pix);
720 }
721 }
722 else
723 {
724 if (shrunken_image_buffer)
725 fbui_put_rgb3 (dpy, win, 0, j, image_width,
726 shrunken_image_buffer + 3*j*image_width);
727 else if (image_buffer)
728 fbui_put_rgb3 (dpy, win, 0, j, image_width,
729 image_buffer + 3*j*image_width);
730 else if (image_buffer_long)
731 fbui_put_rgb (dpy, win, 0, j, image_width,
732 image_buffer_long + 4*j*image_width);
733 }
734 }
735
736 fbui_flush (dpy, win);
737 } /* while */
738
739 fbui_flush (dpy, win);
740 fbui_window_close (dpy, win);
741 fbui_display_close (dpy);
742
743 if (buffer)
744 free (buffer);
745 return 0;
746 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.