xref: /plan9/sys/src/cmd/aux/antiword/dib2eps.c (revision f5736e95f14e1485b3a0291fa82d86cca323ab61)
1 /*
2  * dib2eps.c
3  * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Functions to translate dib pictures into eps
7  *
8  *================================================================
9  * This part of the software is based on:
10  * The Windows Bitmap Decoder Class part of paintlib
11  * Paintlib is copyright (c) 1996-2000 Ulrich von Zadow
12  *================================================================
13  * The credit should go to him, but all the bugs are mine.
14  */
15 
16 #include <stdio.h>
17 #include "antiword.h"
18 
19 
20 /*
21  * vDecode1bpp - decode an uncompressed 1 bit per pixel image
22  */
23 static void
vDecode1bpp(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)24 vDecode1bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
25 {
26 	size_t	tPadding;
27 	int	iX, iY, iN, iByte, iTmp, iEighthWidth, iUse;
28 
29 	DBG_MSG("vDecode1bpp");
30 
31 	fail(pOutFile == NULL);
32 	fail(pImg == NULL);
33 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 2);
34 
35 	DBG_DEC(pImg->iWidth);
36 	DBG_DEC(pImg->iHeight);
37 
38 	iEighthWidth = (pImg->iWidth + 7) / 8;
39 	tPadding = (size_t)(ROUND4(iEighthWidth) - iEighthWidth);
40 
41 	for (iY = 0; iY < pImg->iHeight; iY++) {
42 		for (iX = 0; iX < iEighthWidth; iX++) {
43 			iByte = iNextByte(pInFile);
44 			if (iByte == EOF) {
45 				vASCII85EncodeByte(pOutFile, EOF);
46 				return;
47 			}
48 			if (iX == iEighthWidth - 1 && pImg->iWidth % 8 != 0) {
49 				iUse = pImg->iWidth % 8;
50 			} else {
51 				iUse = 8;
52 			}
53 			for (iN = 0; iN < iUse; iN++) {
54 				switch (iN) {
55 				case 0: iTmp = (iByte & 0x80) / 128; break;
56 				case 1: iTmp = (iByte & 0x40) / 64; break;
57 				case 2: iTmp = (iByte & 0x20) / 32; break;
58 				case 3: iTmp = (iByte & 0x10) / 16; break;
59 				case 4: iTmp = (iByte & 0x08) / 8; break;
60 				case 5: iTmp = (iByte & 0x04) / 4; break;
61 				case 6: iTmp = (iByte & 0x02) / 2; break;
62 				case 7: iTmp = (iByte & 0x01); break;
63 				default: iTmp = 0; break;
64 				}
65 				vASCII85EncodeByte(pOutFile, iTmp);
66 			}
67 		}
68 		(void)tSkipBytes(pInFile, tPadding);
69 	}
70 	vASCII85EncodeByte(pOutFile, EOF);
71 } /* end of vDecode1bpp */
72 
73 /*
74  * vDecode4bpp - decode an uncompressed 4 bits per pixel image
75  */
76 static void
vDecode4bpp(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)77 vDecode4bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
78 {
79 	size_t	tPadding;
80 	int	iX, iY, iN, iByte, iTmp, iHalfWidth, iUse;
81 
82 	DBG_MSG("vDecode4bpp");
83 
84 	fail(pInFile == NULL);
85 	fail(pOutFile == NULL);
86 	fail(pImg == NULL);
87 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
88 
89 	DBG_DEC(pImg->iWidth);
90 	DBG_DEC(pImg->iHeight);
91 
92 	iHalfWidth = (pImg->iWidth + 1) / 2;
93 	tPadding = (size_t)(ROUND4(iHalfWidth) - iHalfWidth);
94 
95 	for (iY = 0; iY < pImg->iHeight; iY++) {
96 		for (iX = 0; iX < iHalfWidth; iX++) {
97 			iByte = iNextByte(pInFile);
98 			if (iByte == EOF) {
99 				vASCII85EncodeByte(pOutFile, EOF);
100 				return;
101 			}
102 			if (iX == iHalfWidth - 1 && odd(pImg->iWidth)) {
103 				iUse = 1;
104 			} else {
105 				iUse = 2;
106 			}
107 			for (iN = 0; iN < iUse; iN++) {
108 				if (odd(iN)) {
109 					iTmp = iByte & 0x0f;
110 				} else {
111 					iTmp = (iByte & 0xf0) / 16;
112 				}
113 				vASCII85EncodeByte(pOutFile, iTmp);
114 			}
115 		}
116 		(void)tSkipBytes(pInFile, tPadding);
117 	}
118 	vASCII85EncodeByte(pOutFile, EOF);
119 } /* end of vDecode4bpp */
120 
121 /*
122  * vDecode8bpp - decode an uncompressed 8 bits per pixel image
123  */
124 static void
vDecode8bpp(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)125 vDecode8bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
126 {
127 	size_t	tPadding;
128 	int	iX, iY, iByte;
129 
130 	DBG_MSG("vDecode8bpp");
131 
132 	fail(pInFile == NULL);
133 	fail(pOutFile == NULL);
134 	fail(pImg == NULL);
135 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
136 
137 	DBG_DEC(pImg->iWidth);
138 	DBG_DEC(pImg->iHeight);
139 
140 	tPadding = (size_t)(ROUND4(pImg->iWidth) - pImg->iWidth);
141 
142 	for (iY = 0; iY < pImg->iHeight; iY++) {
143 		for (iX = 0; iX < pImg->iWidth; iX++) {
144 			iByte = iNextByte(pInFile);
145 			if (iByte == EOF) {
146 				vASCII85EncodeByte(pOutFile, EOF);
147 				return;
148 			}
149 			vASCII85EncodeByte(pOutFile, iByte);
150 		}
151 		(void)tSkipBytes(pInFile, tPadding);
152 	}
153 	vASCII85EncodeByte(pOutFile, EOF);
154 } /* end of vDecode8bpp */
155 
156 /*
157  * vDecode24bpp - decode an uncompressed 24 bits per pixel image
158  */
159 static void
vDecode24bpp(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)160 vDecode24bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
161 {
162 	size_t	tPadding;
163 	int	iX, iY, iBlue, iGreen, iRed, iTripleWidth;
164 
165 	DBG_MSG("vDecode24bpp");
166 
167 	fail(pInFile == NULL);
168 	fail(pOutFile == NULL);
169 	fail(pImg == NULL);
170 	fail(!pImg->bColorImage);
171 
172 	DBG_DEC(pImg->iWidth);
173 	DBG_DEC(pImg->iHeight);
174 
175 	iTripleWidth = pImg->iWidth * 3;
176 	tPadding = (size_t)(ROUND4(iTripleWidth) - iTripleWidth);
177 
178 	for (iY = 0; iY < pImg->iHeight; iY++) {
179 		for (iX = 0; iX < pImg->iWidth; iX++) {
180 			/* Change from BGR order to RGB order */
181 			iBlue = iNextByte(pInFile);
182 			if (iBlue == EOF) {
183 				vASCII85EncodeByte(pOutFile, EOF);
184 				return;
185 			}
186 			iGreen = iNextByte(pInFile);
187 			if (iGreen == EOF) {
188 				vASCII85EncodeByte(pOutFile, EOF);
189 				return;
190 			}
191 			iRed = iNextByte(pInFile);
192 			if (iRed == EOF) {
193 				vASCII85EncodeByte(pOutFile, EOF);
194 				return;
195 			}
196 			vASCII85EncodeByte(pOutFile, iRed);
197 			vASCII85EncodeByte(pOutFile, iGreen);
198 			vASCII85EncodeByte(pOutFile, iBlue);
199 		}
200 		(void)tSkipBytes(pInFile, tPadding);
201 	}
202 	vASCII85EncodeByte(pOutFile, EOF);
203 } /* end of vDecode24bpp */
204 
205 /*
206  * vDecodeRle4 - decode a RLE compressed 4 bits per pixel image
207  */
208 static void
vDecodeRle4(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)209 vDecodeRle4(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
210 {
211 	int	iX, iY, iByte, iTmp, iRunLength, iRun;
212 	BOOL	bEOF, bEOL;
213 
214 	DBG_MSG("vDecodeRle4");
215 
216 	fail(pInFile == NULL);
217 	fail(pOutFile == NULL);
218 	fail(pImg == NULL);
219 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
220 
221 	DBG_DEC(pImg->iWidth);
222 	DBG_DEC(pImg->iHeight);
223 
224 	bEOF = FALSE;
225 
226 	for (iY =  0; iY < pImg->iHeight && !bEOF; iY++) {
227 		bEOL = FALSE;
228 		iX = 0;
229 		while (!bEOL) {
230 			iRunLength = iNextByte(pInFile);
231 			if (iRunLength == EOF) {
232 				vASCII85EncodeByte(pOutFile, EOF);
233 				return;
234 			}
235 			if (iRunLength != 0) {
236 				/*
237 				 * Encoded packet:
238 				 * RunLength pixels, all the "same" value
239 				 */
240 				iByte = iNextByte(pInFile);
241 				if (iByte == EOF) {
242 					vASCII85EncodeByte(pOutFile, EOF);
243 					return;
244 				}
245 				for (iRun = 0; iRun < iRunLength; iRun++) {
246 					if (odd(iRun)) {
247 						iTmp = iByte & 0x0f;
248 					} else {
249 						iTmp = (iByte & 0xf0) / 16;
250 					}
251 					if (iX < pImg->iWidth) {
252 						vASCII85EncodeByte(pOutFile, iTmp);
253 					}
254 					iX++;
255 				}
256 				continue;
257 			}
258 			/* Literal or escape */
259 			iRunLength = iNextByte(pInFile);
260 			if (iRunLength == EOF) {
261 				vASCII85EncodeByte(pOutFile, EOF);
262 				return;
263 			}
264 			if (iRunLength == 0) {		/* End of line escape */
265 				bEOL = TRUE;
266 			} else if (iRunLength == 1) {	/* End of file escape */
267 				bEOF = TRUE;
268 				bEOL = TRUE;
269 			} else if (iRunLength == 2) {	/* Delta escape */
270 				DBG_MSG("RLE4: encountered delta escape");
271 				bEOF = TRUE;
272 				bEOL = TRUE;
273 			} else {			/* Literal packet */
274 				iByte = 0;
275 				for (iRun = 0; iRun < iRunLength; iRun++) {
276 					if (odd(iRun)) {
277 						iTmp = iByte & 0x0f;
278 					} else {
279 						iByte = iNextByte(pInFile);
280 						if (iByte == EOF) {
281 							vASCII85EncodeByte(pOutFile, EOF);
282 							return;
283 						}
284 						iTmp = (iByte & 0xf0) / 16;
285 					}
286 					if (iX < pImg->iWidth) {
287 						vASCII85EncodeByte(pOutFile, iTmp);
288 					}
289 					iX++;
290 				}
291 				/* Padding if the number of bytes is odd */
292 				if (odd((iRunLength + 1) / 2)) {
293 					(void)tSkipBytes(pInFile, 1);
294 				}
295 			}
296 		}
297 		DBG_DEC_C(iX != pImg->iWidth, iX);
298 	}
299 	vASCII85EncodeByte(pOutFile, EOF);
300 } /* end of vDecodeRle4 */
301 
302 /*
303  * vDecodeRle8 - decode a RLE compressed 8 bits per pixel image
304  */
305 static void
vDecodeRle8(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)306 vDecodeRle8(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
307 {
308 	int	iX, iY, iByte, iRunLength, iRun;
309 	BOOL	bEOF, bEOL;
310 
311 	DBG_MSG("vDecodeRle8");
312 
313 	fail(pInFile == NULL);
314 	fail(pOutFile == NULL);
315 	fail(pImg == NULL);
316 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
317 
318 	DBG_DEC(pImg->iWidth);
319 	DBG_DEC(pImg->iHeight);
320 
321 	bEOF = FALSE;
322 
323 	for (iY = 0; iY < pImg->iHeight && !bEOF; iY++) {
324 		bEOL = FALSE;
325 		iX = 0;
326 		while (!bEOL) {
327 			iRunLength = iNextByte(pInFile);
328 			if (iRunLength == EOF) {
329 				vASCII85EncodeByte(pOutFile, EOF);
330 				return;
331 			}
332 			if (iRunLength != 0) {
333 				/*
334 				 * Encoded packet:
335 				 * RunLength pixels, all the same value
336 				 */
337 				iByte = iNextByte(pInFile);
338 				if (iByte == EOF) {
339 					vASCII85EncodeByte(pOutFile, EOF);
340 					return;
341 				}
342 				for (iRun = 0; iRun < iRunLength; iRun++) {
343 					if (iX < pImg->iWidth) {
344 						vASCII85EncodeByte(pOutFile, iByte);
345 					}
346 					iX++;
347 				}
348 				continue;
349 			}
350 			/* Literal or escape */
351 			iRunLength = iNextByte(pInFile);
352 			if (iRunLength == EOF) {
353 				vASCII85EncodeByte(pOutFile, EOF);
354 				return;
355 			}
356 			if (iRunLength == 0) {		/* End of line escape */
357 				bEOL = TRUE;
358 			} else if (iRunLength == 1) {	/* End of file escape */
359 				bEOF = TRUE;
360 				bEOL = TRUE;
361 			} else if (iRunLength == 2) {	/* Delta escape */
362 				DBG_MSG("RLE8: encountered delta escape");
363 				bEOF = TRUE;
364 				bEOL = TRUE;
365 			} else {			/* Literal packet */
366 				for (iRun = 0; iRun < iRunLength; iRun++) {
367 					iByte = iNextByte(pInFile);
368 					if (iByte == EOF) {
369 						vASCII85EncodeByte(pOutFile, EOF);
370 						return;
371 					}
372 					if (iX < pImg->iWidth) {
373 						vASCII85EncodeByte(pOutFile, iByte);
374 					}
375 					iX++;
376 				}
377 				/* Padding if the number of bytes is odd */
378 				if (odd(iRunLength)) {
379 					(void)tSkipBytes(pInFile, 1);
380 				}
381 			}
382 		}
383 		DBG_DEC_C(iX != pImg->iWidth, iX);
384 	}
385 	vASCII85EncodeByte(pOutFile, EOF);
386 } /* end of vDecodeRle8 */
387 
388 /*
389  * vDecodeDIB - decode a dib picture
390  */
391 static void
vDecodeDIB(FILE * pInFile,FILE * pOutFile,const imagedata_type * pImg)392 vDecodeDIB(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
393 {
394 	size_t	tHeaderSize;
395 
396 	fail(pInFile == NULL);
397 	fail(pOutFile == NULL);
398 	fail(pImg == NULL);
399 
400 	/* Skip the bitmap info header */
401 	tHeaderSize = (size_t)ulNextLong(pInFile);
402 	(void)tSkipBytes(pInFile, tHeaderSize - 4);
403 	/* Skip the colortable */
404 	if (pImg->uiBitsPerComponent <= 8) {
405 		(void)tSkipBytes(pInFile,
406 			(size_t)(pImg->iColorsUsed *
407 			 ((tHeaderSize > 12) ? 4 : 3)));
408 	}
409 
410 	switch (pImg->uiBitsPerComponent) {
411 	case 1:
412 		fail(pImg->eCompression != compression_none);
413 		vDecode1bpp(pInFile, pOutFile, pImg);
414 		break;
415 	case 4:
416 		fail(pImg->eCompression != compression_none &&
417 				pImg->eCompression != compression_rle4);
418 		if (pImg->eCompression == compression_rle4) {
419 			vDecodeRle4(pInFile, pOutFile, pImg);
420 		} else {
421 			vDecode4bpp(pInFile, pOutFile, pImg);
422 		}
423 		break;
424 	case 8:
425 		fail(pImg->eCompression != compression_none &&
426 				pImg->eCompression != compression_rle8);
427 		if (pImg->eCompression == compression_rle8) {
428 			vDecodeRle8(pInFile, pOutFile, pImg);
429 		} else {
430 			vDecode8bpp(pInFile, pOutFile, pImg);
431 		}
432 		break;
433 	case 24:
434 		fail(pImg->eCompression != compression_none);
435 		vDecode24bpp(pInFile, pOutFile, pImg);
436 		break;
437 	default:
438 		DBG_DEC(pImg->uiBitsPerComponent);
439 		break;
440 	}
441 } /* end of vDecodeDIB */
442 
443 #if defined(DEBUG)
444 /*
445  * vCopy2File
446  */
447 static void
vCopy2File(FILE * pInFile,ULONG ulFileOffset,size_t tPictureLen)448 vCopy2File(FILE *pInFile, ULONG ulFileOffset, size_t tPictureLen)
449 {
450 	static int	iPicCounter = 0;
451 	FILE	*pOutFile;
452 	size_t	tIndex;
453 	int	iTmp;
454 	char	szFilename[30];
455 
456 	if (!bSetDataOffset(pInFile, ulFileOffset)) {
457 		return;
458 	}
459 
460 	sprintf(szFilename, "/tmp/pic/pic%04d.bmp", ++iPicCounter);
461 	pOutFile = fopen(szFilename, "wb");
462 	if (pOutFile == NULL) {
463 		return;
464 	}
465 	/* Turn a dib into a bmp by adding a fake 14 byte header */
466 	(void)putc('B', pOutFile);
467 	(void)putc('M', pOutFile);
468 	for (iTmp = 0; iTmp < 12; iTmp++) {
469 		if (putc(0, pOutFile) == EOF) {
470 			break;
471 		}
472 	}
473 	for (tIndex = 0; tIndex < tPictureLen; tIndex++) {
474 		iTmp = iNextByte(pInFile);
475 		if (putc(iTmp, pOutFile) == EOF) {
476 			break;
477 		}
478 	}
479 	(void)fclose(pOutFile);
480 } /* end of vCopy2File */
481 #endif /* DEBUG */
482 
483 /*
484  * bTranslateDIB - translate a DIB picture
485  *
486  * This function translates a picture from dib to eps
487  *
488  * return TRUE when sucessful, otherwise FALSE
489  */
490 BOOL
bTranslateDIB(diagram_type * pDiag,FILE * pInFile,ULONG ulFileOffset,const imagedata_type * pImg)491 bTranslateDIB(diagram_type *pDiag, FILE *pInFile,
492 		ULONG ulFileOffset, const imagedata_type *pImg)
493 {
494 #if defined(DEBUG)
495 	fail(pImg->tPosition > pImg->tLength);
496 	vCopy2File(pInFile, ulFileOffset, pImg->tLength - pImg->tPosition);
497 #endif /* DEBUG */
498 
499 	/* Seek to start position of DIB data */
500 	if (!bSetDataOffset(pInFile, ulFileOffset)) {
501 		return FALSE;
502 	}
503 
504 	vImagePrologue(pDiag, pImg);
505 	vDecodeDIB(pInFile, pDiag->pOutFile, pImg);
506 	vImageEpilogue(pDiag);
507 
508 	return TRUE;
509 } /* end of bTranslateDIB */
510