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