File: image.c

package info (click to toggle)
mpsql 2.1-2
  • links: PTS
  • area: non-free
  • in suites: potato
  • size: 3,528 kB
  • ctags: 4,886
  • sloc: ansic: 35,184; makefile: 3,761; sh: 44
file content (598 lines) | stat: -rw-r--r-- 19,702 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
/*  -*- c -*-  */
/* -------------------------------------------------------------------- *
**  copyright (c) 1995 ipvr stuttgart and thomas harrer.
**  see copyright notice below for parts of image_resolve.
** -------------------------------------------------------------------- *
**
**  libhelp
**
**  a comprehensive hypertext help system for OSF/Motif(tm) applications. 
**  based on libhtmlw from NCSA Mosaic(tm) version 2.4
**
**  written by thomas harrer
**  e-mail: Thomas.Harrer@rus.uni-stuttgart.de
**  
** -------------------------------------------------------------------- *
*h  $Id: image.c,v 1.17 1995/06/28 12:59:30 thomas Exp $
** -------------------------------------------------------------------- *
**
*h  module:		image.c
**
**  contents:		routines for image resolving and image cache.
**
**  interface:		- function: image_resolve
**
** -------------------------------------------------------------------- */
/****************************************************************************
 * NCSA Mosaic for the X Window System                                      *
 * Software Development Group                                               *
 * National Center for Supercomputing Applications                          *
 * University of Illinois at Urbana-Champaign                               *
 * 605 E. Springfield, Champaign IL 61820                                   *
 * mosaic@ncsa.uiuc.edu                                                     *
 *                                                                          *
 * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
 *                                                                          *
 * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
 * copyrighted by The Board of Trustees of the University of Illinois       *
 * (UI), and ownership remains with the UI.                                 *
 *                                                                          *
 * The UI grants you (hereafter, Licensee) a license to use the Software    *
 * for academic, research and internal business purposes only, without a    *
 * fee.  Licensee may distribute the binary and source code (if released)   *
 * to third parties provided that the copyright notice and this statement   *
 * appears on all copies and that no charge is associated with such         *
 * copies.                                                                  *
 *                                                                          *
 * Licensee may make derivative works.  However, if Licensee distributes    *
 * any derivative work based on or derived from the Software, then          *
 * Licensee will (1) notify NCSA regarding its distribution of the          *
 * derivative work, and (2) clearly notify users that such derivative       *
 * work is a modified version and not the original NCSA Mosaic              *
 * distributed by the UI.                                                   *
 *                                                                          *
 * Any Licensee wishing to make commercial use of the Software should       *
 * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
 * commercial use.  Commercial use includes (1) integration of all or       *
 * part of the source code into a product for sale or license by or on      *
 * behalf of Licensee to third parties, or (2) distribution of the binary   *
 * code or source code to third parties that need it to utilize a           *
 * commercial product sold or licensed by or on behalf of Licensee.         *
 *                                                                          *
 * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
 * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
 * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
 * USERS OF THIS SOFTWARE.                                                  *
 *                                                                          *
 * By using or copying this Software, Licensee agrees to abide by the       *
 * copyright law and all other applicable laws of the U.S. including, but   *
 * not limited to, export control laws, and the terms of this license.      *
 * UI shall have the right to terminate this license immediately by         *
 * written notice upon Licensee's breach of, or non-compliance with, any    *
 * of its terms.  Licensee may be held legally responsible for any          *
 * copyright infringement that is caused or encouraged by Licensee's        *
 * failure to abide by the terms of this license.                           *
 *                                                                          *
 * Comments and questions are welcome and can be sent to                    *
 * mosaic-x@ncsa.uiuc.edu.                                                  *
 ****************************************************************************/

/* -------------------------------------------------------------------- *
*g  include files
** -------------------------------------------------------------------- */
#include "imageio.h"
#include "HTML.h"
#include "image.h"
#include "path.h"
#include "helpp.h"

/* -------------------------------------------------------------------- *
*g  module identification
** -------------------------------------------------------------------- */
#ifdef RCSID
static char rcsid [] =
    "$Id: image.c,v 1.17 1995/06/28 12:59:30 thomas Exp $";
#endif /* RCSID */

/* -------------------------------------------------------------------- *
*g  private types:	cache_t
** -------------------------------------------------------------------- */
typedef struct cache_s  {

    unsigned long	html_no;      /* the html doc this imgage is in */
    char*		src;	      /* the name of the image. 	*/
    ImageInfo* 		image_info;   /* the image.			*/
    struct cache_s*  	next;	      /* NULL for the last entry. 	*/
    int			mem_usage;    /* staticstics.			*/

} cache_t;

/* -------------------------------------------------------------------- *
*g  global variables
** -------------------------------------------------------------------- */
static cache_t* icache = NULL;	      /* pointer to image cache.        */
static int	cache_len = 0;	      /* number of cached images        */
static int	cache_mem_usage = 0;  /* sum of images memory usage.    */

/* -------------------------------------------------------------------- *
*g  prototypes
** -------------------------------------------------------------------- */
static ImageInfo* icache_find (char*, unsigned long);
static void 	  icache_insert (char*, ImageInfo*, int, unsigned long);
static void	  icache_free (cache_t*);


/* -------------------------------------------------------------------- *
*g ------------- image and imagecache procs --------------------------
** -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- *
*p  procedure-name:	image_resolve
**
**  purpose:		Image resolution function.
**			called by the html widget if image ref occurs
** -------------------------------------------------------------------- *
**  args:		name of image (without help-path).	
**  return type:	ImageInfo*
**  error handling.:	returns NULL if image is not loadable.
** -------------------------------------------------------------------- */
ImageInfo*
image_resolve (/* i  */ Widget 		w,
	       /* i  */ char* 		src,
	       /* i  */ unsigned long	html_no)
{
    ImageInfo*	img_data = NULL;
    if (!src) return NULL;

    /* take the image from the cache if we already have it.  */
    img_data = icache_find (src, html_no);
    if (img_data) {    
	return img_data;
    } else {
	/* filname (with help path). scope: local */
	char*		fname = path_get_helppath (src);

	if (fname) {
	    int mem_usage = 0;
	
	    /*
	     *  code from NCSA Mosaic(Tm) included.
	     */

	    int 		i;
	    int 		cnt;
	    unsigned char 	*data;
	    unsigned char 	*bg_map = NULL;
	    unsigned char 	*bgptr;
	    unsigned char 	*ptr;
	    int 		width;
	    int		height;

	    int 		used [256];
	    XColor 		colrs [256];
	    int 		widthbyheight = 0;

	    int 		bg;
	    int		bg_red = 0;
	    int		bg_green = 0;
	    int 		bg_blue = 0;

	    /* data for visual determination  */
	    XVisualInfo* 	vptr;
	    XVisualInfo 	vinfo;
	    int 		Vclass = PseudoColor;

	    /* find the visual class. (from mosaic pixmaps.c)  */
	    vinfo.visualid = XVisualIDFromVisual 
		(DefaultVisual (XtDisplay (w), 
				DefaultScreen (XtDisplay (w))));
	    vptr = XGetVisualInfo (XtDisplay (w), VisualIDMask, &vinfo, &i);
	    if (vptr) {
		Vclass = vptr->class;
		XFree ((char*) vptr);
	    }
    
	    /* No transparent background by default */
	    bg = -1; bg_map = NULL;
	
	    /* We have to load the image. scope -> icache_free () */
	    data = ReadBitmap (fname, &width, &height, colrs, &bg);
	    checked_free (fname);
	    
	    /* return immediately if ReadBitmap could not load image.  */
	    if (!data) return NULL;
	
	    mem_usage += (width * height * sizeof (char));

	    /* if we have a transparent background, prepare for it */
	    if ((bg >= 0) && (data)) {

		unsigned long 	bg_pixel;
		XColor 		tmpcolr;

		/* 
		 * This code copied from xpmread.c.  I could almost
		 * delete the code from there, but I suppose an XPM
		 * file could pathalogially have multiple transparent
		 * colour indicies. -- GWP
		 */
		XtVaGetValues (w, XtNbackground, &bg_pixel, NULL);
		tmpcolr.pixel = bg_pixel;
		XQueryColor (XtDisplay (w), DefaultColormap
			     (XtDisplay (w), DefaultScreen (XtDisplay (w))),
			     &tmpcolr);

		bg_red = colrs[bg].red = tmpcolr.red;
		bg_green = colrs[bg].green = tmpcolr.green;
		bg_blue = colrs[bg].blue = tmpcolr.blue;
		colrs[bg].flags = DoRed | DoGreen | DoBlue;

		checked_malloc (bg_map, width * height, unsigned char);
		/* will be freed before routine returns.  */
	    }
      
	    checked_malloc (img_data, 1, ImageInfo);
	    mem_usage += sizeof (ImageInfo);
	    img_data->width = width;
	    img_data->height = height;
	    img_data->image_data = data;
	    img_data->image = (Pixmap) NULL;

	    /* Bandaid for bug afflicting Eric's code, apparently. */
	    img_data->internal = 0;

	    widthbyheight = img_data->width * img_data->height;

	    /* Fill out used array. */
	    for (i = 0; i < 256; i++) {
		used [i] = 0;
	    }

	    cnt = 1;
	    bgptr = bg_map;
	    ptr = img_data->image_data;

	    for (i=0; i < widthbyheight; i++) {
		if (used [(int) *ptr] == 0) {
		    used [(int) *ptr] = cnt;
		    cnt++;
		}
		if (bg >= 0) {
		    if (*ptr == bg) {
			*bgptr = (unsigned char)1;
		    } else {
			*bgptr = (unsigned char)0;
		    }
		    bgptr++;
		}
		ptr++;
	    }
	    cnt--;
  
	    /*
	     *  If the image has too many colors, apply a median cut 
	     *  algorithm to reduce the color usage, and then reprocess it.
	     *  Don't cut colors for direct mapped visuals like TrueColor.
	     */
	    if ((cnt > COLORS_PER_IMAGE)
		&& (Vclass != TrueColor)) {
		MedianCut (img_data->image_data, &img_data->width, 
			   &img_data->height, colrs, 256, 
			   COLORS_PER_IMAGE);
      
		for (i=0; i < 256; i++)
		    used [i] = 0;
		cnt = 1;
		ptr = img_data->image_data;
		for (i = 0; i < widthbyheight; i++) {
		    if (used [(int) *ptr] == 0) {
			used [(int) *ptr] = cnt;
			cnt++;
		    }
		    ptr++;
		}
		cnt--;

		/* if we had a transparent bg, MedianCut used it. 
		   Get a new one */
		if (bg >= 0) {
		    cnt++; bg = 256;
		}
	    }

	    img_data->num_colors = cnt;

	    /* allocate the colors.  */
	    checked_malloc (img_data->reds, cnt, int);
	    checked_malloc (img_data->greens, cnt, int);
	    checked_malloc (img_data->blues, cnt, int);
	    mem_usage += ((3 * cnt) * sizeof (int));

	    for (i=0; i < 256; i++) {
		int indx;
      
		if (used[i] != 0) {
		    indx = used[i] - 1;
		    img_data->reds[indx] = colrs[i].red;
		    img_data->greens[indx] = colrs[i].green;
		    img_data->blues[indx] = colrs[i].blue;

		    /* squeegee in the background color */
		    if ((bg >= 0)&&(i == bg)) {
			img_data->reds[indx] = bg_red;
			img_data->greens[indx] = bg_green;
			img_data->blues[indx] = bg_blue;
		    }
		}
	    }

	    /* if MedianCut ate our background, add the new one now. */
	    if (bg == 256) {
		img_data->reds [cnt - 1] = bg_red;
		img_data->greens [cnt - 1] = bg_green;
		img_data->blues [cnt - 1] = bg_blue;
	    }
  
	    bgptr = bg_map;
	    ptr = img_data->image_data;
	    for (i=0; i < widthbyheight; i++) {
		*ptr = (unsigned char) (used [(int)*ptr] - 1);

		/* if MedianCut ate the background, enforce it here */
		if (bg == 256) {
		    if ((int) *bgptr == 1){
			*ptr = (unsigned char) (cnt - 1);
		    }
		    bgptr++;
		}
		ptr++;
	    }

	    /* free the background map if we have one */
	    if (bg_map) {
		checked_free (bg_map);
	    }
	    icache_insert (src, img_data, mem_usage, html_no);
	    return img_data;    
	    
	}  else  { /* if (!fname) */
	    return NULL;
	}/* if (fname)  */
    } /* icache hit  */
    return NULL;
}

/* -------------------------------------------------------------------- *
*p  procedure-name:	icache_find
**
**  purpose:		search image cache for image. 
**			return ImageInfo structure if found
**			else returns NULL.
** -------------------------------------------------------------------- *
**  args:		name of image source (without help prefix).
**  return type:	ImageInfo*
** -------------------------------------------------------------------- */
static ImageInfo*
icache_find (/* i  */ char* 		image_src,
	     /* i  */ unsigned long 	html_no)
{
    cache_t* cache = icache;
    int count = 0;		/* consistency checking: */
				/* must equal cache_len after traversal. */

    /* we traverse the cache list till we find the reference  */
    while (cache) {
	if (0 == c_strcmp (cache->src, image_src)) {
	    cache->html_no = html_no;
	    return cache->image_info;
	}
	
	/* follow the link.  */
	cache = cache->next;
	count++;
	if (count > cache_len) {
	    fprintf (stderr, "inconsistency in icache_find.");
	    fatal_error (error_inconsistency);
	}
    }
    return NULL;
}

/* -------------------------------------------------------------------- *
*p  procedure-name:	icache_insert
**
**  purpose:		inserts a image into the image chache
** -------------------------------------------------------------------- *
**  args:		name of image without help path prefix
**			pointer to ImageInfo structure to cache
**  return type:	static void
**  precondition:	assumes that image not yet cached.
**			image info must be filled up. buffers
**			->reds, ->greens, ->blues, ->image_data
**			must be allocated using malloc or calloc.
**  postcondition:	src is cached if not already.
**			if there is no free place, the oldest 
**			image is removed.
**  error handling.:	nothing is cached. image data is freed.
** -------------------------------------------------------------------- */
static void
icache_insert (/* i  */ char* 		src,
	       /* i  */ ImageInfo*	new_image_info,
	       /* i  */ int		mem_usage,
	       /* i  */ unsigned long 	html_no)
{	
    cache_t* new_elem;

    cache_trace (("html: %d, insert %s: chache_len = %d, mem: %d\n", 
		 (int) html_no, src, cache_len, mem_usage));

    if (cache_len > IMG_CACHE_SIZE) {
	
	/*
	 *  if all images in the cache belong to the same document:
	 *  increment the cache size. else find an image not belonging 
	 *  to the current document. free it. insert the current image
	 *  instead. try to free a second unused image to shrink the cache. 
	 */

	int 		count = 0;
	unsigned long	min_html_no = html_no;
	cache_t*   	oldest_elem  = NULL;
	cache_t*	second_elem  = NULL;
	cache_t*	pre = NULL;
	cache_t*	pre_oldest = NULL;
	cache_t*	pre_second = NULL;

	cache_t*   	cache = icache;
	
	while (cache != NULL) {

	    /* search for unused images.  */
	    if (cache->html_no < min_html_no) {
		min_html_no = cache->html_no;
		second_elem = oldest_elem;
		pre_second = pre_oldest;
		oldest_elem = cache;
		pre_oldest = pre;
	    }
	    pre = cache;
	    cache = cache->next; count++;
	    if (count > cache_len) {
		fprintf (stderr, "inconsistency in icache_find.");
		fatal_error (error_inconsistency);
	    }
	}

	/* Replace if we found one:  */

	if (oldest_elem) {

	    /* Free oldest imageinfo structure and src string.  */
	    icache_free (oldest_elem);
	    
	    /* fill it up with the new image. the links remain.  */
	    oldest_elem->html_no = html_no;
	    checked_strdup (oldest_elem->src, src);
	    oldest_elem->image_info = new_image_info;
	    oldest_elem->mem_usage = mem_usage;
	    cache_mem_usage += mem_usage;
	    
	    /* free a second element to shrink the cache.  */
	    if (second_elem) {
		cache_t* tmp = second_elem->next;
		icache_free (second_elem);
		if (!pre_second) {
		    icache = tmp;
		} else {
		    pre_second->next = tmp;
		}
		checked_free (second_elem);
		cache_len--;
	    }
	    cache_trace (("after: %d cache_mem: %d\n", cache_len, 
			  cache_mem_usage));
	    return;
	}	    
    }

    checked_malloc (new_elem, 1, cache_t);

    /* Insert the new elem at the beginning.  */
    new_elem->html_no = html_no;
    checked_strdup (new_elem->src, src);
    new_elem->image_info = new_image_info;
    new_elem->next = icache;
    new_elem->mem_usage = mem_usage;
    cache_mem_usage += mem_usage;
    
    icache = new_elem;
    cache_len++;
    cache_trace (("after: %d cache_mem: %d\n", cache_len, cache_mem_usage));
    return;
}

/* -------------------------------------------------------------------- *
*p  procedure-name:	icache_free
**
**  purpose:		frees all data of a cache entry. does not free 
**			entry itself.
** -------------------------------------------------------------------- */
static void
icache_free (/* i  */ cache_t* entry)
{
    if (entry) {
	ImageInfo* iinfo = entry->image_info;

	cache_mem_usage -= entry->mem_usage;

	if (iinfo->reds)   	checked_free (iinfo->reds);
	if (iinfo->greens) 	checked_free (iinfo->greens);
	if (iinfo->blues)  	checked_free (iinfo->blues);
	if (iinfo->image_data)	checked_free (iinfo->image_data);
	    
	checked_free (iinfo);
	checked_free (entry->src);
    }    
}

/* -------------------------------------------------------------------- *
*p  procedure-name:	icache_flush
**
**  purpose:		releases all information in the image cache.
** 			%%% can be dangerous %%%
** -------------------------------------------------------------------- */
void
icache_flush (void)
{
    cache_t* icp = icache;
    
    while (icp) {

	cache_t* inx = icp->next;
	icache_free (icp);
	checked_free (icp);
	cache_len--;
	icp = inx;
    }
    if (cache_len != 0) {
	fprintf (stderr, "inconsistency in image cache (flush)\n");
	exit (EXIT_FAILURE);
    }
    icache = NULL;
}

/* -------------------------------------------------------------------- *
*g ------------ small information functions ---------------------------
** -------------------------------------------------------------------- */
int 
the_cache_mem (void)
{
    return cache_mem_usage;
}

int 
the_cache_size (void)
{
    return cache_len;
}

int 
the_cache_default_size (void)
{
    return IMG_CACHE_SIZE;
}

int 
the_colors (void)
{
    return COLORS_PER_IMAGE;
}

/* -------------------------------------------------------------------- *
*l  emacs:
**  local variables:
**  mode:		c
**  outline-regexp:	"\*[HGPLT]"
**  comment-column:	32
**  eval:		(outline-minor-mode t)
**  end:
** -------------------------------------------------------------------- */