git.y1.nz

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.