xref: /plan9/sys/src/cmd/aux/antiword/dib2sprt.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * dib2sprt.c
3  * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Functions to translate dib pictures into sprites
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include "DeskLib:Error.h"
12 #include "DeskLib:Sprite.h"
13 #include "antiword.h"
14 
15 #if 0 /* defined(DEBUG) */
16 static int iPicCounter = 0;
17 #endif /* DEBUG */
18 
19 
20 /*
21  * iGetByteWidth - compute the number of bytes needed for a row of pixels
22  */
23 static int
iGetByteWidth(const imagedata_type * pImg)24 iGetByteWidth(const imagedata_type *pImg)
25 {
26 	switch (pImg->uiBitsPerComponent) {
27 	case  1:
28 		return (pImg->iWidth + 31) / 32 * sizeof(int);
29 	case  4:
30 		return (pImg->iWidth + 7) / 8 * sizeof(int);
31 	case  8:
32 	case 24:
33 		return (pImg->iWidth + 3) / 4 * sizeof(int);
34 	default:
35 		DBG_DEC(pImg->uiBitsPerComponent);
36 		return 0;
37 	}
38 } /* end of iGetByteWidth */
39 
40 /*
41  * pCreateBlankSprite - Create a blank sprite.
42  *
43  * Create a blank sprite and add a palette if needed
44  *
45  * returns a pointer to the sprite when successful, otherwise NULL
46  */
47 static sprite_areainfo *
pCreateBlankSprite(const imagedata_type * pImg,size_t * pSize)48 pCreateBlankSprite(const imagedata_type *pImg, size_t *pSize)
49 {
50 	sprite_areainfo	*pArea;
51 	UCHAR	*pucTmp;
52 	size_t	tSize;
53 	screen_modeval	uMode;
54 	int	iIndex, iPaletteEntries;
55 
56 	TRACE_MSG("pCreateBlankSprite");
57 
58 	fail(pImg == NULL);
59 	fail(pSize == NULL);
60 
61 	switch (pImg->uiBitsPerComponent) {
62 	case  1:
63 		uMode.screen_mode = 18;
64 		iPaletteEntries = 2;
65 		break;
66 	case  4:
67 		uMode.screen_mode = 20;
68 		iPaletteEntries = 16;
69 		break;
70 	case  8:
71 	case 24:
72 		uMode.screen_mode = 21;
73 		iPaletteEntries = 0;
74 		break;
75 	default:
76 		DBG_DEC(pImg->uiBitsPerComponent);
77 		return NULL;
78 	}
79 	fail(iPaletteEntries < 0 || iPaletteEntries > 16);
80 
81 	/* Get memory for the sprite */
82 	tSize = sizeof(sprite_areainfo) +
83 		Sprite_MemorySize(pImg->iWidth, pImg->iHeight, uMode,
84 		iPaletteEntries > 0 ? sprite_HASPAL : sprite_HASNOMASKPAL);
85 	DBG_DEC(tSize);
86 	pArea = xmalloc(tSize);
87 
88 	/* Initialise sprite area */
89 	pArea->areasize = tSize;
90 	pArea->numsprites = 0;
91 	pArea->firstoffset = sizeof(sprite_areainfo);
92 	pArea->freeoffset = sizeof(sprite_areainfo);
93 
94 	/* Create a blank sprite */
95 	Error_CheckFatal(Sprite_Create(pArea, "wordimage",
96 		iPaletteEntries > 0 ? 1 : 0,
97 		pImg->iWidth, pImg->iHeight, uMode));
98 
99 	/* Add the palette */
100 	pucTmp = (UCHAR *)pArea + pArea->firstoffset + sizeof(sprite_header);
101 	for (iIndex = 0; iIndex < iPaletteEntries; iIndex++) {
102 		/* First color */
103 		*pucTmp++ = 0;
104 		*pucTmp++ = pImg->aucPalette[iIndex][0];
105 		*pucTmp++ = pImg->aucPalette[iIndex][1];
106 		*pucTmp++ = pImg->aucPalette[iIndex][2];
107 		/* Second color */
108 		*pucTmp++ = 0;
109 		*pucTmp++ = pImg->aucPalette[iIndex][0];
110 		*pucTmp++ = pImg->aucPalette[iIndex][1];
111 		*pucTmp++ = pImg->aucPalette[iIndex][2];
112 	}
113 
114 	*pSize = tSize;
115 	return pArea;
116 } /* end of pCreateBlankSprite */
117 
118 /*
119  * iReduceColor - reduce from 24 bit to 8 bit color
120  *
121  * Reduce 24 bit true colors to RISC OS default 256 color palette
122  *
123  * returns the resulting color
124  */
125 static int
iReduceColor(int iRed,int iGreen,int iBlue)126 iReduceColor(int iRed, int iGreen, int iBlue)
127 {
128 	int	iResult;
129 
130 	iResult = (iBlue & 0x80) ? 0x80 : 0;
131 	iResult |= (iGreen & 0x80) ? 0x40 : 0;
132 	iResult |= (iGreen & 0x40) ? 0x20 : 0;
133 	iResult |= (iRed & 0x80) ? 0x10 : 0;
134 	iResult |= (iBlue & 0x40) ? 0x08 : 0;
135 	iResult |= (iRed & 0x40) ? 0x04 : 0;
136 	iResult |= ((iRed | iGreen | iBlue) & 0x20) ? 0x02 : 0;
137 	iResult |= ((iRed | iGreen | iBlue) & 0x10) ? 0x01 : 0;
138 	return iResult;
139 } /* end of iReduceColor */
140 
141 /*
142  * vDecode1bpp - decode an uncompressed 1 bit per pixel image
143  */
144 static void
vDecode1bpp(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)145 vDecode1bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
146 {
147 	int	iX, iY, iByteWidth, iOffset, iTmp, iEighthWidth, iPadding;
148 	UCHAR	ucTmp;
149 
150 	DBG_MSG("vDecode1bpp");
151 
152 	fail(pFile == NULL);
153 	fail(pucData == NULL);
154 	fail(pImg == NULL);
155 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 2);
156 
157 	iByteWidth = iGetByteWidth(pImg);
158 
159 	iEighthWidth = (pImg->iWidth + 7) / 8;
160 	iPadding = ROUND4(iEighthWidth) - iEighthWidth;
161 
162 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
163 		for (iX = 0; iX < iEighthWidth; iX++) {
164 			iTmp = iNextByte(pFile);
165 			if (iTmp == EOF) {
166 				return;
167 			}
168 			/* Reverse the bit order */
169 			ucTmp  = (iTmp & BIT(0)) ? (UCHAR)BIT(7) : 0;
170 			ucTmp |= (iTmp & BIT(1)) ? (UCHAR)BIT(6) : 0;
171 			ucTmp |= (iTmp & BIT(2)) ? (UCHAR)BIT(5) : 0;
172 			ucTmp |= (iTmp & BIT(3)) ? (UCHAR)BIT(4) : 0;
173 			ucTmp |= (iTmp & BIT(4)) ? (UCHAR)BIT(3) : 0;
174 			ucTmp |= (iTmp & BIT(5)) ? (UCHAR)BIT(2) : 0;
175 			ucTmp |= (iTmp & BIT(6)) ? (UCHAR)BIT(1) : 0;
176 			ucTmp |= (iTmp & BIT(7)) ? (UCHAR)BIT(0) : 0;
177 			iOffset = iY * iByteWidth + iX;
178 			*(pucData + iOffset) = ucTmp;
179 		}
180 		(void)tSkipBytes(pFile, iPadding);
181 	}
182 } /* end of vDecode1bpp */
183 
184 /*
185  * vDecode4bpp - decode an uncompressed 4 bits per pixel image
186  */
187 static void
vDecode4bpp(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)188 vDecode4bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
189 {
190 	int	iX, iY, iByteWidth, iOffset, iTmp, iHalfWidth, iPadding;
191 	UCHAR	ucTmp;
192 
193 	DBG_MSG("vDecode4bpp");
194 
195 	fail(pFile == NULL);
196 	fail(pucData == NULL);
197 	fail(pImg == NULL);
198 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
199 
200 	iByteWidth = iGetByteWidth(pImg);
201 
202 	iHalfWidth = (pImg->iWidth + 1) / 2;
203 	iPadding = ROUND4(iHalfWidth) - iHalfWidth;
204 
205 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
206 		for (iX = 0; iX < iHalfWidth; iX++) {
207 			iTmp = iNextByte(pFile);
208 			if (iTmp == EOF) {
209 				return;
210 			}
211 			/* Reverse the nibble order */
212 			ucTmp = (iTmp & 0xf0) >> 4;
213 			ucTmp |= (iTmp & 0x0f) << 4;
214 			iOffset = iY * iByteWidth + iX;
215 			*(pucData + iOffset) = ucTmp;
216 		}
217 		(void)tSkipBytes(pFile, iPadding);
218 	}
219 } /* end of vDecode4bpp */
220 
221 /*
222  * vDecode8bpp - decode an uncompressed 8 bits per pixel image
223  */
224 static void
vDecode8bpp(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)225 vDecode8bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
226 {
227 	int	iX, iY, iByteWidth, iOffset, iIndex, iPadding;
228 
229 	DBG_MSG("vDecode8bpp");
230 
231 	fail(pFile == NULL);
232 	fail(pucData == NULL);
233 	fail(pImg == NULL);
234 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
235 
236 	iByteWidth = iGetByteWidth(pImg);
237 
238 	iPadding = ROUND4(pImg->iWidth) - pImg->iWidth;
239 
240 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
241 		for (iX = 0; iX < pImg->iWidth; iX++) {
242 			iIndex = iNextByte(pFile);
243 			if (iIndex == EOF) {
244 				return;
245 			}
246 			iOffset = iY * iByteWidth + iX;
247 			*(pucData + iOffset) = iReduceColor(
248 				pImg->aucPalette[iIndex][0],
249 				pImg->aucPalette[iIndex][1],
250 				pImg->aucPalette[iIndex][2]);
251 		}
252 		(void)tSkipBytes(pFile, iPadding);
253 	}
254 } /* end of vDecode8bpp */
255 
256 /*
257  * vDecode24bpp - decode an uncompressed 24 bits per pixel image
258  */
259 static void
vDecode24bpp(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)260 vDecode24bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
261 {
262 	int	iX, iY, iTripleWidth, iByteWidth, iOffset, iPadding;
263 	int	iRed, iGreen, iBlue;
264 
265 	DBG_MSG("vDecode24bpp");
266 
267 	fail(pFile == NULL);
268 	fail(pucData == NULL);
269 	fail(pImg == NULL);
270 
271 	iByteWidth = iGetByteWidth(pImg);
272 
273 	iTripleWidth = pImg->iWidth * 3;
274 	iPadding = ROUND4(iTripleWidth) - iTripleWidth;
275 
276 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
277 		for (iX = 0; iX < pImg->iWidth; iX++) {
278 			iBlue = iNextByte(pFile);
279 			if (iBlue == EOF) {
280 				return;
281 			}
282 			iGreen = iNextByte(pFile);
283 			if (iGreen == EOF) {
284 				return;
285 			}
286 			iRed = iNextByte(pFile);
287 			if (iRed == EOF) {
288 				return;
289 			}
290 			iOffset = iY * iByteWidth + iX;
291 			*(pucData + iOffset) =
292 					iReduceColor(iRed, iGreen, iBlue);
293 		}
294 		(void)tSkipBytes(pFile, iPadding);
295 	}
296 } /* end of vDecode24bpp */
297 
298 /*
299  * vDecodeRle4 - decode a RLE compressed 4 bits per pixel image
300  */
301 static void
vDecodeRle4(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)302 vDecodeRle4(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
303 {
304 	int	iX, iY, iByteWidth, iOffset, iTmp, iHalfWidth;
305 	int	iRun, iRunLength, iHalfRun;
306 	BOOL	bEOL;
307 	UCHAR	ucTmp;
308 
309 	DBG_MSG("vDecodeRle4");
310 
311 	fail(pFile == NULL);
312 	fail(pucData == NULL);
313 	fail(pImg == NULL);
314 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
315 
316 	DBG_DEC(pImg->iWidth);
317 	DBG_DEC(pImg->iHeight);
318 
319 	iByteWidth = iGetByteWidth(pImg);
320 	iHalfWidth = (pImg->iWidth + 1) / 2;
321 
322 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
323 		bEOL = FALSE;
324 		iX = 0;
325 		while (!bEOL) {
326 			iRunLength = iNextByte(pFile);
327 			if (iRunLength == EOF) {
328 				return;
329 			}
330 			if (iRunLength != 0) {
331 			  	/*
332 				 * Encoded packet:
333 				 * RunLength pixels, all the "same" value
334 				 */
335 				iTmp = iNextByte(pFile);
336 				if (iTmp == EOF) {
337 					return;
338 				}
339 				/* Reverse the nibble order */
340 				ucTmp = (iTmp & 0xf0) >> 4;
341 				ucTmp |= (iTmp & 0x0f) << 4;
342 				iHalfRun = (iRunLength + 1) / 2;
343 				for (iRun = 0; iRun < iHalfRun; iRun++) {
344 					if (iX < iHalfWidth) {
345 						iOffset = iY * iByteWidth + iX;
346 						*(pucData + iOffset) = ucTmp;
347 					}
348 					iX++;
349 				}
350 				continue;
351 			}
352 			/* Literal or escape */
353 			iRunLength = iNextByte(pFile);
354 			if (iRunLength == EOF) {
355 				return;
356 			}
357 			if (iRunLength == 0) {		/* End of line escape */
358 				bEOL = TRUE;
359 			} else if (iRunLength == 1) {	/* End of file escape */
360 				return;
361 			} else if (iRunLength == 2) {	/* Delta escape */
362 				DBG_MSG("RLE4: encountered delta escape");
363 				return;
364 			} else {			/* Literal packet */
365 				iHalfRun = (iRunLength + 1) / 2;
366 				for (iRun = 0; iRun < iHalfRun; iRun++) {
367 					iTmp = iNextByte(pFile);
368 					if (iTmp == EOF) {
369 						return;
370 					}
371 					/* Reverse the nibble order */
372 					ucTmp = (iTmp & 0xf0) >> 4;
373 					ucTmp |= (iTmp & 0x0f) << 4;
374 					if (iX < iHalfWidth) {
375 						iOffset = iY * iByteWidth + iX;
376 						*(pucData + iOffset) = ucTmp;
377 					}
378 					iX++;
379 				}
380 				/* Padding if the number of bytes is odd */
381 				if (odd(iHalfRun)) {
382 					(void)tSkipBytes(pFile, 1);
383 				}
384 			}
385 		}
386 		DBG_DEC_C(iX != iHalfWidth, iX);
387 	}
388 } /* end of vDecodeRle4 */
389 
390 /*
391  * vDecodeRle8 - decode a RLE compressed 8 bits per pixel image
392  */
393 static void
vDecodeRle8(FILE * pFile,UCHAR * pucData,const imagedata_type * pImg)394 vDecodeRle8(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
395 {
396 	int	iX, iY, iRun, iRunLength, iOffset, iIndex, iByteWidth;
397 	BOOL	bEOL;
398 
399 	DBG_MSG("vDecodeRle8");
400 
401 	fail(pFile == NULL);
402 	fail(pucData == NULL);
403 	fail(pImg == NULL);
404 	fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
405 
406 	DBG_DEC(pImg->iWidth);
407 	DBG_DEC(pImg->iHeight);
408 
409 	iByteWidth = iGetByteWidth(pImg);
410 
411 	for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
412 		bEOL = FALSE;
413 		iX = 0;
414 		while (!bEOL) {
415 			iRunLength = iNextByte(pFile);
416 			if (iRunLength == EOF) {
417 				return;
418 			}
419 			if (iRunLength != 0) {
420 			  	/*
421 				 * Encoded packet:
422 				 * RunLength pixels, all the same value
423 				 */
424 				iIndex = iNextByte(pFile);
425 				if (iIndex == EOF) {
426 					return;
427 				}
428 				for (iRun = 0; iRun < iRunLength; iRun++) {
429 					if (iX < pImg->iWidth) {
430 						iOffset = iY * iByteWidth + iX;
431 						*(pucData + iOffset) =
432 							iReduceColor(
433 							pImg->aucPalette[iIndex][0],
434 							pImg->aucPalette[iIndex][1],
435 							pImg->aucPalette[iIndex][2]);
436 					}
437 					iX++;
438 				}
439 				continue;
440 			}
441 			/* Literal or escape */
442 			iRunLength = iNextByte(pFile);
443 			if (iRunLength == EOF) {
444 				return;
445 			}
446 			if (iRunLength == 0) {		/* End of line escape */
447 				bEOL = TRUE;
448 			} else if (iRunLength == 1) {	/* End of file escape */
449 				return;
450 			} else if (iRunLength == 2) {	/* Delta escape */
451 				DBG_MSG("RLE8: encountered delta escape");
452 				return;
453 			} else {			/* Literal packet */
454 				for (iRun = 0; iRun < iRunLength; iRun++) {
455 					iIndex = iNextByte(pFile);
456 					if (iIndex == EOF) {
457 						return;
458 					}
459 					if (iX < pImg->iWidth) {
460 						iOffset = iY * iByteWidth + iX;
461 						*(pucData + iOffset) =
462 							iReduceColor(
463 							pImg->aucPalette[iIndex][0],
464 							pImg->aucPalette[iIndex][1],
465 							pImg->aucPalette[iIndex][2]);
466 					}
467 					iX++;
468 				}
469 				/* Padding if the number of bytes is odd */
470 				if (odd(iRunLength)) {
471 					(void)tSkipBytes(pFile, 1);
472 				}
473 			}
474 		}
475 		DBG_DEC_C(iX != pImg->iWidth, iX);
476 	}
477 } /* end of vDecodeRle8 */
478 
479 #if 0 /* defined(DEBUG) */
480 static void
481 vCopy2File(UCHAR *pucSprite, size_t tSpriteSize)
482 {
483 	FILE	*pOutFile;
484 	int	iIndex;
485 	char	szFilename[30];
486 
487 	sprintf(szFilename, "<Wimp$ScrapDir>.sprt%04d", ++iPicCounter);
488 	pOutFile = fopen(szFilename, "wb");
489 	if (pOutFile == NULL) {
490 		return;
491 	}
492 	DBG_MSG(szFilename);
493 	for (iIndex = 4; iIndex < (int)tSpriteSize; iIndex++) {
494 		if (putc(pucSprite[iIndex], pOutFile) == EOF) {
495 			break;
496 		}
497 	}
498 	(void)fclose(pOutFile);
499 	vSetFiletype(szFilename, FILETYPE_SPRITE);
500 } /* end of vCopy2File */
501 #endif /* DEBUG */
502 
503 /*
504  * vDecodeDIB - decode a dib picture
505  */
506 static void
vDecodeDIB(diagram_type * pDiag,FILE * pFile,const imagedata_type * pImg)507 vDecodeDIB(diagram_type *pDiag, FILE *pFile, const imagedata_type *pImg)
508 {
509 	sprite_areainfo	*pSprite;
510 	UCHAR	*pucPalette, *pucData;
511 	size_t	tSpriteSize;
512 	int	iHeaderSize;
513 
514 	/* Skip the bitmap info header */
515 	iHeaderSize = (int)ulNextLong(pFile);
516 	(void)tSkipBytes(pFile, iHeaderSize - 4);
517 	/* Skip the colortable */
518 	if (pImg->uiBitsPerComponent <= 8) {
519 		(void)tSkipBytes(pFile,
520 			pImg->iColorsUsed * ((iHeaderSize > 12) ? 4 : 3));
521 	}
522 
523 	/* Create an blank sprite */
524 	pSprite = pCreateBlankSprite(pImg, &tSpriteSize);
525 	pucPalette = (UCHAR *)pSprite +
526 			pSprite->firstoffset + sizeof(sprite_header);
527 
528 	/* Add the pixel information */
529 	switch (pImg->uiBitsPerComponent) {
530 	case  1:
531 		fail(pImg->eCompression != compression_none);
532 		pucData = pucPalette + 2 * 8;
533 		vDecode1bpp(pFile, pucData, pImg);
534 		break;
535 	case  4:
536 		fail(pImg->eCompression != compression_none &&
537 				pImg->eCompression != compression_rle4);
538 		pucData = pucPalette + 16 * 8;
539 		if (pImg->eCompression == compression_rle4) {
540 			vDecodeRle4(pFile, pucData, pImg);
541 		} else {
542 			vDecode4bpp(pFile, pucData, pImg);
543 		}
544 		break;
545 	case  8:
546 		fail(pImg->eCompression != compression_none &&
547 				pImg->eCompression != compression_rle8);
548 		pucData = pucPalette + 0 * 8;
549 		if (pImg->eCompression == compression_rle8) {
550 			vDecodeRle8(pFile, pucData, pImg);
551 		} else {
552 			vDecode8bpp(pFile, pucData, pImg);
553 		}
554 		break;
555 	case 24:
556 		fail(pImg->eCompression != compression_none);
557 		pucData = pucPalette + 0 * 8;
558 		vDecode24bpp(pFile, pucData, pImg);
559 		break;
560 	default:
561 		DBG_DEC(pImg->uiBitsPerComponent);
562 		break;
563 	}
564 
565 #if 0 /* defined(DEBUG) */
566 	vCopy2File((UCHAR *)pSprite, tSpriteSize);
567 #endif /* DEBUG */
568 
569 	/* Add the sprite to the Draw file */
570 	vImage2Diagram(pDiag, pImg,
571 		(UCHAR *)pSprite + pSprite->firstoffset,
572 		tSpriteSize - pSprite->firstoffset);
573 
574 	/* Clean up before you leave */
575 	pSprite = xfree(pSprite);
576 } /* end of vDecodeDIB */
577 
578 /*
579  * bTranslateDIB - translate a DIB picture
580  *
581  * This function translates a picture from dib to sprite
582  *
583  * return TRUE when sucessful, otherwise FALSE
584  */
585 BOOL
bTranslateDIB(diagram_type * pDiag,FILE * pFile,ULONG ulFileOffset,const imagedata_type * pImg)586 bTranslateDIB(diagram_type *pDiag, FILE *pFile,
587 	ULONG ulFileOffset, const imagedata_type *pImg)
588 {
589 	/* Seek to start position of DIB data */
590 	if (!bSetDataOffset(pFile, ulFileOffset)) {
591 		return FALSE;
592 	}
593 
594 	vDecodeDIB(pDiag, pFile, pImg);
595 
596 	return TRUE;
597 } /* end of bTranslateDIB */
598