The R Project SVN R

Rev

Rev 44003 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 44003 Rev 45017
Line 49... Line 49...
49
/*
49
/*
50
 *  Create a new image:
50
 *  Create a new image:
51
 */
51
 */
52
image newimage(int width, int height, int depth)
52
image newimage(int width, int height, int depth)
53
{
53
{
54
	image img;
54
    image img;
55
 
55
 
56
	if ((depth != 8) && (depth != 32))
56
    if ((depth != 8) && (depth != 32))
57
		return NULL;
57
	return NULL;
58
 
58
 
59
	img = create(struct imagedata);
59
    img = create(struct imagedata);
60
 
60
 
61
	if (! img)
61
    if (! img)
62
		return img;
62
	return img;
63
 
63
 
64
	img->width  = width;
64
    img->width  = width;
65
	img->height = height;
65
    img->height = height;
66
 
66
 
67
	if (depth == 8) {
67
    if (depth == 8) {
68
		img->depth  = 8;
68
	img->depth  = 8;
69
		img->pixels = array(width*height, byte);
69
	img->pixels = array(width*height, byte);
70
	}
70
    }
71
	else {
71
    else {
72
		img->depth  = 32;
72
	img->depth  = 32;
73
		img->pixels = (byte *) array(width*height, rgb);
73
	img->pixels = (byte *) array(width*height, rgb);
74
	}
74
    }
75
 
75
 
76
	return img;
76
    return img;
77
}
77
}
78
 
78
 
79
/*
79
/*
80
 *  Make a new copy of an image:
80
 *  Make a new copy of an image:
81
 */
81
 */
82
image copyimage(image img)
82
image copyimage(image img)
83
{
83
{
84
	image new_img;
84
    image new_img;
85
 
85
 
86
	if (! img)
86
    if (! img)
87
		return img;
87
	return img;
88
 
88
 
89
	new_img = newimage(img->width, img->height, img->depth);
89
    new_img = newimage(img->width, img->height, img->depth);
90
	setpixels(new_img, img->pixels);
90
    setpixels(new_img, img->pixels);
91
	setpalette(new_img, img->cmapsize, img->cmap);
91
    setpalette(new_img, img->cmapsize, img->cmap);
92
 
92
 
93
	return new_img;
93
    return new_img;
94
}
94
}
95
 
95
 
96
/*
96
/*
97
 *  Delete an image:
97
 *  Delete an image:
98
 */
98
 */
99
void delimage(image img)
99
void delimage(image img)
100
{
100
{
101
	if (img) {
101
    if (img) {
102
		discard(img->cmap);
102
	discard(img->cmap);
103
		discard(img->pixels);
103
	discard(img->pixels);
104
		discard(img);
104
	discard(img);
105
	}
105
    }
106
}
106
}
107
 
107
 
108
/*
108
/*
109
 *  Print an image:
109
 *  Print an image:
110
 */
110
 */
111
#if DEBUG
111
#if DEBUG
112
PROTECTED
112
PROTECTED
113
void printimage(FILE *file, image img)
113
void printimage(FILE *file, image img)
114
{
114
{
115
	int i;
115
    int i;
116
	long w, h, n;
116
    long w, h, n;
117
 
117
 
118
	fprintf(file, "Pixmap:\n");
118
    fprintf(file, "Pixmap:\n");
119
	fprintf(file, " depth     = %d\n", img->depth);
119
    fprintf(file, " depth     = %d\n", img->depth);
120
	fprintf(file, " width     = %d\n", img->width);
120
    fprintf(file, " width     = %d\n", img->width);
121
	fprintf(file, " height    = %d\n", img->height);
121
    fprintf(file, " height    = %d\n", img->height);
122
	fprintf(file, " cmapsize = %d\n", img->cmapsize);
122
    fprintf(file, " cmapsize = %d\n", img->cmapsize);
123
	fprintf(file, " cmap:\n");
123
    fprintf(file, " cmap:\n");
124
	for (i=0; i < img->cmapsize; i++)
124
    for (i=0; i < img->cmapsize; i++)
125
		fprintf(file, "  %-02.2X = %-08.8lX\n", i, img->cmap[i]);
125
	fprintf(file, "  %-02.2X = %-08.8lX\n", i, img->cmap[i]);
126
	fprintf(file, " pixels:\n");
126
    fprintf(file, " pixels:\n");
127
	for (h=0; h < img->height; h++) {
127
    for (h=0; h < img->height; h++) {
128
		fprintf(file, "  [");
128
	fprintf(file, "  [");
129
		for (w=0; w < (img->width * img->depth / 8); w++) {
129
	for (w=0; w < (img->width * img->depth / 8); w++) {
130
			n = h * (img->width * img->depth / 8) + w;
130
	    n = h * (img->width * img->depth / 8) + w;
131
			fprintf(file, "%-02.2X", img->pixels[n]);
131
	    fprintf(file, "%-02.2X", img->pixels[n]);
132
		}
-
 
133
		fprintf(file, "]\n");
-
 
134
	}
132
	}
-
 
133
	fprintf(file, "]\n");
-
 
134
    }
135
}
135
}
136
#endif
136
#endif
137
 
137
 
138
/*
138
/*
139
 *  Discover the dimensions of the image:
139
 *  Discover the dimensions of the image:
Line 146... Line 146...
146
/*
146
/*
147
 *  Change an image's pixels:
147
 *  Change an image's pixels:
148
 */
148
 */
149
void setpixels(image img, byte pixels[])
149
void setpixels(image img, byte pixels[])
150
{
150
{
151
	long i, length;
151
    long i, length;
152
 
152
 
153
	if (! img)
153
    if (! img)
154
		return;
154
	return;
155
 
155
 
156
	length = img->width * img->height;
156
    length = img->width * img->height;
157
	if (img->depth > 8)
157
    if (img->depth > 8)
158
		length = length * sizeof(rgb);
158
	length = length * sizeof(rgb);
159
 
159
 
160
	for (i=0; i < length; i++)
160
    for (i=0; i < length; i++)
161
		img->pixels[i] = pixels[i];
161
	img->pixels[i] = pixels[i];
162
}
162
}
163
 
163
 
164
/*
164
/*
165
 *  Return an image's pixel array:
165
 *  Return an image's pixel array:
166
 */
166
 */
167
byte * getpixels(image img)
167
byte * getpixels(image img)
168
{
168
{
169
	if (img)
169
    if (img)
170
		return img->pixels;
170
	return img->pixels;
171
	else
171
    else
172
		return NULL;
172
	return NULL;
173
}
173
}
174
 
174
 
175
/*
175
/*
176
 *  Change an image's cmap:
176
 *  Change an image's cmap:
177
 */
177
 */
178
void setpalette(image img, int cmapsize, rgb *cmap)
178
void setpalette(image img, int cmapsize, rgb *cmap)
179
{
179
{
180
	int i;
180
    int i;
181
 
181
 
182
	if (! img)
182
    if (! img)
183
		return;
183
	return;
184
 
184
 
185
	discard(img->cmap);
185
    discard(img->cmap);
186
 
186
 
187
	img->cmapsize = cmapsize;
187
    img->cmapsize = cmapsize;
188
	img->cmap = array(cmapsize, rgb);
188
    img->cmap = array(cmapsize, rgb);
189
 
189
 
190
	for (i=0; i < cmapsize; i++)
190
    for (i=0; i < cmapsize; i++)
191
		img->cmap[i] = cmap[i];
191
	img->cmap[i] = cmap[i];
192
}
192
}
193
 
193
 
194
/*
194
/*
195
 *  Return information about an image's cmap:
195
 *  Return information about an image's cmap:
196
 */
196
 */
197
rgb * getpalette(image img)
197
rgb * getpalette(image img)
198
{
198
{
199
	if (img)
199
    if (img)
200
		return img->cmap;
200
	return img->cmap;
201
	else
201
    else
202
		return NULL;
202
	return NULL;
203
}
203
}
204
 
204
 
205
int getpalettesize(image img)
205
int getpalettesize(image img)
206
{
206
{
207
	if (img)
207
    if (img)
208
		return img->cmapsize;
208
	return img->cmapsize;
209
	else
209
    else
210
		return 0;
210
	return 0;
211
}
211
}
212
 
212
 
213
/*
213
/*
214
 *  Try to generate an 8-bit version of an image:
214
 *  Try to generate an 8-bit version of an image:
215
 *  If there are less than 256 unique colours in a 32-bit
215
 *  If there are less than 256 unique colours in a 32-bit
Line 217... Line 217...
217
 *  indexed 8-bit image.
217
 *  indexed 8-bit image.
218
 *  Returns NULL if more than 256 colours are found.
218
 *  Returns NULL if more than 256 colours are found.
219
 */
219
 */
220
static image fast_find_cmap (image img)
220
static image fast_find_cmap (image img)
221
{
221
{
222
	image new_img;
222
    image new_img;
223
	long   i, j, length;
223
    long   i, j, length;
224
	rgb *  pixel32;
224
    rgb *  pixel32;
225
	byte * pixel8;
225
    byte * pixel8;
226
	int    cmapsize, low, high, mid;
226
    int    cmapsize, low, high, mid;
227
	rgb    col;
227
    rgb    col;
228
	rgb    cmap[256];
228
    rgb    cmap[256];
229
 
229
 
230
	pixel32 = (rgb *) img->pixels;
230
    pixel32 = (rgb *) img->pixels;
231
 
231
 
232
	/* the first colour goes into the cmap automatically: */
232
    /* the first colour goes into the cmap automatically: */
233
	length = img->width * img->height;
233
    length = img->width * img->height;
234
	cmapsize = 0;  mid = 0;
234
    cmapsize = 0;  mid = 0;
-
 
235
 
-
 
236
    for (i=0; i < length; i++)
-
 
237
    {
-
 
238
	col = *pixel32 ++;
-
 
239
	/* only allow one transparent colour in the cmap: */
-
 
240
	if (col & 0xF0000000UL)
-
 
241
	    col  = 0xFFFFFFFFUL;	/* transparent */
-
 
242
	else
-
 
243
	    col &= 0x00FFFFFFUL;	/* opaque */
235
 
244
 
236
	for (i=0; i < length; i++)
-
 
237
	{
-
 
238
		col = *pixel32 ++;
-
 
239
		/* only allow one transparent colour in the cmap: */
-
 
240
		if (col & 0xF0000000UL)
-
 
241
			col  = 0xFFFFFFFFUL;	/* transparent */
-
 
242
		else
-
 
243
			col &= 0x00FFFFFFUL;	/* opaque */
-
 
244
 
-
 
245
		/* binary search the cmap: */
245
	/* binary search the cmap: */
246
		low = 0;  high = cmapsize - 1;
246
	low = 0;  high = cmapsize - 1;
247
		while (low <= high) {
247
	while (low <= high) {
248
			mid = (low+high)/2;
248
	    mid = (low+high)/2;
249
			if      (col < cmap[mid]) high = mid - 1;
249
	    if      (col < cmap[mid]) high = mid - 1;
250
			else if (col > cmap[mid]) low  = mid + 1;
250
	    else if (col > cmap[mid]) low  = mid + 1;
251
			else break;
251
	    else break;
252
		}
252
	}
253
 
253
 
254
		if (high < low) {
254
	if (high < low) {
255
			/* didn't find colour in cmap, insert it: */
255
	    /* didn't find colour in cmap, insert it: */
256
			if (cmapsize >= 256)
256
	    if (cmapsize >= 256)
257
				return NULL;
257
		return NULL;
258
			for (j=cmapsize; j > low; j--)
258
	    for (j=cmapsize; j > low; j--)
259
				cmap[j] = cmap[j-1];
259
		cmap[j] = cmap[j-1];
260
			cmap[low] = col;
260
	    cmap[low] = col;
261
			cmapsize ++;
261
	    cmapsize ++;
262
		}
-
 
263
	}
262
	}
-
 
263
    }
264
 
264
 
265
	/* now create the 8-bit indexed image: */
265
    /* now create the 8-bit indexed image: */
266
 
266
 
267
	new_img = newimage(img->width, img->height, 8);
267
    new_img = newimage(img->width, img->height, 8);
268
	if (! new_img)
268
    if (! new_img)
269
		return new_img;
269
	return new_img;
270
	setpalette(new_img, cmapsize, cmap);
270
    setpalette(new_img, cmapsize, cmap);
271
 
271
 
272
	/* now convert each 32-bit pixel into an 8-bit pixel: */
272
    /* now convert each 32-bit pixel into an 8-bit pixel: */
273
 
273
 
274
	pixel32 = (rgb *) img->pixels;
274
    pixel32 = (rgb *) img->pixels;
275
	pixel8 = (byte *) new_img->pixels;
275
    pixel8 = (byte *) new_img->pixels;
276
 
276
 
277
	for (i=0; i < length; i++)
277
    for (i=0; i < length; i++)
278
	{
278
    {
279
		col = *pixel32 ++;
279
	col = *pixel32 ++;
280
 
280
 
281
		/* only allow one transparent colour in the cmap: */
281
	/* only allow one transparent colour in the cmap: */
282
		if (col & 0xF0000000UL)
282
	if (col & 0xF0000000UL)
283
			col  = 0xFFFFFFFFUL;	/* transparent */
283
	    col  = 0xFFFFFFFFUL;	/* transparent */
284
		else
284
	else
285
			col &= 0x00FFFFFFUL;	/* opaque */
285
	    col &= 0x00FFFFFFUL;	/* opaque */
286
 
-
 
287
		/* binary search the cmap (the colour must be there): */
-
 
288
		low = 0;  high = cmapsize - 1;
-
 
289
		while (low <= high) {
-
 
290
			mid = (low+high)/2;
-
 
291
			if      (col < cmap[mid]) high = mid - 1;
-
 
292
			else if (col > cmap[mid]) low  = mid + 1;
-
 
293
			else break;
-
 
294
		}
-
 
295
 
-
 
296
		if (high < low) {
-
 
297
			/* impossible situation */
-
 
298
			delimage(new_img);
-
 
299
			return NULL;
-
 
300
		}
-
 
301
 
286
 
-
 
287
	/* binary search the cmap (the colour must be there): */
302
		*pixel8 = mid;  pixel8 ++;
288
	low = 0;  high = cmapsize - 1;
-
 
289
	while (low <= high) {
-
 
290
	    mid = (low+high)/2;
-
 
291
	    if      (col < cmap[mid]) high = mid - 1;
-
 
292
	    else if (col > cmap[mid]) low  = mid + 1;
-
 
293
	    else break;
303
	}
294
	}
304
 
295
 
-
 
296
	if (high < low) {
-
 
297
	    /* impossible situation */
-
 
298
	    delimage(new_img);
-
 
299
	    return NULL;
-
 
300
	}
-
 
301
 
-
 
302
	*pixel8 = mid;  pixel8 ++;
-
 
303
    }
-
 
304
 
305
	return new_img;
305
    return new_img;
306
}
306
}
307
 
307
 
308
/*
308
/*
309
 *  Try to generate an 8-bit version of an image:
309
 *  Try to generate an 8-bit version of an image:
310
 *  This routine will approximate a 32-bit image using a
310
 *  This routine will approximate a 32-bit image using a
311
 *  7x7x5 colour cube.
311
 *  7x7x5 colour cube.
312
 *  If it runs out of memory, it returns NULL.
312
 *  If it runs out of memory, it returns NULL.
313
 */
313
 */
314
static image fast_generate_cmap (image img)
314
static image fast_generate_cmap (image img)
315
{
315
{
316
	image new_img;
316
    image new_img;
317
	long   i, length, col;
317
    long   i, length, col;
318
	int    r, g, b, value;
318
    int    r, g, b, value;
319
	rgb *  pixel32;
319
    rgb *  pixel32;
320
	byte * pixel8;
320
    byte * pixel8;
321
	rgb    cmap[256];
321
    rgb    cmap[256];
322
 
322
 
323
	/* Generate the colour map: */
323
    /* Generate the colour map: */
324
 
324
 
325
	for (r=0; r<7; r++)		/* 7x7x5 colour cube */
325
    for (r=0; r<7; r++)		/* 7x7x5 colour cube */
326
	  for (g=0; g<7; g++)
326
	for (g=0; g<7; g++)
327
	    for (b=0; b<5; b++)
327
	    for (b=0; b<5; b++)
328
		cmap [r*35 + g*5 + b] = rgb(r,g,b);
328
		cmap [r*35 + g*5 + b] = rgb(r,g,b);
329
 
329
 
330
	for (i=0; i<9; i++)		/* greyscale ramp */
330
    for (i=0; i<9; i++)		/* greyscale ramp */
331
	{
331
    {
332
		value = 255 * i / 8;
332
	value = 255 * i / 8;
333
		cmap [254 - 8 + i] = rgb(value, value, value);
333
	cmap [254 - 8 + i] = rgb(value, value, value);
-
 
334
    }
-
 
335
 
-
 
336
    cmap [255] = 0xFFFFFFFFUL;	/* transparent */
-
 
337
 
-
 
338
    /* Generate the 8-bit indexed image: */
-
 
339
 
-
 
340
    new_img = newimage(img->width, img->height, 8);
-
 
341
    if (! new_img)
-
 
342
	return new_img;
-
 
343
    setpalette(new_img, 256, cmap);
334
	}
344
 
-
 
345
    /* Translate the pixels from 32-bit to 8-bit: */
335
 
346
 
-
 
347
    length = img->width * img->height;
-
 
348
    pixel32 = (rgb *) img->pixels;
336
	cmap [255] = 0xFFFFFFFFUL;	/* transparent */
349
    pixel8 = (byte *) new_img->pixels;
337
 
350
 
338
	/* Generate the 8-bit indexed image: */
351
    for (i=0; i < length; i++) {
-
 
352
	col = *pixel32 ++;
-
 
353
	r = getred(col);
-
 
354
	g = getgreen(col);
-
 
355
	b = getblue(col);
339
 
356
 
340
	new_img = newimage(img->width, img->height, 8);
-
 
341
	if (! new_img)
-
 
342
		return new_img;
-
 
343
	setpalette(new_img, 256, cmap);
-
 
344
 
-
 
345
	/* Translate the pixels from 32-bit to 8-bit: */
-
 
346
 
-
 
347
	length = img->width * img->height;
-
 
348
	pixel32 = (rgb *) img->pixels;
-
 
349
	pixel8 = (byte *) new_img->pixels;
-
 
350
 
-
 
351
	for (i=0; i < length; i++) {
-
 
352
		col = *pixel32 ++;
-
 
353
		r = getred(col);
-
 
354
		g = getgreen(col);
-
 
355
		b = getblue(col);
-
 
356
 
-
 
357
		if (getalpha(col) > 0x7F)  /* transparent */
357
	if (getalpha(col) > 0x7F)  /* transparent */
358
			value = 255;
358
	    value = 255;
359
 
-
 
360
		else if ((r == g) && (r == b))	/* grey */
-
 
361
		{
-
 
362
			r = (r + 16) / 32;
-
 
363
			if (r == 0)
-
 
364
				value = 0;	/* black */
-
 
365
			else
-
 
366
				value = 254 - 8 + r;
-
 
367
		}
-
 
368
 
-
 
369
		else	/* map to 7x7x5 colour cube */
-
 
370
		{
-
 
371
			r = (r + 21) / 42;
-
 
372
			g = (g + 21) / 42;
-
 
373
			b = (b + 32) / 64;
-
 
374
 
359
 
-
 
360
	else if ((r == g) && (r == b))	/* grey */
-
 
361
	{
-
 
362
	    r = (r + 16) / 32;
-
 
363
	    if (r == 0)
-
 
364
		value = 0;	/* black */
-
 
365
	    else
375
			value = r*35 + g*5 + b;
366
		value = 254 - 8 + r;
376
		}
367
	}
-
 
368
 
-
 
369
	else	/* map to 7x7x5 colour cube */
-
 
370
	{
-
 
371
	    r = (r + 21) / 42;
-
 
372
	    g = (g + 21) / 42;
-
 
373
	    b = (b + 32) / 64;
377
 
374
 
378
		*pixel8 = value;  pixel8 ++;
375
	    value = r*35 + g*5 + b;
379
	}
376
	}
380
 
377
 
-
 
378
	*pixel8 = value;  pixel8 ++;
-
 
379
    }
-
 
380
 
381
	return new_img;
381
    return new_img;
382
}
382
}
383
 
383
 
384
/*
384
/*
385
 *  Try to generate an 8-bit version of a 32-bit image:
385
 *  Try to generate an 8-bit version of a 32-bit image:
386
 *  Return NULL on failure.
386
 *  Return NULL on failure.
387
 */
387
 */
388
image convert32to8 (image img)
388
image convert32to8 (image img)
389
{
389
{
390
	image new_img;
390
    image new_img;
391
 
391
 
392
	if (! img)
392
    if (! img)
393
		return img;
393
	return img;
394
 
394
 
395
	if (img->depth <= 8)
395
    if (img->depth <= 8)
396
		return copyimage(img);
396
	return copyimage(img);
397
 
397
 
398
	new_img = fast_find_cmap(img);
398
    new_img = fast_find_cmap(img);
399
	if (! new_img)
399
    if (! new_img)
400
		new_img = fast_generate_cmap(img);
400
	new_img = fast_generate_cmap(img);
401
 
401
 
402
	return new_img;
402
    return new_img;
403
}
403
}
404
 
404
 
405
/*
405
/*
406
 *  Try to generate a 32-bit version of an 8-bit image:
406
 *  Try to generate a 32-bit version of an 8-bit image:
407
 *  Return NULL if there is no memory left.
407
 *  Return NULL if there is no memory left.
408
 */
408
 */
409
image convert8to32 (image img)
409
image convert8to32 (image img)
410
{
410
{
411
	image new_img;
411
    image new_img;
412
	long i;
412
    long i;
413
	rgb *pixel32;
413
    rgb *pixel32;
414
	byte *pixel8;
414
    byte *pixel8;
415
	byte value;
415
    byte value;
416
 
416
 
417
	if (! img)
417
    if (! img)
418
		return img;
418
	return img;
419
 
-
 
420
	new_img = newimage(img->width, img->height, 32);
-
 
421
	if (! new_img)
-
 
422
		return new_img;
-
 
423
 
-
 
424
	pixel32 = (rgb *) new_img->pixels;
-
 
425
	pixel8 = (byte *) img->pixels;
-
 
426
 
-
 
427
	for (i=img->width * img->height; i; i--) {
-
 
428
		value = *pixel8 ++;
-
 
429
		if (value >= img->cmapsize)
-
 
430
			value = img->cmapsize - 1;
-
 
431
		*pixel32 ++ = img->cmap[value];
-
 
432
	}
-
 
433
 
419
 
-
 
420
    new_img = newimage(img->width, img->height, 32);
-
 
421
    if (! new_img)
434
	return new_img;
422
	return new_img;
-
 
423
 
-
 
424
    pixel32 = (rgb *) new_img->pixels;
-
 
425
    pixel8 = (byte *) img->pixels;
-
 
426
 
-
 
427
    for (i=img->width * img->height; i; i--) {
-
 
428
	value = *pixel8 ++;
-
 
429
	if (value >= img->cmapsize)
-
 
430
	    value = img->cmapsize - 1;
-
 
431
	*pixel32 ++ = img->cmap[value];
-
 
432
    }
-
 
433
 
-
 
434
    return new_img;
435
}
435
}
436
 
436
 
437
/*
437
/*
438
 *  Sort an image's colour map, eliminating redudancies.
438
 *  Sort an image's colour map, eliminating redudancies.
439
 *  This operation transforms an existing image.
439
 *  This operation transforms an existing image.
Line 441... Line 441...
441
 
441
 
442
typedef int (*qsort_func)(const void *a, const void *b);
442
typedef int (*qsort_func)(const void *a, const void *b);
443
 
443
 
444
static int compare_freq(long *a, long *b)
444
static int compare_freq(long *a, long *b)
445
{
445
{
446
	long freq_a, freq_b;
446
    long freq_a, freq_b;
447
	int value_a, value_b;
447
    int value_a, value_b;
448
 
448
 
449
	freq_a = (*a) >> 8;
449
    freq_a = (*a) >> 8;
450
	freq_b = (*b) >> 8;
450
    freq_b = (*b) >> 8;
451
	value_a = (*a) & 0x00FF;
451
    value_a = (*a) & 0x00FF;
452
	value_b = (*b) & 0x00FF;
452
    value_b = (*b) & 0x00FF;
453
 
453
 
454
	if (freq_a < freq_b)        return (+1);
454
    if (freq_a < freq_b)        return (+1);
455
	else if (freq_a > freq_b)   return (-1);
455
    else if (freq_a > freq_b)   return (-1);
456
	else                        return (value_a - value_b);
456
    else                        return (value_a - value_b);
457
}
457
}
458
 
458
 
459
void sortpalette(image img)
459
void sortpalette(image img)
460
{
460
{
461
	long	i, j, length;
461
    long	i, j, length;
462
	int 	old_value, new_value;
462
    int	old_value, new_value;
463
	rgb 	col;
463
    rgb	col;
464
	int 	new_size;
464
    int	new_size;
465
	long *	histogram;
465
    long *	histogram;
466
	byte *	translate;
466
    byte *	translate;
467
	rgb *	new_cmap;
467
    rgb *	new_cmap;
468
 
468
 
469
	if (! img)
469
    if (! img)
470
		return;
470
	return;
471
	if (img->depth > 8)
471
    if (img->depth > 8)
472
		return;
472
	return;
473
 
473
 
474
	histogram = array(256, long);
474
    histogram = array(256, long);
475
	translate = array(256, byte);
475
    translate = array(256, byte);
476
 
476
 
477
	/* Generate a colour histogram: */
477
    /* Generate a colour histogram: */
478
	length = img->width * img->height;
478
    length = img->width * img->height;
479
	for (i=0; i < length; i++)
479
    for (i=0; i < length; i++)
480
		histogram[img->pixels[i]] ++;
480
	histogram[img->pixels[i]] ++;
481
 
481
 
482
	/* Place colour indexes in low byte of histogram: */
482
    /* Place colour indexes in low byte of histogram: */
483
	for (i=0; i < 256; i++) {
483
    for (i=0; i < 256; i++) {
484
		histogram[i] <<= 8;
484
	histogram[i] <<= 8;
485
		histogram[i] |= i;
485
	histogram[i] |= i;
486
	}
486
    }
487
 
487
 
488
	/* Sort the histogram in decreasing frequency order: */
488
    /* Sort the histogram in decreasing frequency order: */
489
	qsort(histogram, 256, sizeof(long), (qsort_func) compare_freq);
489
    qsort(histogram, 256, sizeof(long), (qsort_func) compare_freq);
490
 
490
 
491
	/* Generate a colour translation table: */
491
    /* Generate a colour translation table: */
492
	new_size = img->cmapsize;
492
    new_size = img->cmapsize;
493
 
493
 
494
	for (i=255; i >= 0; i--)
494
    for (i=255; i >= 0; i--)
495
	{
495
    {
496
		old_value = histogram[i] & 0x00FFL;
496
	old_value = histogram[i] & 0x00FFL;
497
		new_value = i;
497
	new_value = i;
498
		col = img->cmap[i];
498
	col = img->cmap[i];
499
 
499
 
500
		/* coalesce identical colours in cmap */
500
	/* coalesce identical colours in cmap */
501
		for (j=i-1; j >= 0; j--) {
501
	for (j=i-1; j >= 0; j--) {
502
			if (img->cmap[j] == col)
502
	    if (img->cmap[j] == col)
503
				new_value = j;
503
		new_value = j;
504
		}
504
	}
505
 
505
 
506
		translate[old_value] = new_value;
506
	translate[old_value] = new_value;
507
 
507
 
508
		/* find smallest useless colour */
508
	/* find smallest useless colour */
509
		if ((histogram[i] >> 8) == 0)
509
	if ((histogram[i] >> 8) == 0)
510
			new_size = i;
510
	    new_size = i;
511
	}
511
    }
512
 
512
 
513
	/* Generate a sorted colour map: */
513
    /* Generate a sorted colour map: */
514
	new_cmap = array(new_size, rgb);
514
    new_cmap = array(new_size, rgb);
515
 
515
 
516
	for (i=0; i < new_size; i++) {
516
    for (i=0; i < new_size; i++) {
517
		old_value = histogram[i] & 0x00FFL;
517
	old_value = histogram[i] & 0x00FFL;
518
		new_value = i;
518
	new_value = i;
519
		new_cmap[new_value] = img->cmap[old_value];
519
	new_cmap[new_value] = img->cmap[old_value];
520
	}
520
    }
521
 
521
 
522
	/* Change the existing colour map: */
522
    /* Change the existing colour map: */
523
	img->cmapsize = new_size;
523
    img->cmapsize = new_size;
524
	for (i=0; i < new_size; i++)
524
    for (i=0; i < new_size; i++)
525
		img->cmap[i] = new_cmap[i];
525
	img->cmap[i] = new_cmap[i];
526
	discard(new_cmap);
526
    discard(new_cmap);
527
 
527
 
528
	/* Translate the pixels to the new colour map: */
528
    /* Translate the pixels to the new colour map: */
529
	for (i=0 ; i < length; i++)
529
    for (i=0 ; i < length; i++)
530
		img->pixels[i] = translate[img->pixels[i]];
530
	img->pixels[i] = translate[img->pixels[i]];
531
 
531
 
532
	/* Clean up and return new image: */
532
    /* Clean up and return new image: */
533
	discard(translate);
533
    discard(translate);
534
	discard(histogram);
534
    discard(histogram);
535
}
535
}
536
 
536
 
537
#ifdef UNUSED
537
#ifdef UNUSED
538
/*
538
/*
539
 *  Load and save images (utility functions):
539
 *  Load and save images (utility functions):
540
 */
540
 */
541
static int string_ends_with(const char *name, const char *ending)
541
static int string_ends_with(const char *name, const char *ending)
542
{
542
{
543
	int i, j, result;
543
    int i, j, result;
544
 
544
 
545
	if (name == NULL)
545
    if (name == NULL)
546
		return (ending == NULL);
546
	return (ending == NULL);
547
 
547
 
548
	result = 1;
548
    result = 1;
549
	for (i=0; name[i]; )
549
    for (i=0; name[i]; )
550
		i = i + 1;
550
	i = i + 1;
551
	for (j=0; ending[j]; )
551
    for (j=0; ending[j]; )
552
		j = j + 1;
552
	j = j + 1;
553
	while (result && (i >= 0) && (j >= 0)) {
553
    while (result && (i >= 0) && (j >= 0)) {
554
		if (tolower(name[i]) != tolower(ending[j]))
554
	if (tolower(name[i]) != tolower(ending[j]))
555
			result = 0;
555
	    result = 0;
556
		i = i - 1;
556
	i = i - 1;
557
		j = j - 1;
557
	j = j - 1;
558
	}
558
    }
559
	if ((i == 0) && (j > 0))
559
    if ((i == 0) && (j > 0))
560
		result = 0;
560
	result = 0;
561
	return result;
561
    return result;
562
}
562
}
563
 
563
 
564
static unsigned char read_hex_byte(FILE *file)
564
static unsigned char read_hex_byte(FILE *file)
565
{
565
{
566
	int ch;
566
    int ch;
567
	int i, value;
567
    int i, value;
568
	unsigned char result = 0;
568
    unsigned char result = 0;
569
 
569
 
570
	ch = 0;
570
    ch = 0;
571
	while (ch != EOF) {
571
    while (ch != EOF) {
572
		if ((ch = getc(file)) != '0') continue;
572
	if ((ch = getc(file)) != '0') continue;
573
		if ((ch = getc(file)) != 'x') continue;
573
	if ((ch = getc(file)) != 'x') continue;
574
 
574
 
575
		for (i=0; i<2; i++) {
575
	for (i=0; i<2; i++) {
576
			ch = getc(file);
576
	    ch = getc(file);
577
			if (isdigit(ch))
577
	    if (isdigit(ch))
578
				value = ch - '0';
578
		value = ch - '0';
579
			else if (isalpha(ch))
579
	    else if (isalpha(ch))
580
				value = tolower(ch) - 'a' + 10;
580
		value = tolower(ch) - 'a' + 10;
581
			else
581
	    else
582
				return result;
582
		return result;
583
			result = (result << 4) | value;
583
	    result = (result << 4) | value;
584
		}
584
	}
585
		break;
585
	break;
586
	}
586
    }
587
	return result;
587
    return result;
588
}
588
}
589
 
589
 
590
static unsigned long read_hex_long(FILE *file)
590
static unsigned long read_hex_long(FILE *file)
591
{
591
{
592
	int ch;
592
    int ch;
593
	int i, value;
593
    int i, value;
594
	unsigned long result = 0;
594
    unsigned long result = 0;
595
 
595
 
596
	ch = 0;
596
    ch = 0;
597
	while (ch != EOF) {
597
    while (ch != EOF) {
598
		if ((ch = getc(file)) != '0') continue;
598
	if ((ch = getc(file)) != '0') continue;
599
		if ((ch = getc(file)) != 'x') continue;
599
	if ((ch = getc(file)) != 'x') continue;
600
 
600
 
601
		for (i=0; i<8; i++) {
601
	for (i=0; i<8; i++) {
602
			ch = getc(file);
602
	    ch = getc(file);
603
			if (isdigit(ch))
603
	    if (isdigit(ch))
604
				value = ch - '0';
604
		value = ch - '0';
605
			else if (isalpha(ch)) {
605
	    else if (isalpha(ch)) {
606
				ch = tolower(ch);
606
		ch = tolower(ch);
607
				if (ch > 'f')
607
		if (ch > 'f')
608
					return result;
608
		    return result;
609
				value = ch - 'a' + 10;
609
		value = ch - 'a' + 10;
610
			}
610
	    }
611
			else
611
	    else
612
				return result;
612
		return result;
613
			result = (result << 4) | value;
613
	    result = (result << 4) | value;
614
		}
614
	}
615
		break;
615
	break;
616
	}
616
    }
617
	return result;
617
    return result;
618
}
618
}
619
 
619
 
620
static const char * header_comment   = "/* GraphApp image type 1 */\n";
620
static const char * header_comment   = "/* GraphApp image type 1 */\n";
621
static const char * depth_comment    = "/* depth  = %d */\n";
621
static const char * depth_comment    = "/* depth  = %d */\n";
622
static const char * width_comment    = "/* width  = %d */\n";
622
static const char * width_comment    = "/* width  = %d */\n";
623
static const char * height_comment   = "/* height = %d */\n";
623
static const char * height_comment   = "/* height = %d */\n";
624
static const char * cmapsize_comment = "/* cmapsize = %d */\n";
624
static const char * cmapsize_comment = "/* cmapsize = %d */\n";
625
 
625
 
626
static image load_header_image_file(FILE *file)
626
static image load_header_image_file(FILE *file)
627
{
627
{
628
	char  line[100];
628
    char  line[100];
629
	long  i, size;
629
    long  i, size;
630
	int   width = 0, height = 0, depth = 8;
630
    int   width = 0, height = 0, depth = 8;
631
	int   cmapsize = 0;
631
    int   cmapsize = 0;
632
	rgb * cmap = NULL;
632
    rgb * cmap = NULL;
633
	rgb  *pixel32;
633
    rgb  *pixel32;
634
	byte *pixel8;
634
    byte *pixel8;
635
	image img = NULL;
635
    image img = NULL;
636
 
636
 
637
	if (file == NULL)
637
    if (file == NULL)
-
 
638
	return NULL;
-
 
639
 
-
 
640
    if (fgets(line, sizeof(line)-2, file) == NULL)
-
 
641
	return NULL;
-
 
642
    if (strcmp(line, header_comment))
638
		return NULL;
643
	return NULL;
639
 
644
 
-
 
645
    for (i=0; i<4; i++) {
640
	if (fgets(line, sizeof(line)-2, file) == NULL)
646
	if (fgets(line, sizeof(line)-2, file) == NULL)
641
		return NULL;
647
	    return NULL;
-
 
648
	if (! strncmp(line, depth_comment, 12))
-
 
649
	    depth = atoi(line+12);
-
 
650
	if (! strncmp(line, width_comment, 12))
-
 
651
	    width = atoi(line+12);
642
	if (strcmp(line, header_comment))
652
	if (! strncmp(line, height_comment, 12))
-
 
653
	    height = atoi(line+12);
-
 
654
	if (! strncmp(line, cmapsize_comment, 14))
-
 
655
	    cmapsize = atoi(line+14);
-
 
656
    }
-
 
657
 
-
 
658
    img = newimage(width, height, depth);
-
 
659
    if (img == NULL)
643
		return NULL;
660
	return NULL;
644
 
661
 
645
	for (i=0; i<4; i++) {
662
    if (depth <= 8) {
646
		if (fgets(line, sizeof(line)-2, file) == NULL)
663
	if (fgets(line, sizeof(line)-2, file) == NULL)
647
			return NULL;
664
	    return NULL;
648
		if (! strncmp(line, depth_comment, 12))
-
 
649
			depth = atoi(line+12);
-
 
650
		if (! strncmp(line, width_comment, 12))
665
	if (strncmp(line, "rgb ", 4) != 0) {
651
			width = atoi(line+12);
666
	    delimage(img);
652
		if (! strncmp(line, height_comment, 12))
-
 
653
			height = atoi(line+12);
667
	    return NULL;
654
		if (! strncmp(line, cmapsize_comment, 14))
-
 
655
			cmapsize = atoi(line+14);
-
 
656
	}
668
	}
657
 
-
 
658
	img = newimage(width, height, depth);
-
 
659
	if (img == NULL)
-
 
660
		return NULL;
-
 
661
 
-
 
662
	if (depth <= 8) {
-
 
663
		if (fgets(line, sizeof(line)-2, file) == NULL)
-
 
664
			return NULL;
-
 
665
		if (strncmp(line, "rgb ", 4) != 0) {
-
 
666
			delimage(img);
-
 
667
			return NULL;
-
 
668
		}
-
 
669
		for (i=0; i<cmapsize; i++) {
669
	for (i=0; i<cmapsize; i++) {
670
			append(cmap, read_hex_long(file));
670
	    append(cmap, read_hex_long(file));
671
		}
-
 
672
		if (fgets(line, sizeof(line)-2, file) == NULL)
-
 
673
			return NULL;
-
 
674
 
-
 
675
		img->cmapsize = cmapsize;
-
 
676
		img->cmap = cmap;
-
 
677
	}
671
	}
678
 
-
 
679
	pixel32 = (rgb *) img->pixels;
-
 
680
	pixel8  = img->pixels;
-
 
681
	size    = (long) width * height;
-
 
682
 
-
 
683
	if (fgets(line, sizeof(line)-2, file) == NULL)
672
	if (fgets(line, sizeof(line)-2, file) == NULL)
684
		return NULL;
673
	    return NULL;
685
 
674
 
686
	if (depth <= 8) {
-
 
687
		for (i=0; i<size; i++)
675
	img->cmapsize = cmapsize;
688
			pixel8[i] = read_hex_byte(file);
-
 
689
	}
-
 
690
	else {
-
 
691
		for (i=0; i<size; i++)
676
	img->cmap = cmap;
692
			pixel32[i] = read_hex_long(file);
-
 
693
	}
677
    }
694
 
678
 
-
 
679
    pixel32 = (rgb *) img->pixels;
-
 
680
    pixel8  = img->pixels;
-
 
681
    size    = (long) width * height;
-
 
682
 
-
 
683
    if (fgets(line, sizeof(line)-2, file) == NULL)
-
 
684
	return NULL;
-
 
685
 
-
 
686
    if (depth <= 8) {
-
 
687
	for (i=0; i<size; i++)
-
 
688
	    pixel8[i] = read_hex_byte(file);
-
 
689
    }
-
 
690
    else {
-
 
691
	for (i=0; i<size; i++)
-
 
692
	    pixel32[i] = read_hex_long(file);
-
 
693
    }
-
 
694
 
695
	return img;
695
    return img;
696
}
696
}
697
 
697
 
698
static void save_header_image_file(FILE *file, char *name, image img)
698
static void save_header_image_file(FILE *file, char *name, image img)
699
{
699
{
700
	long i, size;
700
    long i, size;
701
	int width;
701
    int width;
702
	rgb * pixel32;
702
    rgb * pixel32;
703
	byte *pixel8;
703
    byte *pixel8;
704
 
704
 
705
	if (file == NULL)
705
    if (file == NULL)
706
		return;
706
	return;
707
	if (img == NULL)
707
    if (img == NULL)
708
		return;
708
	return;
709
 
709
 
710
	fprintf(file, header_comment);
710
    fprintf(file, header_comment);
711
	fprintf(file, depth_comment,  img->depth);
711
    fprintf(file, depth_comment,  img->depth);
712
	fprintf(file, width_comment,  img->width);
712
    fprintf(file, width_comment,  img->width);
713
	fprintf(file, height_comment, img->height);
713
    fprintf(file, height_comment, img->height);
714
	fprintf(file, cmapsize_comment, img->cmapsize);
714
    fprintf(file, cmapsize_comment, img->cmapsize);
715
 
715
 
716
	if (img->depth <= 8) {
716
    if (img->depth <= 8) {
717
		fprintf(file, "rgb %s_cmap [] = {\n", name);
717
	fprintf(file, "rgb %s_cmap [] = {\n", name);
718
		for (i=0; i<img->cmapsize; i++)
718
	for (i=0; i<img->cmapsize; i++)
719
			fprintf(file, "\t0x%-8.8lXUL,\n", img->cmap[i]);
719
	    fprintf(file, "\t0x%-8.8lXUL,\n", img->cmap[i]);
720
		fprintf(file, "};\n");
-
 
721
	}
-
 
722
 
-
 
723
	pixel32 = (rgb *) img->pixels;
-
 
724
	pixel8  = img->pixels;
-
 
725
	size    = (long) img->width * img->height;
-
 
726
	width   = img->width;
-
 
727
 
-
 
728
	if (img->depth <= 8) {
-
 
729
		fprintf(file, "byte %s_pixels [] = {", name);
-
 
730
		if (width > 12) width = 12;
-
 
731
		for (i=0; i<size; i++) {
-
 
732
			if ((i%width) == 0)
-
 
733
				fprintf(file, "\n  ");
-
 
734
			fprintf(file, "0x%-2.2X, ", pixel8[i]);
-
 
735
		}
-
 
736
		fprintf(file, "\n};\n");
-
 
737
	}
-
 
738
	else {
-
 
739
		fprintf(file, "rgb %s_pixels [] = {", name);
-
 
740
		if (width > 5) width = 5;
-
 
741
		for (i=0; i<size; i++) {
-
 
742
			if ((i%width) == 0)
-
 
743
				fprintf(file, "\n  ");
-
 
744
			fprintf(file, "0x%-8.8lXUL, ", pixel32[i]);
-
 
745
		}
-
 
746
		fprintf(file, "\n};\n");
-
 
747
	}
-
 
748
 
-
 
749
	fprintf(file, "imagedata %s_imagedata = {\n", name);
-
 
750
	fprintf(file, "\t%d,\t/* depth */\n",  img->depth);
-
 
751
	fprintf(file, "\t%d,\t/* width */\n",  img->width);
-
 
752
	fprintf(file, "\t%d,\t/* height */\n", img->height);
-
 
753
	fprintf(file, "\t%d,\t/* cmapsize */\n", img->cmapsize);
-
 
754
	if (img->depth <= 8) {
-
 
755
		fprintf(file, "\t%s_cmap,\n", name);
-
 
756
		fprintf(file, "\t%s_pixels\n", name);
-
 
757
	}
-
 
758
	else {
-
 
759
		fprintf(file, "\t(rgb *) 0\n");
-
 
760
		fprintf(file, "\t(byte *) %s_pixels\n", name);
-
 
761
	}
-
 
762
	fprintf(file, "};\n");
720
	fprintf(file, "};\n");
-
 
721
    }
-
 
722
 
-
 
723
    pixel32 = (rgb *) img->pixels;
-
 
724
    pixel8  = img->pixels;
-
 
725
    size    = (long) img->width * img->height;
-
 
726
    width   = img->width;
-
 
727
 
-
 
728
    if (img->depth <= 8) {
-
 
729
	fprintf(file, "byte %s_pixels [] = {", name);
-
 
730
	if (width > 12) width = 12;
-
 
731
	for (i=0; i<size; i++) {
-
 
732
	    if ((i%width) == 0)
-
 
733
		fprintf(file, "\n  ");
-
 
734
	    fprintf(file, "0x%-2.2X, ", pixel8[i]);
-
 
735
	}
-
 
736
	fprintf(file, "\n};\n");
-
 
737
    }
-
 
738
    else {
-
 
739
	fprintf(file, "rgb %s_pixels [] = {", name);
-
 
740
	if (width > 5) width = 5;
-
 
741
	for (i=0; i<size; i++) {
-
 
742
	    if ((i%width) == 0)
-
 
743
		fprintf(file, "\n  ");
-
 
744
	    fprintf(file, "0x%-8.8lXUL, ", pixel32[i]);
-
 
745
	}
-
 
746
	fprintf(file, "\n};\n");
-
 
747
    }
-
 
748
 
-
 
749
    fprintf(file, "imagedata %s_imagedata = {\n", name);
-
 
750
    fprintf(file, "\t%d,\t/* depth */\n",  img->depth);
-
 
751
    fprintf(file, "\t%d,\t/* width */\n",  img->width);
-
 
752
    fprintf(file, "\t%d,\t/* height */\n", img->height);
-
 
753
    fprintf(file, "\t%d,\t/* cmapsize */\n", img->cmapsize);
-
 
754
    if (img->depth <= 8) {
-
 
755
	fprintf(file, "\t%s_cmap,\n", name);
-
 
756
	fprintf(file, "\t%s_pixels\n", name);
-
 
757
    }
-
 
758
    else {
-
 
759
	fprintf(file, "\t(rgb *) 0\n");
-
 
760
	fprintf(file, "\t(byte *) %s_pixels\n", name);
-
 
761
    }
-
 
762
    fprintf(file, "};\n");
763
	fprintf(file, "image %s_image = & %s_imagedata;\n",
763
    fprintf(file, "image %s_image = & %s_imagedata;\n",
764
			name, name);
764
	    name, name);
765
	fprintf(file, "\n");
765
    fprintf(file, "\n");
766
}
766
}
767
 
767
 
768
static image load_header_image(const char *filename)
768
static image load_header_image(const char *filename)
769
{
769
{
770
	FILE *file;
770
    FILE *file;
771
	image img;
771
    image img;
772
 
772
 
773
	file = fopen(filename, "rt");
773
    file = fopen(filename, "rt");
774
	img = load_header_image_file(file);
774
    img = load_header_image_file(file);
775
	fclose(file);
775
    fclose(file);
776
	return img;
776
    return img;
777
}
777
}
778
 
778
 
779
static char * base_file_name(const char *filename)
779
static char * base_file_name(const char *filename)
780
{
780
{
781
	char *name = NULL;
781
    char *name = NULL;
782
	int i, start, end;
782
    int i, start, end;
783
 
783
 
784
	end = strlen(filename);
784
    end = strlen(filename);
785
	while (filename[end] != '.')
785
    while (filename[end] != '.')
786
		end--;
786
	end--;
787
	for (start=end; start > 0; start--) {
787
    for (start=end; start > 0; start--) {
788
		if ((filename[start] == '\\')
788
	if ((filename[start] == '\\')
789
		 || (filename[start] == '/')
789
	    || (filename[start] == '/')
790
		 || (filename[start] == ':')) {
790
	    || (filename[start] == ':')) {
791
			start ++;
791
	    start ++;
792
			break;
792
	    break;
793
		}
793
	}
794
	}
794
    }
795
	for (i=start; i < end; i++)
795
    for (i=start; i < end; i++)
796
		append(name, tolower(filename[i]));
796
	append(name, tolower(filename[i]));
797
	return name;
797
    return name;
798
}
798
}
799
 
799
 
800
static void save_header_image(image img, const char *filename)
800
static void save_header_image(image img, const char *filename)
801
{
801
{
802
	FILE *file;
802
    FILE *file;
803
	char *name;
803
    char *name;
804
 
804
 
805
	file = fopen(filename, "wt");
805
    file = fopen(filename, "wt");
806
	name = base_file_name(filename);
806
    name = base_file_name(filename);
807
	save_header_image_file(file, name, img);
807
    save_header_image_file(file, name, img);
808
	discard(name);
808
    discard(name);
809
	fclose(file);
809
    fclose(file);
810
}
810
}
811
 
811
 
812
/*
812
/*
813
 *  Top-level functions for loading and saving images:
813
 *  Top-level functions for loading and saving images:
814
 */
814
 */
815
image loadimage(const char *filename)
815
image loadimage(const char *filename)
816
{
816
{
817
	if (string_ends_with(filename, ".gif"))
817
    if (string_ends_with(filename, ".gif"))
818
		return load_gif(filename);
818
	return load_gif(filename);
819
	else if (string_ends_with(filename, ".h"))
819
    else if (string_ends_with(filename, ".h"))
820
		return load_header_image(filename);
820
	return load_header_image(filename);
821
	else if (string_ends_with(filename, ".img"))
821
    else if (string_ends_with(filename, ".img"))
822
		return load_header_image(filename);
822
	return load_header_image(filename);
823
	else
823
    else
824
		return NULL;
824
	return NULL;
825
}
825
}
826
 
826
 
827
void saveimage(image img, const char *filename)
827
void saveimage(image img, const char *filename)
828
{
828
{
829
	if (string_ends_with(filename, ".gif"))
829
    if (string_ends_with(filename, ".gif"))
830
		save_gif(img, filename);
830
	save_gif(img, filename);
831
	else if (string_ends_with(filename, ".h"))
831
    else if (string_ends_with(filename, ".h"))
832
		save_header_image(img, filename);
832
	save_header_image(img, filename);
833
	else if (string_ends_with(filename, ".img"))
833
    else if (string_ends_with(filename, ".img"))
834
		save_header_image(img, filename);
834
	save_header_image(img, filename);
835
}
835
}
836
#endif
836
#endif
837
 
837
 
838
/*
838
/*
839
 *  Changing an rgb's value:
839
 *  Changing an rgb's value:
840
 */
840
 */
841
 
841
 
842
rgb darker(rgb pixel)
842
rgb darker(rgb pixel)
843
{
843
{
844
	int r, g, b;
844
    int r, g, b;
845
 
845
 
846
	if (getalpha(pixel) > 0x7F)
846
    if (getalpha(pixel) > 0x7F)
847
		return Transparent;
847
	return Transparent;
848
 
848
 
849
	r = getred(pixel);
849
    r = getred(pixel);
850
	g = getgreen(pixel);
850
    g = getgreen(pixel);
851
	b = getblue(pixel);
851
    b = getblue(pixel);
852
 
852
 
853
	return rgb((r+1)*3/4,(g+1)*3/4,(b+1)*3/4);
853
    return rgb((r+1)*3/4,(g+1)*3/4,(b+1)*3/4);
854
}
854
}
855
 
855
 
856
rgb brighter(rgb pixel)
856
rgb brighter(rgb pixel)
857
{
857
{
858
	int r, g, b;
858
    int r, g, b;
859
 
859
 
860
	if (getalpha(pixel) > 0x7F)
860
    if (getalpha(pixel) > 0x7F)
861
		return Transparent;
861
	return Transparent;
862
 
862
 
863
	r = getred(pixel);
863
    r = getred(pixel);
864
	g = getgreen(pixel);
864
    g = getgreen(pixel);
865
	b = getblue(pixel);
865
    b = getblue(pixel);
866
 
866
 
867
	r = (r) * 4 / 3; if (r > 255) r = 255;
867
    r = (r) * 4 / 3; if (r > 255) r = 255;
868
	g = (g) * 4 / 3; if (g > 255) g = 255;
868
    g = (g) * 4 / 3; if (g > 255) g = 255;
869
	b = (b) * 4 / 3; if (b > 255) b = 255;
869
    b = (b) * 4 / 3; if (b > 255) b = 255;
870
	return rgb(r,g,b);
870
    return rgb(r,g,b);
871
}
871
}
872
 
872
 
873
static rgb monochrome(rgb pixel)
873
static rgb monochrome(rgb pixel)
874
{
874
{
875
	int min, max, g, b;
875
    int min, max, g, b;
876
 
876
 
877
	if (getalpha(pixel) > 0x7F)
877
    if (getalpha(pixel) > 0x7F)
878
		return Transparent;
878
	return Transparent;
879
 
879
 
880
	max = min = getred(pixel);
880
    max = min = getred(pixel);
881
	g = getgreen(pixel);
881
    g = getgreen(pixel);
882
	if      (g < min) min = g;
882
    if      (g < min) min = g;
883
	else if (g > max) max = g;
883
    else if (g > max) max = g;
884
	b = getblue(pixel);
884
    b = getblue(pixel);
885
	if      (b < min) min = b;
885
    if      (b < min) min = b;
886
	else if (b > max) max = b;
886
    else if (b > max) max = b;
887
 
887
 
888
	if (min > 0xE0) 	pixel = White;
888
    if (min > 0xE0)	pixel = White;
889
	else if (max < 0x10)	pixel = Black;
889
    else if (max < 0x10)	pixel = Black;
890
	else if (max < 0x60)	pixel = Black;
890
    else if (max < 0x60)	pixel = Black;
891
	else if (max < 0xD0)	pixel = Black;
891
    else if (max < 0xD0)	pixel = Black;
892
	else			pixel = White;
892
    else			pixel = White;
893
 
893
 
894
	return pixel;
894
    return pixel;
895
}
895
}
896
 
896
 
897
static rgb greyscale(rgb pixel)
897
static rgb greyscale(rgb pixel)
898
{
898
{
899
	int min, max, g, b;
899
    int min, max, g, b;
900
 
900
 
901
	if (getalpha(pixel) > 0x7F)
901
    if (getalpha(pixel) > 0x7F)
902
		return Transparent;
902
	return Transparent;
903
 
903
 
904
	max = min = getred(pixel);
904
    max = min = getred(pixel);
905
	g = getgreen(pixel);
905
    g = getgreen(pixel);
906
	if      (g < min) min = g;
906
    if      (g < min) min = g;
907
	else if (g > max) max = g;
907
    else if (g > max) max = g;
908
	b = getblue(pixel);
908
    b = getblue(pixel);
909
	if      (b < min) min = b;
909
    if      (b < min) min = b;
910
	else if (b > max) max = b;
910
    else if (b > max) max = b;
911
 
911
 
912
	if (min > 0xE0) 	pixel = White;
912
    if (min > 0xE0)	pixel = White;
913
	else if (max < 0x10)	pixel = Black;
913
    else if (max < 0x10)	pixel = Black;
914
	else if (max < 0x60)	pixel = DarkGrey;
914
    else if (max < 0x60)	pixel = DarkGrey;
915
	else if (max < 0xD0)	pixel = Grey;
915
    else if (max < 0xD0)	pixel = Grey;
916
	else			pixel = LightGrey;
916
    else			pixel = LightGrey;
917
 
917
 
918
	return pixel;
918
    return pixel;
919
}
919
}
920
 
920
 
921
/*
921
/*
922
 *  Determine pixel values from an image:
922
 *  Determine pixel values from an image:
923
 */
923
 */
924
 
924
 
925
PROTECTED
925
PROTECTED
926
rgb get_image_pixel(image img, int x, int y)
926
rgb get_image_pixel(image img, int x, int y)
927
{
927
{
928
	int value;
928
    int value;
929
	rgb pixel;
929
    rgb pixel;
930
 
930
 
931
	if ((x < 0) || (x >= img->width))	return Transparent;
931
    if ((x < 0) || (x >= img->width))	return Transparent;
932
	if ((y < 0) || (y >= img->height))	return Transparent;
932
    if ((y < 0) || (y >= img->height))	return Transparent;
933
 
933
 
934
	if (img->depth <= 8) {
934
    if (img->depth <= 8) {
935
		value = img->pixels[y*img->width + x];
935
	value = img->pixels[y*img->width + x];
936
		pixel = img->cmap[value];
936
	pixel = img->cmap[value];
937
	} else {
937
    } else {
938
		pixel = ((rgb *)(img->pixels))[y*img->width + x];
938
	pixel = ((rgb *)(img->pixels))[y*img->width + x];
939
	}
939
    }
940
 
940
 
941
	if (getalpha(pixel) > 0x7F) return Transparent;
941
    if (getalpha(pixel) > 0x7F) return Transparent;
942
	return (pixel & White);
942
    return (pixel & White);
943
}
943
}
944
 
944
 
945
PROTECTED
945
PROTECTED
946
rgb get_monochrome_pixel(image img, int x, int y)
946
rgb get_monochrome_pixel(image img, int x, int y)
947
{
947
{
948
	return monochrome(get_image_pixel(img, x, y));
948
    return monochrome(get_image_pixel(img, x, y));
949
}
949
}
950
 
950
 
951
PROTECTED
951
PROTECTED
952
rgb get_grey_pixel(image img, int x, int y)
952
rgb get_grey_pixel(image img, int x, int y)
953
{
953
{
954
	return greyscale(get_image_pixel(img, x, y));
954
    return greyscale(get_image_pixel(img, x, y));
955
}
955
}
956
 
956
 
957
/*
957
/*
958
 *  Return an image scaled to a new width and/or height.
958
 *  Return an image scaled to a new width and/or height.
959
 *  The source rectangle sr can be used to crop the source image.
959
 *  The source rectangle sr can be used to crop the source image.
Line 961... Line 961...
961
 *  it is no longer needed.
961
 *  it is no longer needed.
962
 */
962
 */
963
 
963
 
964
static void scale_8_bit_image(image dest, image src, rect dr, rect sr)
964
static void scale_8_bit_image(image dest, image src, rect dr, rect sr)
965
{
965
{
966
	int value;
966
    int value;
967
	long x, y;
967
    long x, y;
968
	long dx, dy, sx, sy;
968
    long dx, dy, sx, sy;
969
	long dw, dh, sw, sh;
969
    long dw, dh, sw, sh;
970
	byte * src_pixels = src->pixels;
970
    byte * src_pixels = src->pixels;
971
	byte * dest_pixels = dest->pixels;
971
    byte * dest_pixels = dest->pixels;
972
 
972
 
973
	dw = dest->width;
973
    dw = dest->width;
974
	dh = dest->height;
974
    dh = dest->height;
975
	sw = src->width;
975
    sw = src->width;
976
	sh = src->height;
976
    sh = src->height;
977
 
977
 
978
	for (y=0; y < dr.height; y++)
978
    for (y=0; y < dr.height; y++)
979
	  for (x=0; x < dr.width; x++) {
979
	for (x=0; x < dr.width; x++) {
980
		sy = sr.y + y * sr.height / dr.height;
980
	    sy = sr.y + y * sr.height / dr.height;
981
		sx = sr.x + x * sr.width / dr.width;
981
	    sx = sr.x + x * sr.width / dr.width;
982
		if ((sx >= 0) && (sx < sw) && (sy >= 0) && (sy < sh))
982
	    if ((sx >= 0) && (sx < sw) && (sy >= 0) && (sy < sh))
983
			value = src_pixels [sy * sw + sx];
983
		value = src_pixels [sy * sw + sx];
984
		else
984
	    else
985
			value = 0;
985
		value = 0;
986
		dy = dr.y + y;
986
	    dy = dr.y + y;
987
		dx = dr.x + x;
987
	    dx = dr.x + x;
988
		if ((dx >= 0) && (dx < dw) && (dy >= 0) && (dy < dh))
988
	    if ((dx >= 0) && (dx < dw) && (dy >= 0) && (dy < dh))
989
			dest_pixels [dy * dw + dx] = value;
989
		dest_pixels [dy * dw + dx] = value;
990
	  }
990
	}
991
}
991
}
992
 
992
 
993
static void scale_32_bit_image(image dest, image src, rect dr, rect sr)
993
static void scale_32_bit_image(image dest, image src, rect dr, rect sr)
994
{
994
{
995
	rgb value;
995
    rgb value;
996
	long x, y;
996
    long x, y;
997
	long dx, dy, sx, sy;
997
    long dx, dy, sx, sy;
998
	long dw, dh, sw, sh;
998
    long dw, dh, sw, sh;
999
	rgb * src_pixels = (rgb *) src->pixels;
999
    rgb * src_pixels = (rgb *) src->pixels;
1000
	rgb * dest_pixels = (rgb *) dest->pixels;
1000
    rgb * dest_pixels = (rgb *) dest->pixels;
1001
 
1001
 
1002
	dw = dest->width;
1002
    dw = dest->width;
1003
	dh = dest->height;
1003
    dh = dest->height;
1004
	sw = src->width;
1004
    sw = src->width;
1005
	sh = src->height;
1005
    sh = src->height;
1006
 
1006
 
1007
	for (y=0; y < dr.height; y++)
1007
    for (y=0; y < dr.height; y++)
1008
	  for (x=0; x < dr.width; x++) {
1008
	for (x=0; x < dr.width; x++) {
1009
		sy = sr.y + y * sr.height / dr.height;
1009
	    sy = sr.y + y * sr.height / dr.height;
1010
		sx = sr.x + x * sr.width / dr.width;
1010
	    sx = sr.x + x * sr.width / dr.width;
1011
		if ((sx >= 0) && (sx < sw) && (sy >= 0) && (sy < sh))
1011
	    if ((sx >= 0) && (sx < sw) && (sy >= 0) && (sy < sh))
1012
			value = src_pixels [sy * sw + sx];
1012
		value = src_pixels [sy * sw + sx];
1013
		else
1013
	    else
1014
			value = 0;
1014
		value = 0;
1015
		dy = dr.y + y;
1015
	    dy = dr.y + y;
1016
		dx = dr.x + x;
1016
	    dx = dr.x + x;
1017
		if ((dx >= 0) && (dx < dw) && (dy >= 0) && (dy < dh))
1017
	    if ((dx >= 0) && (dx < dw) && (dy >= 0) && (dy < dh))
1018
			dest_pixels [dy * dw + dx] = value;
1018
		dest_pixels [dy * dw + dx] = value;
1019
	  }
1019
	}
1020
}
1020
}
1021
 
1021
 
1022
image scaleimage(image src, rect dr, rect sr)
1022
image scaleimage(image src, rect dr, rect sr)
1023
{
1023
{
1024
	image dest;
1024
    image dest;
1025
 
1025
 
1026
	if (! src)
1026
    if (! src)
1027
		return NULL;
1027
	return NULL;
1028
 
1028
 
1029
	dest = newimage(dr.width, dr.height, src->depth);
1029
    dest = newimage(dr.width, dr.height, src->depth);
1030
	if (! dest)
1030
    if (! dest)
1031
		return NULL;
1031
	return NULL;
1032
 
1032
 
1033
	if (src->depth == 8) {
1033
    if (src->depth == 8) {
1034
		setpalette(dest, src->cmapsize, src->cmap);
1034
	setpalette(dest, src->cmapsize, src->cmap);
1035
		scale_8_bit_image(dest, src, dr, sr);
1035
	scale_8_bit_image(dest, src, dr, sr);
1036
	}
1036
    }
1037
	else if (src->depth == 32) {
1037
    else if (src->depth == 32) {
1038
		scale_32_bit_image(dest, src, dr, sr);
1038
	scale_32_bit_image(dest, src, dr, sr);
1039
	}
1039
    }
1040
	else {
1040
    else {
1041
		del(dest);
1041
	del(dest);
1042
		dest = NULL;
1042
	dest = NULL;
1043
	}
1043
    }
1044
 
1044
 
1045
	return dest;
1045
    return dest;
1046
}
1046
}
1047
 
1047
 
1048
/*
1048
/*
1049
 *  Functions for drawing an image:
1049
 *  Functions for drawing an image:
1050
 */
1050
 */
1051
 
1051
 
1052
static int get_mono_pixval(image src, image dest, int x, int y)
1052
static int get_mono_pixval(image src, image dest, int x, int y)
1053
{
1053
{
1054
	int i;
1054
    int i;
1055
	rgb pixel = get_monochrome_pixel(src, x, y);
1055
    rgb pixel = get_monochrome_pixel(src, x, y);
1056
 
1056
 
1057
	for (i=0; i < dest->cmapsize; i++)
1057
    for (i=0; i < dest->cmapsize; i++)
1058
		if (pixel == dest->cmap[i])
1058
	if (pixel == dest->cmap[i])
1059
			return i;
1059
	    return i;
1060
	return dest->cmapsize - 1;
1060
    return dest->cmapsize - 1;
1061
}
1061
}
1062
 
1062
 
1063
static int get_grey_pixval(image src, image dest, int x, int y)
1063
static int get_grey_pixval(image src, image dest, int x, int y)
1064
{
1064
{
1065
	int i;
1065
    int i;
1066
	rgb pixel = get_grey_pixel(src, x, y);
1066
    rgb pixel = get_grey_pixel(src, x, y);
1067
 
1067
 
1068
	for (i=0; i < dest->cmapsize; i++)
1068
    for (i=0; i < dest->cmapsize; i++)
1069
		if (pixel == dest->cmap[i])
1069
	if (pixel == dest->cmap[i])
1070
			return i;
1070
	    return i;
1071
	return dest->cmapsize - 1;
1071
    return dest->cmapsize - 1;
1072
}
1072
}
1073
 
1073
 
1074
void drawmonochrome(image src, rect dr, rect sr)
1074
void drawmonochrome(image src, rect dr, rect sr)
1075
{
1075
{
1076
	image dest;
1076
    image dest;
1077
	int x, y;
1077
    int x, y;
1078
	rgb cmap[3] = {Black, White, Transparent};
1078
    rgb cmap[3] = {Black, White, Transparent};
1079
 
1079
 
1080
	if (! src)
1080
    if (! src)
1081
		return;
1081
	return;
1082
 
1082
 
1083
	dest = newimage(src->width, src->height, 8);
1083
    dest = newimage(src->width, src->height, 8);
1084
	setpalette(dest, 3, cmap);
1084
    setpalette(dest, 3, cmap);
1085
 
1085
 
1086
	for (y=0; y < dest->height; y++)
1086
    for (y=0; y < dest->height; y++)
1087
	  for (x=0; x < dest->width; x++)
1087
	for (x=0; x < dest->width; x++)
1088
		dest->pixels[y * dest->width + x]
1088
	    dest->pixels[y * dest->width + x]
1089
			= get_mono_pixval(src, dest, x, y);
1089
		= get_mono_pixval(src, dest, x, y);
1090
	drawimage(dest, dr, sr);
1090
    drawimage(dest, dr, sr);
1091
	del(dest);
1091
    del(dest);
1092
}
1092
}
1093
 
1093
 
1094
void drawgreyscale(image src, rect dr, rect sr)
1094
void drawgreyscale(image src, rect dr, rect sr)
1095
{
1095
{
1096
	image dest;
1096
    image dest;
1097
	int x, y;
1097
    int x, y;
1098
	rgb cmap[6] = {Black, DarkGrey, Grey, LightGrey, White, Transparent};
1098
    rgb cmap[6] = {Black, DarkGrey, Grey, LightGrey, White, Transparent};
1099
 
1099
 
1100
	if (! src)
1100
    if (! src)
1101
		return;
1101
	return;
1102
 
1102
 
1103
	dest = newimage(src->width, src->height, 8);
1103
    dest = newimage(src->width, src->height, 8);
1104
	setpalette(dest, 6, cmap);
1104
    setpalette(dest, 6, cmap);
1105
 
1105
 
1106
	for (y=0; y < dest->height; y++)
1106
    for (y=0; y < dest->height; y++)
1107
	  for (x=0; x < dest->width; x++)
1107
	for (x=0; x < dest->width; x++)
1108
		dest->pixels[y * dest->width + x]
1108
	    dest->pixels[y * dest->width + x]
1109
			= get_grey_pixval(src, dest, x, y);
1109
		= get_grey_pixval(src, dest, x, y);
1110
	drawimage(dest, dr, sr);
1110
    drawimage(dest, dr, sr);
1111
	del(dest);
1111
    del(dest);
1112
}
1112
}
1113
 
1113
 
1114
void drawdarker(image src, rect dr, rect sr)
1114
void drawdarker(image src, rect dr, rect sr)
1115
{
1115
{
1116
	image dest = NULL;
1116
    image dest = NULL;
1117
	int i, x, y;
1117
    int i, x, y;
1118
	rgb *newcmap = NULL, *oldcmap = NULL;
1118
    rgb *newcmap = NULL, *oldcmap = NULL;
1119
	rgb *pixels;
1119
    rgb *pixels;
1120
 
1120
 
1121
	if (! src)
1121
    if (! src)
1122
		return;
1122
	return;
1123
 
1123
 
1124
	if (src->depth == 8) {
1124
    if (src->depth == 8) {
1125
		newcmap = array(src->cmapsize, rgb);
1125
	newcmap = array(src->cmapsize, rgb);
1126
		for (i=0; i < src->cmapsize; i++)
1126
	for (i=0; i < src->cmapsize; i++)
1127
			newcmap[i] = darker(src->cmap[i]);
1127
	    newcmap[i] = darker(src->cmap[i]);
1128
		oldcmap = src->cmap;
1128
	oldcmap = src->cmap;
1129
		src->cmap = newcmap;
1129
	src->cmap = newcmap;
1130
		dest = src;
1130
	dest = src;
1131
	}
1131
    }
1132
	else if (src->depth == 32) {
1132
    else if (src->depth == 32) {
1133
		dest = newimage(src->width, src->height, src->depth);
1133
	dest = newimage(src->width, src->height, src->depth);
1134
		if (dest) {
1134
	if (dest) {
1135
		  pixels = (rgb *) dest->pixels;
1135
	    pixels = (rgb *) dest->pixels;
1136
		  for (y=0; y < dest->height; y++)
1136
	    for (y=0; y < dest->height; y++)
1137
		    for (x=0; x < dest->width; x++)
1137
		for (x=0; x < dest->width; x++)
1138
			pixels[y * dest->width + x]
1138
		    pixels[y * dest->width + x]
1139
				= darker(get_image_pixel(src, x, y));
1139
			= darker(get_image_pixel(src, x, y));
1140
		} else {
1140
	} else {
1141
			dest = src;
1141
	    dest = src;
1142
		}
-
 
1143
	}
1142
	}
-
 
1143
    }
1144
	drawimage(dest, dr, sr);
1144
    drawimage(dest, dr, sr);
1145
	if (dest != src)
1145
    if (dest != src)
1146
		del(dest);
1146
	del(dest);
1147
	if (src->cmap == newcmap)
1147
    if (src->cmap == newcmap)
1148
		src->cmap = oldcmap;
1148
	src->cmap = oldcmap;
1149
	discard(newcmap);
1149
    discard(newcmap);
1150
}
1150
}
1151
 
1151
 
1152
void drawbrighter(image src, rect dr, rect sr)
1152
void drawbrighter(image src, rect dr, rect sr)
1153
{
1153
{
1154
	image dest = NULL;
1154
    image dest = NULL;
1155
	int i, x, y;
1155
    int i, x, y;
1156
	rgb *newcmap = NULL, *oldcmap = NULL;
1156
    rgb *newcmap = NULL, *oldcmap = NULL;
1157
	rgb *pixels;
1157
    rgb *pixels;
1158
 
1158
 
1159
	if (! src)
1159
    if (! src)
1160
		return;
1160
	return;
1161
 
1161
 
1162
	if (src->depth == 8) {
1162
    if (src->depth == 8) {
1163
		newcmap = array(src->cmapsize, rgb);
1163
	newcmap = array(src->cmapsize, rgb);
1164
		for (i=0; i < src->cmapsize; i++)
1164
	for (i=0; i < src->cmapsize; i++)
1165
			newcmap[i] = brighter(src->cmap[i]);
1165
	    newcmap[i] = brighter(src->cmap[i]);
1166
		oldcmap = src->cmap;
1166
	oldcmap = src->cmap;
1167
		src->cmap = newcmap;
1167
	src->cmap = newcmap;
1168
		dest = src;
1168
	dest = src;
1169
	}
1169
    }
1170
	else if (src->depth == 32) {
1170
    else if (src->depth == 32) {
1171
		dest = newimage(src->width, src->height, src->depth);
1171
	dest = newimage(src->width, src->height, src->depth);
1172
		if (dest) {
1172
	if (dest) {
1173
		  pixels = (rgb *) dest->pixels;
1173
	    pixels = (rgb *) dest->pixels;
1174
		  for (y=0; y < dest->height; y++)
1174
	    for (y=0; y < dest->height; y++)
1175
		    for (x=0; x < dest->width; x++)
1175
		for (x=0; x < dest->width; x++)
1176
			pixels[y * dest->width + x]
1176
		    pixels[y * dest->width + x]
1177
				= brighter(get_image_pixel(src,x,y));
1177
			= brighter(get_image_pixel(src,x,y));
1178
		} else {
1178
	} else {
1179
			dest = src;
1179
	    dest = src;
1180
		}
-
 
1181
	}
1180
	}
-
 
1181
    }
1182
	drawimage(dest, dr, sr);
1182
    drawimage(dest, dr, sr);
1183
	if (dest != src)
1183
    if (dest != src)
1184
		del(dest);
1184
	del(dest);
1185
	if (src->cmap == newcmap)
1185
    if (src->cmap == newcmap)
1186
		src->cmap = oldcmap;
1186
	src->cmap = oldcmap;
1187
	discard(newcmap);
1187
    discard(newcmap);
1188
}
1188
}