1 /* libwmf ("ipa/ipa/bmp.h"): library for wmf conversion
2    Copyright (C) 2000 - various; see CREDITS, ChangeLog, and sources
3 
4    The libwmf Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8 
9    The libwmf Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with the libwmf Library; see the file COPYING.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18 
19 
20 #ifndef HAVE_GD
21 /* png stuff below adapted from stuff sent to me [fjf] by Lennard D. Rosenthal;
22  * probably used in ImageMagick and may not be covered, therefore, by the LGPL - (fjf)
23  *
24  * utility routine for saving a pixbuf to a png file.
25  * This was adapted from Iain Holmes' code in gnome-iconedit, and probably
26  * should be in a utility library, possibly in gdk-pixbuf itself.
27  */
ldr_bmp_png(wmfAPI * API,wmfBMP_Draw_t * bmp_draw,FILE * out)28 static void ldr_bmp_png (wmfAPI* API,wmfBMP_Draw_t* bmp_draw,FILE* out)
29 {
30 #ifdef HAVE_LIBPNG
31 	wmfRGB rgb;
32 
33 	png_structp png_ptr = 0;
34 	png_infop info_ptr = 0;
35 	png_text text[2];
36 
37 	int i;
38 	int j;
39 	int x;
40 	int y;
41 	int width  = (int) bmp_draw->crop.w;
42 	int height = (int) bmp_draw->crop.h;
43 	int depth = 8; /* ?? bit depth (bits per sample) */
44 	int opacity;
45 
46 	char* ptr = 0;
47 	char* buffer = (char*) wmf_malloc (API,4 * width);
48 
49 	if (ERR (API))
50 	{	WMF_DEBUG (API,"bailing...");
51 		return;
52 	}
53 
54 	png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0);
55 	if (png_ptr == 0)
56 	{	WMF_DEBUG (API,"Failed to write bitmap as PNG! (png_create_write_struct failed)");
57 		wmf_free (API,buffer);
58 		return;
59 	}
60 
61 	info_ptr = png_create_info_struct (png_ptr);
62 	if (info_ptr == 0)
63 	{	WMF_DEBUG (API,"Failed to write bitmap as PNG! (png_create_info_struct failed)");
64 		png_destroy_write_struct (&png_ptr,0);
65 		wmf_free (API,buffer);
66 		return;
67 	}
68 
69 	if (setjmp (png_ptr->jmpbuf))
70 	{	WMF_DEBUG (API,"Failed to write bitmap as PNG! (setjmp failed)");
71 		png_destroy_write_struct (&png_ptr,&info_ptr);
72 		wmf_free (API,buffer);
73 		return;
74 	}
75 
76 	png_init_io (png_ptr,out);
77 
78 	png_set_IHDR (png_ptr,info_ptr,width,height,depth,
79 		      PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
80 
81 	/* Some text to go with the png image */
82 	text[0].key = "Title";
83 	text[0].text = "A converted bitmap";
84 	text[0].compression = PNG_TEXT_COMPRESSION_NONE;
85 	text[1].key = "Software";
86 	text[1].text = "libwmf2";
87 	text[1].compression = PNG_TEXT_COMPRESSION_NONE;
88 
89 	png_set_text (png_ptr,info_ptr,text,2);
90 
91 	/* Write header data
92 	 */
93 	png_write_info (png_ptr,info_ptr);
94 
95 	/* pump the raster data into libpng, one scan line at a time
96 	 */
97 	x = (int) bmp_draw->crop.x;
98 	y = (int) bmp_draw->crop.y;
99 
100 	for (j = 0; j < height; j++)
101 	{	ptr = buffer;
102 		for (i = 0; i < width; i++)
103 		{	opacity = wmf_ipa_bmp_color (API,&(bmp_draw->bmp),&rgb,x+i,y+j);
104 			*ptr++ = (char) rgb.r;
105 			*ptr++ = (char) rgb.g;
106 			*ptr++ = (char) rgb.b;
107 			*ptr++ = (char) ((unsigned char) (opacity & 0xff));
108 		}
109 		png_write_row (png_ptr,(png_bytep) buffer);
110 	}
111 
112 	png_write_end (png_ptr,info_ptr);
113 	png_destroy_write_struct (&png_ptr,&info_ptr);
114 
115 	wmf_free (API,buffer);
116 #else /* HAVE_LIBPNG */
117 	WMF_ERROR (API,"Glitch? No PNG support!");
118 	API->err = wmf_E_Glitch;
119 #endif /* HAVE_LIBPNG */
120 	return;
121 }
122 #endif /* ! HAVE_GD */
123 #ifdef HAVE_GD
ipa_b64_sink(void * context,const char * buffer,int length)124 static int ipa_b64_sink (void* context,const char* buffer,int length)
125 {	ipa_b64_t* b64 = (ipa_b64_t*) context;
126 
127 	int i = 0;
128 
129 	while (i < length)
130 	{	// coverity[overrun-local : FALSE] - coverity seems to fail to see that ipa_b64_flush resets length to 0
131 		b64->buffer[b64->length] = buffer[i];
132 		i++;
133 		b64->length++;
134 		if (b64->length == IPA_B64_BUFLEN) ipa_b64_flush (context);
135 	}
136 
137 	return (i);
138 }
139 #endif /* HAVE_GD */
140 #ifdef HAVE_GD
ipa_b64_flush(void * context)141 static void ipa_b64_flush (void* context)
142 {	ipa_b64_t* b64 = (ipa_b64_t*) context;
143 
144 	static char B64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
145 
146 	char buffer[IPA_B64_LEQUIV];
147 
148 	unsigned long ulc1;
149 	unsigned long ulc2;
150 	unsigned long ulc3;
151 	unsigned long ulc;
152 
153 	int triplets = (b64->length + 2) / 3;
154 	int triplen;
155 	int i;
156 
157 	char* ptr = b64->buffer;
158 	char* btr = buffer;
159 
160 	if (b64->length == 0) return;
161 
162 	triplen = triplets * 3;
163 	for (i = b64->length; i < triplen; i++) b64->buffer[i] = 0;
164 
165 	(*btr) = '\n';
166 	btr++;
167 
168 	for (i = 0; i < triplets; i++)
169 	{	ulc1 = (unsigned long) ((unsigned char) (*ptr));
170 		ptr++;
171 		ulc2 = (unsigned long) ((unsigned char) (*ptr));
172 		ptr++;
173 		ulc3 = (unsigned long) ((unsigned char) (*ptr));
174 		ptr++;
175 
176 		ulc = (ulc1 << 16) | (ulc2 << 8) | ulc3;
177 
178 		ulc1 = (ulc & (0x3f << 18)) >> 18;
179 		ulc2 = (ulc & (0x3f << 12)) >> 12;
180 		ulc3 = (ulc & (0x3f <<  6)) >>  6;
181 
182 		ulc &= 0x3f;
183 
184 		(*btr) = B64[ulc1];
185 		btr++;
186 		(*btr) = B64[ulc2];
187 		btr++;
188 		(*btr) = B64[ulc3];
189 		btr++;
190 		(*btr) = B64[ulc ];
191 		btr++;
192 	}
193 
194 	if ((triplen - b64->length) > 1) (*(btr-2)) = '=';
195 	if ((triplen - b64->length) > 0) (*(btr-1)) = '=';
196 
197 	(*btr) = '\0';
198 
199 	wmf_stream_printf (b64->API,b64->out,buffer);
200 
201 	b64->length = 0;
202 }
203 #endif /* HAVE_GD */
204 
wmf_ipa_bmp_b64(wmfAPI * API,wmfBMP_Draw_t * bmp_draw,wmfStream * out)205 void wmf_ipa_bmp_b64 (wmfAPI* API,wmfBMP_Draw_t* bmp_draw,wmfStream* out)
206 {
207 #ifdef HAVE_GD
208 	gdImage* image = 0;
209 
210 	gdSink sink;
211 
212 	ipa_b64_t b64;
213 
214 	WMF_DEBUG (API,"~~~~~~~~wmf_ipa_bmp_b64");
215 #ifndef HAVE_LIBPNG
216 	WMF_DEBUG (API,"No support for PNG, sorry!");
217 	API->err = wmf_E_DeviceError;
218 	return;
219 #endif /* HAVE_LIBPNG */
220 	image = ipa_bmp_gd (API,bmp_draw);
221 
222 	if (image == 0) return;
223 
224 	b64.API = API;
225 	b64.out = out;
226 
227 	b64.length = 0;
228 
229 	sink.context = (void*) (&b64);
230 	sink.sink = ipa_b64_sink;
231 
232 	gdImagePngToSink (image,&sink);
233 	gdImageDestroy (image);
234 
235 	ipa_b64_flush (sink.context);
236 #endif /* HAVE_GD */
237 }
238 
wmf_ipa_bmp_png(wmfAPI * API,wmfBMP_Draw_t * bmp_draw,char * name)239 void wmf_ipa_bmp_png (wmfAPI* API,wmfBMP_Draw_t* bmp_draw,char* name)
240 {	FILE* file = 0;
241 #ifdef HAVE_GD
242 	gdImage* image = 0;
243 #endif /* HAVE_GD */
244 	WMF_DEBUG (API,"~~~~~~~~wmf_ipa_bmp_png");
245 #ifndef HAVE_LIBPNG
246 	WMF_DEBUG (API,"No support for PNG, sorry!");
247 	API->err = wmf_E_DeviceError;
248 	return;
249 #endif /* HAVE_LIBPNG */
250 	file = fopen (name,"wb");
251 
252 	if (file == 0)
253 	{	WMF_ERROR (API,"Failed to open file to write GD image!");
254 		return;
255 	}
256 #ifdef HAVE_GD
257 	image = ipa_bmp_gd (API,bmp_draw);
258 
259 	if (image)
260 	{	gdImagePng (image,file);
261 		gdImageDestroy (image);
262 	}
263 #else /* HAVE_GD */
264 	ldr_bmp_png (API,bmp_draw,file);
265 #endif /* HAVE_GD */
266 
267 	fclose (file);
268 }
269 
wmf_ipa_bmp_jpg(wmfAPI * API,wmfBMP_Draw_t * bmp_draw,char * name)270 void wmf_ipa_bmp_jpg (wmfAPI* API,wmfBMP_Draw_t* bmp_draw,char* name)
271 {
272 #ifdef HAVE_GD
273 	FILE* file = 0;
274 
275 	gdImage* image = 0;
276 
277 	WMF_DEBUG (API,"~~~~~~~~wmf_ipa_bmp_jpg");
278 #ifndef HAVE_LIBJPEG
279 	WMF_DEBUG (API,"No support for JPEG, sorry!");
280 	API->err = wmf_E_DeviceError;
281 	return;
282 #endif /* HAVE_LIBJPEG */
283 	file = fopen (name,"wb");
284 
285 	if (file == 0)
286 	{	WMF_ERROR (API,"Failed to open file to write GD image!");
287 		return;
288 	}
289 
290 	image = ipa_bmp_gd (API,bmp_draw);
291 
292 	if (image)
293 	{	gdImageJpeg (image,file,-1); /* Default quality. */
294 		gdImageDestroy (image);
295 	}
296 
297 	fclose (file);
298 #endif /* HAVE_GD */
299 }
300 #ifdef HAVE_GD
ipa_bmp_gd(wmfAPI * API,wmfBMP_Draw_t * bmp_draw)301 static gdImage* ipa_bmp_gd (wmfAPI* API,wmfBMP_Draw_t* bmp_draw)
302 {	wmfRGB rgb;
303 
304 	int color;
305 
306 	unsigned int ui_x;
307 	unsigned int ui_y;
308 
309 	unsigned int i;
310 	unsigned int j;
311 
312 	gdImage* image = 0;
313 
314 	WMF_DEBUG (API,"~~~~~~~~ipa_bmp_gd");
315 
316 	if (bmp_draw->bmp.data == 0)
317 	{	WMF_ERROR (API,"Glitch! Attempt to write non-existant bitmap.");
318 		API->err = wmf_E_Glitch;
319 		return (0);
320 	}
321 
322 	image = gdImageCreateTrueColor ((int) bmp_draw->crop.w,(int) bmp_draw->crop.h);
323 
324 	if (image == 0)
325 	{	WMF_ERROR (API,"Failed to create GD image!");
326 		API->err = wmf_E_DeviceError;
327 		return (0);
328 	}
329 
330 	ui_x = (unsigned int) bmp_draw->crop.x;
331 	ui_y = (unsigned int) bmp_draw->crop.y;
332 
333 	for (j = 0; j < (unsigned int) bmp_draw->crop.h; j++)
334 	{	for (i = 0; i < (unsigned int) bmp_draw->crop.w; i++)
335 		{	wmf_ipa_bmp_color (API,&(bmp_draw->bmp),&rgb,ui_x+i,ui_y+j);
336 
337 			color = gdImageColorResolve (image,rgb.r,rgb.g,rgb.b);
338 
339 			gdImageSetPixel (image,(int) i,(int) (bmp_draw->crop.h-1-j),color);
340 		}
341 	}
342 
343 	return (image);
344 }
345 #endif /* HAVE_GD */
wmf_ipa_bmp_eps(wmfAPI * API,wmfBMP_Draw_t * bmp_draw,char * name)346 void wmf_ipa_bmp_eps (wmfAPI* API,wmfBMP_Draw_t* bmp_draw,char* name)
347 {	wmfRGB rgb;
348 
349 	unsigned int i;
350 	unsigned int j;
351 	unsigned int k;
352 
353 	unsigned int ui_x;
354 	unsigned int ui_y;
355 
356 	unsigned int width;
357 	unsigned int height;
358 
359 	static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
360 
361 	char buffer[80];
362 
363 	FILE* file = 0;
364 
365 	WMF_DEBUG (API,"~~~~~~~~wmf_ipa_bmp_eps");
366 
367 	if (bmp_draw->bmp.data == 0)
368 	{	WMF_ERROR (API,"Glitch! Attempt to write non-existant bitmap.");
369 		API->err = wmf_E_Glitch;
370 		return;
371 	}
372 
373 	file = fopen (name,"w");
374 
375 	if (file == 0)
376 	{	WMF_ERROR (API,"Failed to open file to write EPS image!");
377 		API->err = wmf_E_BadFile;
378 		return;
379 	}
380 
381 	ui_x = (unsigned int) bmp_draw->crop.x;
382 	ui_y = (unsigned int) bmp_draw->crop.y;
383 
384 	width  = (unsigned int) bmp_draw->crop.w;
385 	height = (unsigned int) bmp_draw->crop.h;
386 
387 	/* Output as an embedded eps */
388 
389 	fputs ("%!PS-Adobe-2.0 EPSF-2.0\n",file);
390 	fputs ("%%BoundingBox: ",file);
391 	fprintf (file," 0 0 %u %u\n",width,height);
392 
393 	fprintf (file," 0 %d translate\n",1);
394 	fprintf (file," %u %u scale\n",width,height);
395 
396 	/* I'm going to assume it's a color image - TODO: monochrome */
397 
398 	fprintf (file," /picstr %u 3 mul string def\n",width);
399 
400 	fprintf (file," %u %u 8\n",width,height);
401 
402 	fprintf (file," [ %u 0 0 %u 0 0 ]\n",width,height);
403 
404 	fputs (" { currentfile picstr readhexstring pop } false 3\n",file);
405 
406 	fputs (" colorimage\n",file);
407 
408 	for (j = 0; j < height; j++)
409 	{	k = 0;
410 		for (i = 0; i < width; i++)
411 		{	if (k == 78)
412 			{	buffer[k++] = '\n';
413 				buffer[k] = 0;
414 				fputs (buffer,file);
415 				k = 0;
416 			}
417 
418 			wmf_ipa_bmp_color (API,&(bmp_draw->bmp),&rgb,ui_x+i,ui_y+j);
419 
420 			buffer[k++] = hex[(rgb.r & 0xf0) >> 4];
421 			buffer[k++] = hex[ rgb.r & 0x0f      ];
422 			buffer[k++] = hex[(rgb.g & 0xf0) >> 4];
423 			buffer[k++] = hex[ rgb.g & 0x0f      ];
424 			buffer[k++] = hex[(rgb.b & 0xf0) >> 4];
425 			buffer[k++] = hex[ rgb.b & 0x0f      ];
426 		}
427 		if (k > 0)
428 		{	buffer[k++] = '\n';
429 			buffer[k] = 0;
430 			fputs (buffer,file);
431 		}
432 	}
433 
434 	fputs ("showpage\n",file);
435 
436 	fclose (file);
437 
438 	return;
439 }
440 
wmf_ipa_bmp_read(wmfAPI * API,wmfBMP_Read_t * bmp_read)441 void wmf_ipa_bmp_read (wmfAPI* API,wmfBMP_Read_t* bmp_read)
442 {	wmfBMP* bmp = 0;
443 
444 	BMPSource source;
445 
446 	BMPData* data;
447 
448 	WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_read");
449 
450 	bmp = &(bmp_read->bmp);
451 
452 	bmp->data = 0;
453 
454 	data = (BMPData*) wmf_malloc (API,sizeof (BMPData));
455 
456 	if (ERR (API))
457 	{	if (API->flags & WMF_OPT_IGNORE_NONFATAL)
458 		{	API->err = wmf_E_None;
459 			bmp->data = 0;
460 		}
461 		WMF_DEBUG (API,"bailing...");
462 		return;
463 	}
464 
465 	data->NColors = 0;
466 	data->rgb = 0;
467 	data->image = 0;
468 
469 	bmp->width  = bmp_read->width;
470 	bmp->height = bmp_read->height;
471 
472 	bmp->data = (void*) data;
473 
474 	source.begin = bmp_read->buffer;
475 	source.end   = bmp_read->buffer + bmp_read->length;
476 	source.ptr   = bmp_read->buffer;
477 
478 	ReadBMPImage (API,bmp,&source);
479 
480 	if (ERR (API))
481 	{	if (API->flags & WMF_OPT_IGNORE_NONFATAL)
482 		{	API->err = wmf_E_None;
483 			bmp->data = 0;
484 		}
485 	}
486 }
487 
wmf_ipa_bmp_free(wmfAPI * API,wmfBMP * bmp)488 void wmf_ipa_bmp_free (wmfAPI* API,wmfBMP* bmp)
489 {	BMPData* data;
490 
491 	WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_free");
492 
493 	if (bmp->data == 0) return;
494 
495 	data = (BMPData*) bmp->data;
496 
497 	if (data->rgb)   wmf_free (API,(void*) data->rgb  );
498 	if (data->image) wmf_free (API,(void*) data->image);
499 
500 	wmf_free (API,bmp->data);
501 
502 	bmp->data = 0;
503 }
504 
wmf_ipa_bmp_copy(wmfAPI * API,wmfBMP * bmp,unsigned int width,unsigned int height)505 wmfBMP wmf_ipa_bmp_copy (wmfAPI* API,wmfBMP* bmp,unsigned int width,unsigned int height)
506 {	wmfBMP copy;
507 
508 	wmfRGB rgb;
509 
510 	BMPData* copy_data = 0;
511 	BMPData* data = 0;
512 
513 	float x;
514 	float y;
515 
516 	unsigned int i;
517 	unsigned int j;
518 
519 	int opacity;
520 
521 	size_t size;
522 
523 	WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_copy");
524 
525 	copy.width  = width;
526 	copy.height = height;
527 
528 	copy.data = 0;
529 
530 	if (bmp->data == 0) return (copy);
531 
532 	data = (BMPData*) bmp->data;
533 
534 	copy.data = wmf_malloc (API,sizeof (BMPData));
535 
536 	if (ERR (API))
537 	{	WMF_DEBUG (API,"bailing...");
538 		return (copy);
539 	}
540 
541 	copy_data = (BMPData*) copy.data;
542 
543 	if (data->rgb)
544 	{	copy_data->NColors = data->NColors;
545 		copy_data->rgb = (wmfRGB*) wmf_malloc (API,data->NColors * sizeof (wmfRGB));
546 
547 		if (ERR (API))
548 		{	WMF_DEBUG (API,"bailing...");
549 			wmf_free (API,copy.data);
550 			copy.data = 0;
551 			return (copy);
552 		}
553 	}
554 	else
555 	{	copy_data->NColors = 0;
556 		copy_data->rgb = 0;
557 	}
558 
559 	copy_data->bits_per_pixel = data->bits_per_pixel;
560 
561 	copy_data->bytes_per_line = 4 * ((width * copy_data->bits_per_pixel + 31) / 32);
562 
563 	size = height * copy_data->bytes_per_line * sizeof (unsigned char);
564 
565 	copy_data->image = (unsigned char*) wmf_malloc (API,size);
566 
567 	if (ERR (API))
568 	{	WMF_DEBUG (API,"bailing...");
569 		if (copy_data->rgb) wmf_free (API,copy_data->rgb);
570 		wmf_free (API,copy.data);
571 		copy.data = 0;
572 		return (copy);
573 	}
574 
575 	copy_data->masked = data->masked;
576 	copy_data->flipped = data->flipped;
577 
578 	/* Data structure is complete, now to copy the image... */
579 
580 	for (j = 0; j < height; j++)
581 	{	y = (float) ((double) j * (double) bmp->height / (double) height);
582 		for (i = 0; i < width; i++)
583 		{	x = (float) ((double) i * (double) bmp->width / (double) width);
584 
585 			opacity = wmf_ipa_bmp_interpolate (API,bmp,&rgb,x,y);
586 
587 			if (opacity < 0) break; /* Shouldn't occur, I think */
588 
589 			wmf_ipa_bmp_setcolor (API,&copy,&rgb,(unsigned char) opacity,i,j);
590 		}
591 	}
592 
593 	return (copy);
594 }
595 
wmf_ipa_bmp_color(wmfAPI * API,wmfBMP * bmp,wmfRGB * rgb,unsigned int x,unsigned int y)596 int wmf_ipa_bmp_color (wmfAPI* API,wmfBMP* bmp,wmfRGB* rgb,unsigned int x,unsigned int y)
597 {	int status = -1; /* error value */
598 
599 /*	WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_color"); */
600 
601 	rgb->r = 0;
602 	rgb->g = 0;
603 	rgb->b = 0;
604 
605 	if (bmp->data && x < bmp->width && y < bmp->height)
606 	{	status = ExtractColor (API,bmp,rgb,x,y);
607 	}
608 	else if ((API->flags & WMF_OPT_IGNORE_NONFATAL) == 0)
609 	{	WMF_ERROR (API,"Point outside bitmap");
610 		API->err = wmf_E_Glitch;
611 	}
612 
613 	return (status);
614 }
615 
wmf_ipa_bmp_interpolate(wmfAPI * API,wmfBMP * bmp,wmfRGB * rgb,float x,float y)616 int wmf_ipa_bmp_interpolate (wmfAPI* API,wmfBMP* bmp,wmfRGB* rgb,float x,float y)
617 {	int status = -1; /* error value */
618 
619 	unsigned int i1;
620 	unsigned int i2;
621 	unsigned int j1;
622 	unsigned int j2;
623 
624 	unsigned char o_11;
625 	unsigned char o_12;
626 	unsigned char o_21;
627 	unsigned char o_22;
628 
629 	float f_11;
630 	float f_12;
631 	float f_21;
632 	float f_22;
633 
634 	wmfRGB rgb_11;
635 	wmfRGB rgb_12;
636 	wmfRGB rgb_21;
637 	wmfRGB rgb_22;
638 
639 /*	WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_interpolate"); */
640 
641 	i1 = (unsigned int) floor (x);
642 	i2 = (unsigned int) ceil (x);
643 	j1 = (unsigned int) floor (y);
644 	j2 = (unsigned int) ceil (y);
645 
646 	if (i1 >= (unsigned int)(bmp->width - 2))
647 	{	i1 = bmp->width - 2;
648 		i2 = bmp->width - 1;
649 	}
650 
651 	if (j1 >= (unsigned int)(bmp->height - 2))
652 	{	j1 = bmp->height - 2;
653 		j2 = bmp->height - 1;
654 	}
655 
656 	if ((i1 == i2) && (j1 == j2)) return (wmf_ipa_bmp_color (API,bmp,rgb,i1,j1));
657 
658 	i2 = i1 + 1;
659 	j2 = j1 + 1;
660 
661 	rgb->r = 0;
662 	rgb->g = 0;
663 	rgb->b = 0;
664 
665 	status = wmf_ipa_bmp_color (API,bmp,&rgb_11,i1,j1);
666 	if (status < 0) return (status);
667 	o_11 = (unsigned char) status;
668 
669 	status = wmf_ipa_bmp_color (API,bmp,&rgb_12,i2,j1);
670 	if (status < 0) return (status);
671 	o_12 = (unsigned char) status;
672 
673 	status = wmf_ipa_bmp_color (API,bmp,&rgb_21,i1,j2);
674 	if (status < 0) return (status);
675 	o_21 = (unsigned char) status;
676 
677 	status = wmf_ipa_bmp_color (API,bmp,&rgb_22,i2,j2);
678 	if (status < 0) return (status);
679 	o_22 = (unsigned char) status;
680 
681 	x -= (float) i1;
682 	y -= (float) j1;
683 
684 	f_11 = (1 - x) * (1 - y);
685 	f_12 = x * (1 - y);
686 	f_22 = x * y;
687 	f_21 = (1 - x) * y;
688 
689 	status = (int) (rgb_11.r * f_11 + rgb_21.r * f_21 + rgb_22.r * f_22 + rgb_12.r * f_12);
690 	rgb->r = (unsigned char) ((status < 0) ? 0 : ((status > 255) ? 255 : status));
691 
692 	status = (int) (rgb_11.g * f_11 + rgb_21.g * f_21 + rgb_22.g * f_22 + rgb_12.g * f_12);
693 	rgb->g = (unsigned char) ((status < 0) ? 0 : ((status > 255) ? 255 : status));
694 
695 	status = (int) (rgb_11.b * f_11 + rgb_21.b * f_21 + rgb_22.b * f_22 + rgb_12.b * f_12);
696 	rgb->b = (unsigned char) ((status < 0) ? 0 : ((status > 255) ? 255 : status));
697 
698 	status = (int) (o_11 * f_11 + o_21 * f_21 + o_22 * f_22 + o_12 * f_12);
699 	status = ((status < 0) ? 0 : ((status > 255) ? 255 : status));
700 
701 	return (status);
702 }
703 
wmf_ipa_bmp_setcolor(wmfAPI * API,wmfBMP * bmp,wmfRGB * rgb,unsigned char opacity,unsigned int x,unsigned int y)704 void wmf_ipa_bmp_setcolor (wmfAPI* API,wmfBMP* bmp,wmfRGB* rgb,unsigned char opacity,
705                            unsigned int x,unsigned int y)
706 {
707 	/* WMF_DEBUG (API,"~~~~~~~~wmf_[ipa_]bmp_setcolor"); */
708 
709 	if (bmp->data && x < bmp->width && y < bmp->height)
710 	{	SetColor (API,bmp,rgb,opacity,x,y);
711 	}
712 	else if ((API->flags & WMF_OPT_IGNORE_NONFATAL) == 0)
713 	{	WMF_ERROR (API,"Point outside bitmap");
714 		API->err = wmf_E_Glitch;
715 	}
716 }
717 
718 /* Following source adapted from ImageMagick-5.2.7's coders/bmp.c, hence:
719 %
720 %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 %                                                                             %
723 %                                                                             %
724 %                                                                             %
725 %                            BBBB   M   M  PPPP                               %
726 %                            B   B  MM MM  P   P                              %
727 %                            BBBB   M M M  PPPP                               %
728 %                            B   B  M   M  P                                  %
729 %                            BBBB   M   M  P                                  %
730 %                                                                             %
731 %                                                                             %
732 %                    Read/Write ImageMagick Image Format.                     %
733 %                                                                             %
734 %                                                                             %
735 %                              Software Design                                %
736 %                                John Cristy                                  %
737 %                                 July 1992                                   %
738 %                                                                             %
739 %                                                                             %
740 %  Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated %
741 %  to making software imaging solutions freely available.                     %
742 %                                                                             %
743 %  Permission is hereby granted, free of charge, to any person obtaining a    %
744 %  copy of this software and associated documentation files ("ImageMagick"),  %
745 %  to deal in ImageMagick without restriction, including without limitation   %
746 %  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
747 %  and/or sell copies of ImageMagick, and to permit persons to whom the       %
748 %  ImageMagick is furnished to do so, subject to the following conditions:    %
749 %                                                                             %
750 %  The above copyright notice and this permission notice shall be included in %
751 %  all copies or substantial portions of ImageMagick.                         %
752 %                                                                             %
753 %  The software is provided "as is", without warranty of any kind, express or %
754 %  implied, including but not limited to the warranties of merchantability,   %
755 %  fitness for a particular purpose and noninfringement.  In no event shall   %
756 %  ImageMagick Studio be liable for any claim, damages or other liability,    %
757 %  whether in an action of contract, tort or otherwise, arising from, out of  %
758 %  or in connection with ImageMagick or the use or other dealings in          %
759 %  ImageMagick.                                                               %
760 %                                                                             %
761 %  Except as contained in this notice, the name of the ImageMagick Studio     %
762 %  shall not be used in advertising or otherwise to promote the sale, use or  %
763 %  other dealings in ImageMagick without prior written authorization from the %
764 %  ImageMagick Studio.                                                        %
765 %                                                                             %
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767 %
768 %
769 */
770 
ReadBlob(BMPSource * src,size_t length,unsigned char * buffer)771 static size_t ReadBlob (BMPSource* src,size_t length,unsigned char* buffer)
772 {	size_t count = 0;
773 
774 	for (count = 0; count < length; count++)
775 	{	if (src->ptr >= src->end) break;
776 
777 		buffer[count] = (*(src->ptr));
778 		src->ptr++;
779 	}
780 
781 	return (count);
782 }
783 
ReadBlobByte(BMPSource * src)784 static int ReadBlobByte (BMPSource* src)
785 {	int byte;
786 
787 	if (src->ptr >= src->end) return (EOF);
788 
789 	byte = (int) (*(src->ptr));
790 	src->ptr++;
791 
792 	return (byte);
793 }
794 
ReadBlobLSBShort(BMPSource * src)795 static unsigned short ReadBlobLSBShort (BMPSource* src)
796 {	unsigned short value;
797 
798 	unsigned char buffer[2];
799 
800 	value = ReadBlob (src,2,buffer);
801 
802 	if (value < 2) return (~value);
803 
804 	value  = buffer[1] << 8;
805 	value |= buffer[0];
806 
807 	return (value);
808 }
809 
ReadBlobLSBLong(BMPSource * src)810 static unsigned int ReadBlobLSBLong (BMPSource* src)
811 {	unsigned int value;
812 
813 	unsigned char buffer[4];
814 
815 	value = ReadBlob (src,4,buffer);
816 
817 	if (value < 4) return (~value); /* i.e., = -1 */
818 
819 	value  = buffer[3] << 24;
820 	value |= buffer[2] << 16;
821 	value |= buffer[1] <<  8;
822 	value |= buffer[0];
823 
824 	return (value);
825 }
826 
TellBlob(BMPSource * src)827 static long TellBlob (BMPSource* src)
828 {	return ((long) (src->ptr - src->begin));
829 }
830 
831 /*
832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833 %                                                                             %
834 %                                                                             %
835 %                                                                             %
836 %   D e c o d e I m a g e                                                     %
837 %                                                                             %
838 %                                                                             %
839 %                                                                             %
840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
841 %
842 %  Method DecodeImage unpacks the packed image pixels into runlength-encoded
843 %  pixel packets.
844 %
845 %  A description of each parameter follows:
846 %
847 %    o compression:  A value of 1 means the compressed pixels are runlength
848 %      encoded for a 256-color bitmap.  A value of 2 means a 16-color bitmap.
849 %
850 %    o pixels:  The address of a byte (8 bits) array of pixel data created by
851 %      the decoding process.
852 %
853 %
854 */
DecodeImage(wmfBMP * bmp,BMPSource * src,unsigned int compression,unsigned char * pixels)855 static int DecodeImage (wmfBMP* bmp,BMPSource* src,unsigned int compression,unsigned char* pixels)
856 {	int byte;
857 	int count;
858 	int i;
859 
860 	U16 x;
861 	U16 y;
862 
863 	U32 u;
864 
865 	unsigned char* q;
866 	unsigned char* end;
867 
868 	for (u = 0; u < ((U32) bmp->width * (U32) bmp->height); u++) pixels[u] = 0;
869 
870 	byte = 0;
871 	x = 0;
872 	q = pixels;
873 	end = pixels + bmp->width * bmp->height;
874 
875 	for (y = 0; y < bmp->height; )
876 	{	count = ReadBlobByte (src);
877 		if (count == EOF) break;
878 		if (count != 0)
879 		{	/* Encoded mode. */
880 			byte = ReadBlobByte (src);
881 			for (i = 0; i < count; i++)
882 			{
883 				if (q == end)
884 					return 0;
885 			 	if (compression == 1)
886 				{	(*(q++)) = (unsigned char) byte;
887 				}
888 				else
889 				{	(*(q++)) = ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
890 					x++;
891 				}
892 			}
893 		}
894 		else
895 		{	/* Escape mode. */
896 			count = ReadBlobByte (src);
897 			if (count == 0x01) return 1;
898 			switch (count)
899 			{
900 			case 0x00:
901 			 {	/* End of line. */
902 				x = 0;
903 				y++;
904 				if (y >= bmp->height)
905 					return 0;
906 				q = pixels + y * bmp->width;
907 				break;
908 			 }
909 			case 0x02:
910 			 {	/* Delta mode. */
911 				x += ReadBlobByte (src);
912 				y += ReadBlobByte (src);
913 				if (y >= bmp->height)
914 					return 0;
915 				if (x >= bmp->width)
916 					return 0;
917 				q = pixels + y * bmp->width + x;
918 				break;
919 			 }
920 			default:
921 			 {	/* Absolute mode. */
922 				for (i = 0; i < count; i++)
923 				{
924 					if (q == end)
925 						return 0;
926 					if (compression == 1)
927 					{	(*(q++)) = ReadBlobByte (src);
928 					}
929 					else
930 					{	if ((i & 0x01) == 0) byte = ReadBlobByte (src);
931 						(*(q++)) = ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
932 					}
933 					x++;
934 				}
935 				/* Read pad byte. */
936 				if (compression == 1)
937 				{	if (count & 0x01) byte = ReadBlobByte (src);
938 				}
939 				else
940 				{	if (((count & 0x03) == 1) || ((count & 0x03) == 2))
941 					{	byte = ReadBlobByte (src);
942 					}
943 				}
944 				break;
945 			 }
946 			}
947 		}
948 /* ?? TODO 	if (QuantumTick (y,image->rows)) MagickMonitor (LoadImageText,y,image->rows); */
949 	}
950 	ReadBlobByte (src);  /* end of line */
951 	ReadBlobByte (src);
952 
953 	return 1;
954 }
955 
956 /*
957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 %                                                                             %
959 %                                                                             %
960 %                                                                             %
961 %   R e a d B M P I m a g e                                                   %
962 %                                                                             %
963 %                                                                             %
964 %                                                                             %
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 %
967 %  Method ReadBMPImage reads a Microsoft Windows bitmap image file and
968 %  returns it.  It allocates the memory necessary for the new Image structure
969 %  and returns a pointer to the new image.
970 %
971 %  The format of the ReadBMPImage method is:
972 %
973 %      image=ReadBMPImage(image_info)
974 %
975 %  A description of each parameter follows:
976 %
977 %    o image:  Method ReadBMPImage returns a pointer to the image after
978 %      reading.  A null image is returned if there is a memory shortage or
979 %      if the image cannot be read.
980 %
981 %    o image_info: Specifies a pointer to an ImageInfo structure.
982 %
983 %    o exception: return any errors or warnings in this structure.
984 %
985 %
986 */
ReadBMPImage(wmfAPI * API,wmfBMP * bmp,BMPSource * src)987 static void ReadBMPImage (wmfAPI* API,wmfBMP* bmp,BMPSource* src)
988 {	BMPInfo bmp_info;
989 
990 	BMPData* data = 0;
991 
992 	long start_position = 0;
993 
994 	unsigned char packet[4];
995 
996 	unsigned int bytes_per_line;
997 	unsigned int image_size;
998 	unsigned int packet_size;
999 	unsigned int i;
1000 
1001 	unsigned long u;
1002 
1003 	size_t bytes_read;
1004 
1005 	data = (BMPData*) bmp->data;
1006 
1007 	memset (&bmp_info,0,sizeof (BMPInfo));
1008 
1009 	bmp_info.ba_offset = 0;
1010 
1011 	bmp_info.size = ReadBlobLSBLong (src);
1012 
1013 	if (bmp_info.size == 12)
1014 	{	/* OS/2 BMP image file. */
1015 		bmp_info.width  = ReadBlobLSBShort (src);
1016 		bmp_info.height = ReadBlobLSBShort (src);
1017 		bmp_info.planes = ReadBlobLSBShort (src);
1018 
1019 		bmp_info.bits_per_pixel = ReadBlobLSBShort (src);
1020 
1021 		bmp_info.x_pixels = 0;
1022 		bmp_info.y_pixels = 0;
1023 		bmp_info.number_colors = 0;
1024 		bmp_info.compression = 0;
1025 		bmp_info.image_size = 0;
1026 	}
1027 	else
1028 	{	/* Microsoft Windows BMP image file. */
1029 		bmp_info.width  = ReadBlobLSBLong (src);
1030 		bmp_info.height = ReadBlobLSBLong (src);
1031 		bmp_info.planes = ReadBlobLSBShort (src);
1032 
1033 		bmp_info.bits_per_pixel = ReadBlobLSBShort (src);
1034 
1035 		bmp_info.compression = ReadBlobLSBLong (src);
1036 		bmp_info.image_size  = ReadBlobLSBLong (src);
1037 
1038 		bmp_info.x_pixels = ReadBlobLSBLong (src);
1039 		bmp_info.y_pixels = ReadBlobLSBLong (src);
1040 
1041 		bmp_info.number_colors = ReadBlobLSBLong (src);
1042 
1043 		bmp_info.colors_important = ReadBlobLSBLong (src);
1044 
1045 		for (u = 0; u < (bmp_info.size - 40); u++) ReadBlobByte (src);
1046 
1047 		if ( (bmp_info.compression == 3)
1048 		  && ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32)) )
1049 		{	bmp_info.red_mask   = ReadBlobLSBShort (src);
1050 			bmp_info.green_mask = ReadBlobLSBShort (src);
1051 			bmp_info.blue_mask  = ReadBlobLSBShort (src);
1052 
1053 			if (bmp_info.size > 40)
1054 			{	/* Read color management information. */
1055 				bmp_info.alpha_mask = ReadBlobLSBShort (src);
1056 				bmp_info.colorspace = ReadBlobLSBLong (src);
1057 
1058 				bmp_info.red_primary.x = ReadBlobLSBLong (src);
1059 				bmp_info.red_primary.y = ReadBlobLSBLong (src);
1060 				bmp_info.red_primary.z = ReadBlobLSBLong (src);
1061 
1062 				bmp_info.green_primary.x = ReadBlobLSBLong (src);
1063 				bmp_info.green_primary.y = ReadBlobLSBLong (src);
1064 				bmp_info.green_primary.z = ReadBlobLSBLong (src);
1065 
1066 				bmp_info.blue_primary.x = ReadBlobLSBLong (src);
1067 				bmp_info.blue_primary.y = ReadBlobLSBLong (src);
1068 				bmp_info.blue_primary.z = ReadBlobLSBLong (src);
1069 
1070 				bmp_info.gamma_scale.x = ReadBlobLSBShort (src);
1071 				bmp_info.gamma_scale.y = ReadBlobLSBShort (src);
1072 				bmp_info.gamma_scale.z = ReadBlobLSBShort (src);
1073 			}
1074 		}
1075 	}
1076 
1077 	if (bmp_info.height < 0)
1078 	{	bmp_info.height = - bmp_info.height;
1079 		data->flipped = 1;
1080 	}
1081 	else
1082 	{	data->flipped = 0;
1083 	}
1084 
1085 	/* WMF may change bitmap size without changing bitmap header
1086 	 */
1087 	if (bmp->width  == 0) bmp->width  = (U16) bmp_info.width;
1088 	if (bmp->height == 0) bmp->height = (U16) bmp_info.height;
1089 
1090 	data->NColors = 0;
1091 	if ((bmp_info.number_colors != 0) || (bmp_info.bits_per_pixel < 16))
1092 	{	data->NColors = (unsigned int) bmp_info.number_colors;
1093 	}
1094 
1095 	if (data->NColors > 0)
1096 	{	/* Read BMP raster colormap. */
1097 		data->rgb = (wmfRGB*) wmf_malloc (API,data->NColors * sizeof (wmfRGB));
1098 
1099 		if (ERR (API))
1100 		{	WMF_DEBUG (API,"bailing...");
1101 			return;
1102 		}
1103 
1104 		if (bmp_info.size == 12) packet_size = 3;
1105 		else                     packet_size = 4;
1106 
1107 		for (i = 0; i < data->NColors; i++)
1108 		{	bytes_read = ReadBlob (src,packet_size,packet);
1109 			if (bytes_read < packet_size)
1110 			{	WMF_ERROR (API,"Unexpected EOF");
1111 				API->err = wmf_E_EOF;
1112 				break;
1113 			}
1114 			data->rgb[i].b = packet[0];
1115 			data->rgb[i].g = packet[1];
1116 			data->rgb[i].r = packet[2];
1117 		}
1118 
1119 		if (ERR (API))
1120 		{	WMF_DEBUG (API,"bailing...");
1121 			return;
1122 		}
1123 	}
1124 
1125 	while (TellBlob (src) < (long) (start_position + bmp_info.offset_bits))
1126 	{	ReadBlobByte (src);
1127 	}
1128 
1129 	/* Read image data. */
1130 	if (bmp_info.compression == 2) bmp_info.bits_per_pixel <<= 1;
1131 
1132 	bytes_per_line = 4 * ((bmp->width * bmp_info.bits_per_pixel + 31) / 32);
1133 
1134 	image_size = bytes_per_line * bmp->height;
1135 
1136 	data->image = (unsigned char*) wmf_malloc (API,image_size);
1137 
1138 	if (ERR (API))
1139 	{	WMF_DEBUG (API,"bailing...");
1140 		return;
1141 	}
1142 
1143 	if ((bmp_info.compression == 0) || (bmp_info.compression == 3))
1144 	{	bytes_read = ReadBlob (src,image_size,data->image);
1145 		if (bytes_read < image_size)
1146 		{	WMF_ERROR (API,"Unexpected EOF");
1147 			API->err = wmf_E_EOF;
1148 		}
1149 	}
1150 	else
1151 	{
1152 		if (bmp_info.bits_per_pixel == 8)	/* Convert run-length encoded raster pixels. */
1153 		{
1154 			if (!DecodeImage (bmp,src,(unsigned int) bmp_info.compression,data->image))
1155 			{	WMF_ERROR (API,"corrupt bmp");
1156 				API->err = wmf_E_BadFormat;
1157 			}
1158 		}
1159 		else
1160 		{	WMF_ERROR (API,"Unexpected pixel depth");
1161 			API->err = wmf_E_BadFormat;
1162 		}
1163 	}
1164 
1165 	if (ERR (API))
1166 	{	WMF_DEBUG (API,"bailing...");
1167 		return;
1168 	}
1169 
1170 	data->bits_per_pixel = bmp_info.bits_per_pixel;
1171 	data->bytes_per_line = bytes_per_line;
1172 
1173 	data->masked = bmp_info.red_mask;
1174 }
1175 
ExtractColor(wmfAPI * API,wmfBMP * bmp,wmfRGB * rgb,unsigned int x,unsigned int y)1176 static int ExtractColor (wmfAPI* API,wmfBMP* bmp,wmfRGB* rgb,unsigned int x,unsigned int y)
1177 {	int status = 0;
1178 
1179 	BMPData* data = 0;
1180 
1181 	int bit;
1182 
1183 	unsigned int color;
1184 
1185 	unsigned char opacity = WMF_BMP_OPAQUE;
1186 
1187 	unsigned char* p;
1188 
1189 	unsigned short word;
1190 
1191 	data = (BMPData*) bmp->data;
1192 
1193 	if (data->flipped) y = (bmp->height - 1) - y;
1194 
1195 	switch (data->bits_per_pixel)
1196 	{
1197 	case 1:
1198 	 {	p = data->image + (y * data->bytes_per_line) + (x >> 3);
1199 		bit = 0x80 >> (x & 0x07);
1200 
1201 		if ((*p) & bit) color = 1;
1202 		else            color = 0;
1203 
1204 		if (data->rgb && (color < data->NColors))
1205 		{	(*rgb) = data->rgb[color];
1206 		}
1207 		else
1208 		{	if (color)
1209 			{	rgb->r = 0;
1210 				rgb->g = 0;
1211 				rgb->b = 0;
1212 			}
1213 			else
1214 			{	rgb->r = 0xff;
1215 				rgb->g = 0xff;
1216 				rgb->b = 0xff;
1217 			}
1218 		}
1219 		break;
1220 	 }
1221 	case 4:
1222 	 {	p = data->image + (y * data->bytes_per_line) + (x >> 1);
1223 
1224 	 	if (x & 1) color =  (*p)       & 0x0f;
1225 	 	else       color = ((*p) >> 4) & 0x0f;
1226 
1227 		if (data->rgb && (color < data->NColors))
1228 		{	(*rgb) = data->rgb[color];
1229 		}
1230 		else
1231 		{	rgb->r = color << 4;
1232 			rgb->g = color << 4;
1233 			rgb->b = color << 4;
1234 		}
1235 		break;
1236 	 }
1237 	case 8:
1238 	 {	p = data->image + (y * data->bytes_per_line) + x;
1239 
1240 		color = (*p);
1241 
1242 		if (data->rgb && (color < data->NColors))
1243 		{	(*rgb) = data->rgb[color];
1244 		}
1245 		else
1246 		{	rgb->r = color;
1247 			rgb->g = color;
1248 			rgb->b = color;
1249 		}
1250 		break;
1251 	 }
1252 	case 16:
1253 	 {	p = data->image + (y * data->bytes_per_line) + (x << 1);
1254 
1255 		word = (unsigned short) p[0] | (((unsigned short) p[1]) << 8);
1256 
1257 		if (data->masked == 0)
1258 		{	rgb->r = ((word >> 10) & 0x1f) << 3;
1259 			rgb->g = ((word >>  5) & 0x1f) << 3;
1260 			rgb->b = ( word        & 0x1f) << 3;
1261 		}
1262 		else
1263 		{	rgb->r = ((word >> 11) & 0x1f) << 3;
1264 			rgb->g = ((word >>  5) & 0x3f) << 2;
1265 			rgb->b = ( word        & 0x1f) << 3;
1266 		}
1267 		break;
1268 	 }
1269 	case 24:
1270 	 {	p = data->image + (y * data->bytes_per_line) + (x + (x << 1));
1271 
1272 	 	rgb->b = p[0];
1273 	 	rgb->g = p[1];
1274 	 	rgb->r = p[2];
1275 
1276 		break;
1277 	 }
1278 	case 32:
1279 	 {	p = data->image + (y * data->bytes_per_line) + (x << 2);
1280 
1281 	 	rgb->b = p[0];
1282 	 	rgb->g = p[1];
1283 	 	rgb->r = p[2];
1284 
1285 	 	opacity = p[3];
1286 
1287 		break;
1288 	 }
1289 	default:
1290 		if ((API->flags & WMF_OPT_IGNORE_NONFATAL) == 0)
1291 		{	WMF_ERROR (API,"Bitmap has bad format (illegal color depth)");
1292 			API->err = wmf_E_BadFormat;
1293 		}
1294 		status = -1;
1295 	break;
1296 	}
1297 
1298 	if (status == 0) status = (int) opacity;
1299 
1300 	return (status);
1301 }
1302 
SetColor(wmfAPI * API,wmfBMP * bmp,wmfRGB * rgb,unsigned char opacity,unsigned int x,unsigned int y)1303 static void SetColor (wmfAPI* API,wmfBMP* bmp,wmfRGB* rgb,unsigned char opacity,unsigned int x,unsigned int y)
1304 {	BMPData* data = 0;
1305 
1306 	unsigned int i;
1307 	unsigned int r_diff;
1308 	unsigned int g_diff;
1309 	unsigned int b_diff;
1310 	unsigned int diff;
1311 	unsigned int min_diff;
1312 	unsigned int color;
1313 
1314 	unsigned char bit;
1315 
1316 	unsigned char* p;
1317 
1318 	unsigned short word;
1319 
1320 	data = (BMPData*) bmp->data;
1321 
1322 	if (data->flipped) y = (bmp->height - 1) - y;
1323 
1324 	switch (data->bits_per_pixel)
1325 	{
1326 	case 1:
1327 	 {	p = data->image + (y * data->bytes_per_line) + (x >> 3);
1328 		bit = 0x80 >> (x & 0x07);
1329 
1330 		if (rgb->r || rgb->g || rgb->b)
1331 		{	(*p) |= ( bit & 0xff);
1332 		}
1333 		else
1334 		{	(*p) &= (~bit & 0xff);
1335 		}
1336 
1337 		break;
1338 	 }
1339 	case 4:
1340 	 {	p = data->image + (y * data->bytes_per_line) + (x >> 1);
1341 
1342 	 	if (data->rgb == 0) break;
1343 
1344 	 	min_diff = 766;
1345 	 	color = 0;
1346 	 	for (i = 0; i < data->NColors; i++)
1347 	 	{	r_diff = (unsigned int) ABS ((int) rgb->r - (int) data->rgb[i].r);
1348 			g_diff = (unsigned int) ABS ((int) rgb->g - (int) data->rgb[i].g);
1349 			b_diff = (unsigned int) ABS ((int) rgb->b - (int) data->rgb[i].b);
1350 			diff = r_diff + g_diff + b_diff;
1351 			if (min_diff > diff)
1352 			{	min_diff = diff;
1353 				color = i;
1354 			}
1355 	 	}
1356 
1357 	 	if (x & 1)
1358 		{	(*p) = ( ((unsigned char) color)       | ((*p) & 0x0f));
1359 		}
1360 	 	else
1361 		{	(*p) = ((((unsigned char) color) << 4) | ((*p) & 0xf0));
1362 		}
1363 
1364 		break;
1365 	 }
1366 	case 8:
1367 	 {	p = data->image + (y * data->bytes_per_line) + x;
1368 
1369 	 	if (data->rgb == 0) break;
1370 
1371 	 	min_diff = 766;
1372 	 	color = 0;
1373 	 	for (i = 0; i < data->NColors; i++)
1374 	 	{	r_diff = (unsigned int) ABS ((int) rgb->r - (int) data->rgb[i].r);
1375 			g_diff = (unsigned int) ABS ((int) rgb->g - (int) data->rgb[i].g);
1376 			b_diff = (unsigned int) ABS ((int) rgb->b - (int) data->rgb[i].b);
1377 			diff = r_diff + g_diff + b_diff;
1378 			if (min_diff > diff)
1379 			{	min_diff = diff;
1380 				color = i;
1381 			}
1382 	 	}
1383 
1384 		(*p) = (unsigned char) color;
1385 
1386 		break;
1387 	 }
1388 	case 16:
1389 	 {	p = data->image + (y * data->bytes_per_line) + (x << 1);
1390 
1391 		word = 0;
1392 
1393 		if (data->masked == 0)
1394 		{	word |= (rgb->r >> 3) << 10;
1395 			word |= (rgb->g >> 3) <<  5;
1396 			word |=  rgb->b >> 3;
1397 		}
1398 		else
1399 		{	word |= (rgb->r >> 3) << 11;
1400 			word |= (rgb->g >> 2) <<  5;
1401 			word |=  rgb->b >> 3;
1402 		}
1403 
1404 		p[0] = (unsigned char) ( word & 0x00ff      );
1405 		p[1] = (unsigned char) ((word & 0xff00) >> 8);
1406 
1407 		break;
1408 	 }
1409 	case 24:
1410 	 {	p = data->image + (y * data->bytes_per_line) + (x + (x << 1));
1411 
1412 	 	p[0] = rgb->b;
1413 	 	p[1] = rgb->g;
1414 	 	p[2] = rgb->r;
1415 
1416 		break;
1417 	 }
1418 	case 32:
1419 	 {	p = data->image + (y * data->bytes_per_line) + (x << 2);
1420 
1421 	 	p[0] = rgb->b;
1422 	 	p[1] = rgb->g;
1423 	 	p[2] = rgb->r;
1424 
1425 	 	p[3] = opacity;
1426 
1427 		break;
1428 	 }
1429 	default:
1430 		if ((API->flags & WMF_OPT_IGNORE_NONFATAL) == 0)
1431 		{	WMF_ERROR (API,"Bitmap has bad format (illegal color depth)");
1432 			API->err = wmf_E_BadFormat;
1433 		}
1434 	break;
1435 	}
1436 }
1437 
1438