3 * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
6 * Functions to translate dib pictures into sprites
11 #include "DeskLib:Error.h"
12 #include "DeskLib:Sprite.h"
15 #if 0 /* defined(DEBUG) */
16 static int iPicCounter
= 0;
21 * iGetByteWidth - compute the number of bytes needed for a row of pixels
24 iGetByteWidth(const imagedata_type
*pImg
)
26 switch (pImg
->uiBitsPerComponent
) {
28 return (pImg
->iWidth
+ 31) / 32 * sizeof(int);
30 return (pImg
->iWidth
+ 7) / 8 * sizeof(int);
33 return (pImg
->iWidth
+ 3) / 4 * sizeof(int);
35 DBG_DEC(pImg
->uiBitsPerComponent
);
38 } /* end of iGetByteWidth */
41 * pCreateBlankSprite - Create a blank sprite.
43 * Create a blank sprite and add a palette if needed
45 * returns a pointer to the sprite when successful, otherwise NULL
47 static sprite_areainfo
*
48 pCreateBlankSprite(const imagedata_type
*pImg
, size_t *pSize
)
50 sprite_areainfo
*pArea
;
54 int iIndex
, iPaletteEntries
;
56 TRACE_MSG("pCreateBlankSprite");
61 switch (pImg
->uiBitsPerComponent
) {
63 uMode
.screen_mode
= 18;
67 uMode
.screen_mode
= 20;
72 uMode
.screen_mode
= 21;
76 DBG_DEC(pImg
->uiBitsPerComponent
);
79 fail(iPaletteEntries
< 0 || iPaletteEntries
> 16);
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
);
86 pArea
= xmalloc(tSize
);
88 /* Initialise sprite area */
89 pArea
->areasize
= tSize
;
90 pArea
->numsprites
= 0;
91 pArea
->firstoffset
= sizeof(sprite_areainfo
);
92 pArea
->freeoffset
= sizeof(sprite_areainfo
);
94 /* Create a blank sprite */
95 Error_CheckFatal(Sprite_Create(pArea
, "wordimage",
96 iPaletteEntries
> 0 ? 1 : 0,
97 pImg
->iWidth
, pImg
->iHeight
, uMode
));
100 pucTmp
= (UCHAR
*)pArea
+ pArea
->firstoffset
+ sizeof(sprite_header
);
101 for (iIndex
= 0; iIndex
< iPaletteEntries
; iIndex
++) {
104 *pucTmp
++ = pImg
->aucPalette
[iIndex
][0];
105 *pucTmp
++ = pImg
->aucPalette
[iIndex
][1];
106 *pucTmp
++ = pImg
->aucPalette
[iIndex
][2];
109 *pucTmp
++ = pImg
->aucPalette
[iIndex
][0];
110 *pucTmp
++ = pImg
->aucPalette
[iIndex
][1];
111 *pucTmp
++ = pImg
->aucPalette
[iIndex
][2];
116 } /* end of pCreateBlankSprite */
119 * iReduceColor - reduce from 24 bit to 8 bit color
121 * Reduce 24 bit true colors to RISC OS default 256 color palette
123 * returns the resulting color
126 iReduceColor(int iRed
, int iGreen
, int iBlue
)
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;
139 } /* end of iReduceColor */
142 * vDecode1bpp - decode an uncompressed 1 bit per pixel image
145 vDecode1bpp(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
147 int iX
, iY
, iByteWidth
, iOffset
, iTmp
, iEighthWidth
, iPadding
;
150 DBG_MSG("vDecode1bpp");
153 fail(pucData
== NULL
);
155 fail(pImg
->iColorsUsed
< 1 || pImg
->iColorsUsed
> 2);
157 iByteWidth
= iGetByteWidth(pImg
);
159 iEighthWidth
= (pImg
->iWidth
+ 7) / 8;
160 iPadding
= ROUND4(iEighthWidth
) - iEighthWidth
;
162 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
163 for (iX
= 0; iX
< iEighthWidth
; iX
++) {
164 iTmp
= iNextByte(pFile
);
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
;
180 (void)tSkipBytes(pFile
, iPadding
);
182 } /* end of vDecode1bpp */
185 * vDecode4bpp - decode an uncompressed 4 bits per pixel image
188 vDecode4bpp(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
190 int iX
, iY
, iByteWidth
, iOffset
, iTmp
, iHalfWidth
, iPadding
;
193 DBG_MSG("vDecode4bpp");
196 fail(pucData
== NULL
);
198 fail(pImg
->iColorsUsed
< 1 || pImg
->iColorsUsed
> 16);
200 iByteWidth
= iGetByteWidth(pImg
);
202 iHalfWidth
= (pImg
->iWidth
+ 1) / 2;
203 iPadding
= ROUND4(iHalfWidth
) - iHalfWidth
;
205 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
206 for (iX
= 0; iX
< iHalfWidth
; iX
++) {
207 iTmp
= iNextByte(pFile
);
211 /* Reverse the nibble order */
212 ucTmp
= (iTmp
& 0xf0) >> 4;
213 ucTmp
|= (iTmp
& 0x0f) << 4;
214 iOffset
= iY
* iByteWidth
+ iX
;
215 *(pucData
+ iOffset
) = ucTmp
;
217 (void)tSkipBytes(pFile
, iPadding
);
219 } /* end of vDecode4bpp */
222 * vDecode8bpp - decode an uncompressed 8 bits per pixel image
225 vDecode8bpp(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
227 int iX
, iY
, iByteWidth
, iOffset
, iIndex
, iPadding
;
229 DBG_MSG("vDecode8bpp");
232 fail(pucData
== NULL
);
234 fail(pImg
->iColorsUsed
< 1 || pImg
->iColorsUsed
> 256);
236 iByteWidth
= iGetByteWidth(pImg
);
238 iPadding
= ROUND4(pImg
->iWidth
) - pImg
->iWidth
;
240 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
241 for (iX
= 0; iX
< pImg
->iWidth
; iX
++) {
242 iIndex
= iNextByte(pFile
);
246 iOffset
= iY
* iByteWidth
+ iX
;
247 *(pucData
+ iOffset
) = iReduceColor(
248 pImg
->aucPalette
[iIndex
][0],
249 pImg
->aucPalette
[iIndex
][1],
250 pImg
->aucPalette
[iIndex
][2]);
252 (void)tSkipBytes(pFile
, iPadding
);
254 } /* end of vDecode8bpp */
257 * vDecode24bpp - decode an uncompressed 24 bits per pixel image
260 vDecode24bpp(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
262 int iX
, iY
, iTripleWidth
, iByteWidth
, iOffset
, iPadding
;
263 int iRed
, iGreen
, iBlue
;
265 DBG_MSG("vDecode24bpp");
268 fail(pucData
== NULL
);
271 iByteWidth
= iGetByteWidth(pImg
);
273 iTripleWidth
= pImg
->iWidth
* 3;
274 iPadding
= ROUND4(iTripleWidth
) - iTripleWidth
;
276 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
277 for (iX
= 0; iX
< pImg
->iWidth
; iX
++) {
278 iBlue
= iNextByte(pFile
);
282 iGreen
= iNextByte(pFile
);
286 iRed
= iNextByte(pFile
);
290 iOffset
= iY
* iByteWidth
+ iX
;
291 *(pucData
+ iOffset
) =
292 iReduceColor(iRed
, iGreen
, iBlue
);
294 (void)tSkipBytes(pFile
, iPadding
);
296 } /* end of vDecode24bpp */
299 * vDecodeRle4 - decode a RLE compressed 4 bits per pixel image
302 vDecodeRle4(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
304 int iX
, iY
, iByteWidth
, iOffset
, iTmp
, iHalfWidth
;
305 int iRun
, iRunLength
, iHalfRun
;
309 DBG_MSG("vDecodeRle4");
312 fail(pucData
== NULL
);
314 fail(pImg
->iColorsUsed
< 1 || pImg
->iColorsUsed
> 16);
316 DBG_DEC(pImg
->iWidth
);
317 DBG_DEC(pImg
->iHeight
);
319 iByteWidth
= iGetByteWidth(pImg
);
320 iHalfWidth
= (pImg
->iWidth
+ 1) / 2;
322 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
326 iRunLength
= iNextByte(pFile
);
327 if (iRunLength
== EOF
) {
330 if (iRunLength
!= 0) {
333 * RunLength pixels, all the "same" value
335 iTmp
= iNextByte(pFile
);
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
;
352 /* Literal or escape */
353 iRunLength
= iNextByte(pFile
);
354 if (iRunLength
== EOF
) {
357 if (iRunLength
== 0) { /* End of line escape */
359 } else if (iRunLength
== 1) { /* End of file escape */
361 } else if (iRunLength
== 2) { /* Delta escape */
362 DBG_MSG("RLE4: encountered delta escape");
364 } else { /* Literal packet */
365 iHalfRun
= (iRunLength
+ 1) / 2;
366 for (iRun
= 0; iRun
< iHalfRun
; iRun
++) {
367 iTmp
= iNextByte(pFile
);
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
;
380 /* Padding if the number of bytes is odd */
382 (void)tSkipBytes(pFile
, 1);
386 DBG_DEC_C(iX
!= iHalfWidth
, iX
);
388 } /* end of vDecodeRle4 */
391 * vDecodeRle8 - decode a RLE compressed 8 bits per pixel image
394 vDecodeRle8(FILE *pFile
, UCHAR
*pucData
, const imagedata_type
*pImg
)
396 int iX
, iY
, iRun
, iRunLength
, iOffset
, iIndex
, iByteWidth
;
399 DBG_MSG("vDecodeRle8");
402 fail(pucData
== NULL
);
404 fail(pImg
->iColorsUsed
< 1 || pImg
->iColorsUsed
> 256);
406 DBG_DEC(pImg
->iWidth
);
407 DBG_DEC(pImg
->iHeight
);
409 iByteWidth
= iGetByteWidth(pImg
);
411 for (iY
= pImg
->iHeight
- 1; iY
>= 0; iY
--) {
415 iRunLength
= iNextByte(pFile
);
416 if (iRunLength
== EOF
) {
419 if (iRunLength
!= 0) {
422 * RunLength pixels, all the same value
424 iIndex
= iNextByte(pFile
);
428 for (iRun
= 0; iRun
< iRunLength
; iRun
++) {
429 if (iX
< pImg
->iWidth
) {
430 iOffset
= iY
* iByteWidth
+ iX
;
431 *(pucData
+ iOffset
) =
433 pImg
->aucPalette
[iIndex
][0],
434 pImg
->aucPalette
[iIndex
][1],
435 pImg
->aucPalette
[iIndex
][2]);
441 /* Literal or escape */
442 iRunLength
= iNextByte(pFile
);
443 if (iRunLength
== EOF
) {
446 if (iRunLength
== 0) { /* End of line escape */
448 } else if (iRunLength
== 1) { /* End of file escape */
450 } else if (iRunLength
== 2) { /* Delta escape */
451 DBG_MSG("RLE8: encountered delta escape");
453 } else { /* Literal packet */
454 for (iRun
= 0; iRun
< iRunLength
; iRun
++) {
455 iIndex
= iNextByte(pFile
);
459 if (iX
< pImg
->iWidth
) {
460 iOffset
= iY
* iByteWidth
+ iX
;
461 *(pucData
+ iOffset
) =
463 pImg
->aucPalette
[iIndex
][0],
464 pImg
->aucPalette
[iIndex
][1],
465 pImg
->aucPalette
[iIndex
][2]);
469 /* Padding if the number of bytes is odd */
470 if (odd(iRunLength
)) {
471 (void)tSkipBytes(pFile
, 1);
475 DBG_DEC_C(iX
!= pImg
->iWidth
, iX
);
477 } /* end of vDecodeRle8 */
479 #if 0 /* defined(DEBUG) */
481 vCopy2File(UCHAR
*pucSprite
, size_t tSpriteSize
)
487 sprintf(szFilename
, "<Wimp$ScrapDir>.sprt%04d", ++iPicCounter
);
488 pOutFile
= fopen(szFilename
, "wb");
489 if (pOutFile
== NULL
) {
493 for (iIndex
= 4; iIndex
< (int)tSpriteSize
; iIndex
++) {
494 if (putc(pucSprite
[iIndex
], pOutFile
) == EOF
) {
498 (void)fclose(pOutFile
);
499 vSetFiletype(szFilename
, FILETYPE_SPRITE
);
500 } /* end of vCopy2File */
504 * vDecodeDIB - decode a dib picture
507 vDecodeDIB(diagram_type
*pDiag
, FILE *pFile
, const imagedata_type
*pImg
)
509 sprite_areainfo
*pSprite
;
510 UCHAR
*pucPalette
, *pucData
;
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));
523 /* Create an blank sprite */
524 pSprite
= pCreateBlankSprite(pImg
, &tSpriteSize
);
525 pucPalette
= (UCHAR
*)pSprite
+
526 pSprite
->firstoffset
+ sizeof(sprite_header
);
528 /* Add the pixel information */
529 switch (pImg
->uiBitsPerComponent
) {
531 fail(pImg
->eCompression
!= compression_none
);
532 pucData
= pucPalette
+ 2 * 8;
533 vDecode1bpp(pFile
, pucData
, pImg
);
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
);
542 vDecode4bpp(pFile
, pucData
, pImg
);
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
);
552 vDecode8bpp(pFile
, pucData
, pImg
);
556 fail(pImg
->eCompression
!= compression_none
);
557 pucData
= pucPalette
+ 0 * 8;
558 vDecode24bpp(pFile
, pucData
, pImg
);
561 DBG_DEC(pImg
->uiBitsPerComponent
);
565 #if 0 /* defined(DEBUG) */
566 vCopy2File((UCHAR
*)pSprite
, tSpriteSize
);
569 /* Add the sprite to the Draw file */
570 vImage2Diagram(pDiag
, pImg
,
571 (UCHAR
*)pSprite
+ pSprite
->firstoffset
,
572 tSpriteSize
- pSprite
->firstoffset
);
574 /* Clean up before you leave */
575 pSprite
= xfree(pSprite
);
576 } /* end of vDecodeDIB */
579 * bTranslateDIB - translate a DIB picture
581 * This function translates a picture from dib to sprite
583 * return TRUE when sucessful, otherwise FALSE
586 bTranslateDIB(diagram_type
*pDiag
, FILE *pFile
,
587 ULONG ulFileOffset
, const imagedata_type
*pImg
)
589 /* Seek to start position of DIB data */
590 if (!bSetDataOffset(pFile
, ulFileOffset
)) {
594 vDecodeDIB(pDiag
, pFile
, pImg
);
597 } /* end of bTranslateDIB */