- Fix palettes that don't have the lower nibble of each component
[AROS.git] / workbench / classes / datatypes / ilbm / ilbmclass.c
blob0e94d17cb397ae20d4d1598ae8a15a55ec2c4aec
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /**********************************************************************/
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <exec/types.h>
13 #include <exec/memory.h>
14 #include <dos/dostags.h>
15 #include <graphics/gfxbase.h>
16 #include <graphics/rpattr.h>
17 #include <graphics/modeid.h>
18 #include <intuition/imageclass.h>
19 #include <intuition/icclass.h>
20 #include <intuition/gadgetclass.h>
21 #include <intuition/cghooks.h>
22 #include <datatypes/datatypesclass.h>
23 #include <datatypes/pictureclass.h>
25 #include <clib/alib_protos.h>
26 #include <proto/exec.h>
27 #include <proto/dos.h>
28 #include <proto/intuition.h>
29 #include <proto/graphics.h>
30 #include <proto/utility.h>
31 #include <proto/iffparse.h>
32 #include <proto/datatypes.h>
34 #ifdef __AROS__
35 #include <aros/symbolsets.h>
36 ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);
37 #else
38 #include "compilerspecific.h"
39 #endif
41 #include "debug.h"
43 #include "methods.h"
46 /**************************************************************************************************/
48 struct FileBitMapHeader
50 UBYTE bmh_Width[2];
51 UBYTE bmh_Height[2];
52 UBYTE bmh_Left[2];
53 UBYTE bmh_Top[2];
54 UBYTE bmh_Depth;
55 UBYTE bmh_Masking;
56 UBYTE bmh_Compression;
57 UBYTE bmh_Pad;
58 UBYTE bmh_Transparent[2];
59 UBYTE bmh_XAspect;
60 UBYTE bmh_YAspect;
61 UBYTE bmh_PageWidth[2];
62 UBYTE bmh_PageHeight[2];
65 /**************************************************************************************************/
67 static LONG propchunks[] =
69 ID_ILBM, ID_BMHD,
70 ID_ILBM, ID_CMAP,
71 ID_ILBM, ID_CAMG
74 /**************************************************************************************************/
76 static UBYTE *UnpackByteRun1(UBYTE *source, UBYTE *dest, LONG unpackedsize)
78 UBYTE r;
79 BYTE c;
81 for(;;)
83 c = (BYTE)(*source++);
84 if (c >= 0)
86 while(c-- >= 0)
88 *dest++ = *source++;
89 if (--unpackedsize <= 0) return source;
92 else if (c != -128)
94 c = -c;
95 r = *source++;
97 while(c-- >= 0)
99 *dest++ = r;
100 if (--unpackedsize <= 0) return source;
106 /**************************************************************************************************/
108 static BOOL ReadBitMapPic(Class *cl, Object *o, struct IFFHandle *handle, struct BitMapHeader *bmhd,
109 struct FileBitMapHeader *file_bmhd, struct ContextNode *body_cn)
111 struct BitMap *bm;
112 UBYTE *src, *body, *uncompress_buf;
113 LONG y, p, w16, bm_bpr, body_bpr, copy_bpr, totdepth;
115 totdepth = bmhd->bmh_Depth;
116 if (file_bmhd->bmh_Masking == mskHasMask) totdepth++;
118 w16 = (bmhd->bmh_Width + 15) & ~15;
119 body_bpr = w16 / 8;
121 p = body_cn->cn_Size;
122 if ((file_bmhd->bmh_Compression == cmpByteRun1))
124 p += body_bpr * totdepth;
127 body = AllocVec(p, MEMF_ANY);
128 if (!body)
130 SetIoErr(ERROR_NO_FREE_STORE);
131 return FALSE;
134 if (ReadChunkBytes(handle, body, body_cn->cn_Size) != body_cn->cn_Size)
136 FreeVec(body);
137 SetIoErr(ERROR_UNKNOWN);
138 return FALSE;
141 bm = AllocBitMap(bmhd->bmh_Width, bmhd->bmh_Height, bmhd->bmh_Depth, BMF_CLEAR, NULL);
142 if (!bm)
144 FreeVec(body);
145 SetIoErr(ERROR_NO_FREE_STORE);
146 return FALSE;
149 bm_bpr = bm->BytesPerRow;
150 copy_bpr = (body_bpr < bm_bpr) ? body_bpr : bm_bpr;
152 switch(file_bmhd->bmh_Compression)
154 case cmpNone:
155 src = body;
156 for(y = 0; y < bmhd->bmh_Height; y++)
158 for(p = 0; p < bmhd->bmh_Depth; p++)
160 UBYTE *dest;
162 dest = bm->Planes[p] + y * bm_bpr;
164 CopyMem(src, dest, copy_bpr);
165 src += body_bpr;
168 if (file_bmhd->bmh_Masking == mskHasMask) src += body_bpr;
170 break;
172 case cmpByteRun1:
173 uncompress_buf = body + body_cn->cn_Size;
174 src = body;
176 for(y = 0; y < bmhd->bmh_Height; y++)
178 UBYTE *copysrc = uncompress_buf;
180 src = UnpackByteRun1(src, uncompress_buf, body_bpr * totdepth);
182 for(p = 0; p < bmhd->bmh_Depth; p++)
184 UBYTE *dest;
186 dest = bm->Planes[p] + y * bm_bpr;
188 CopyMem(copysrc, dest, copy_bpr);
189 copysrc += body_bpr;
193 break;
195 } /* switch(file_bmhd->bmh_Compression) */
197 SetDTAttrs(o, NULL, NULL, PDTA_BitMap, (IPTR)bm, TAG_DONE);
199 FreeVec(body);
200 SetIoErr(0);
202 return TRUE;
205 /**************************************************************************************************/
207 const UBYTE bitmask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0 };
209 static BOOL ReadRGBPic(Class *cl, Object *o, struct IFFHandle *handle, struct BitMapHeader *bmhd,
210 struct FileBitMapHeader *file_bmhd, struct ContextNode *body_cn, UBYTE *coltab)
212 UBYTE *src, *srcline, *srclinestart, *chunkystart, *chunky, *body, *compressed=0, *uncompressed=0, *maskptr;
213 int width, height, numplanes, mask, hamrot1, hamrot2;
214 LONG x, y, p, w16, body_bpr, bodysize;
215 ULONG rgb;
216 UBYTE r, g, b, hmask, mmask;
217 BOOL compress;
219 width = bmhd->bmh_Width;
220 height = bmhd->bmh_Height;
221 numplanes = bmhd->bmh_Depth;
222 w16 = (width + 15) & ~15;
223 body_bpr = w16 / 8;
224 bodysize = body_cn->cn_Size;
226 p = bodysize + width * 3;
227 if ((file_bmhd->bmh_Compression == cmpByteRun1))
229 p += body_bpr * numplanes;
232 body = AllocVec(p, MEMF_ANY);
233 if (!body)
235 SetIoErr(ERROR_NO_FREE_STORE);
236 return FALSE;
239 // D(bug("ilbm.datatype/ReadRGB: Width %d Height %d Depth %d body_bpr %ld bodysize %ld p %ld body %lx\n", width, height, numplanes, body_bpr, bodysize, p, body));
241 if (ReadChunkBytes(handle, body, bodysize) != bodysize)
243 FreeVec(body);
244 SetIoErr(ERROR_UNKNOWN);
245 return FALSE;
248 hamrot1 = 10 - numplanes;
249 hamrot2 = numplanes - 2;
250 mmask = 0xff << (numplanes - 6);
251 hmask = ~mmask;
252 compress = FALSE;
253 switch( file_bmhd->bmh_Compression )
255 case cmpByteRun1:
256 compressed = body;
257 uncompressed = body + bodysize + width * 3;
258 compress = TRUE;
259 case cmpNone:
260 src = body;
261 chunkystart = body + bodysize;
262 for(y = 0; y < height; y++)
264 chunky = chunkystart;
265 srclinestart = src;
266 if( compress )
268 compressed = UnpackByteRun1(compressed, uncompressed, body_bpr * numplanes);
269 srclinestart = uncompressed;
271 r = g = b = 0;
272 maskptr = (UBYTE *) bitmask;
273 for(x = 0; x < width; x++)
275 mask = *maskptr++;
276 if( !mask )
278 maskptr = (UBYTE *) bitmask;
279 mask = *maskptr++;
280 srclinestart++;
282 srcline = srclinestart;
283 rgb = 0;
284 for(p = 0; p < numplanes; p++)
286 rgb = (rgb >> 1) | (*srcline & mask ? 0x800000 : 0);
287 srcline += body_bpr;
289 // D(bug("ilbm.datatype/ReadRGB: RGB %06lx mask %02x srcline %lx chunky %lx\n", rgb, mask, srcline, chunky));
291 /* Process HAM or RGB data (a color table implies HAM) */
292 if( coltab )
294 rgb >>= 14;
295 rgb |= (rgb & 0xff) >> hamrot2;
296 switch( rgb & 0x300 )
298 case 0x000:
299 rgb >>= hamrot1;
300 rgb *= 3;
301 *chunky++ = r = coltab[rgb++];
302 *chunky++ = g = coltab[rgb++];
303 *chunky++ = b = coltab[rgb];
304 break;
305 case 0x100:
306 *chunky++ = r;
307 *chunky++ = g;
308 *chunky++ = b = rgb & mmask | b & hmask;
309 break;
310 case 0x200:
311 *chunky++ = r = rgb & mmask | r & hmask;
312 *chunky++ = g;
313 *chunky++ = b;
314 break;
315 case 0x300:
316 *chunky++ = r;
317 *chunky++ = g = rgb & mmask | g & hmask;
318 *chunky++ = b;
319 break;
322 else
324 *chunky++ = rgb & 0xff;
325 *chunky++ = (rgb >> 8) & 0xff;
326 *chunky++ = (rgb >> 16) & 0xff;
330 if( !DoSuperMethod(cl, o,
331 PDTM_WRITEPIXELARRAY, /* Method_ID */
332 (IPTR) chunkystart, /* PixelData */
333 PBPAFMT_RGB, /* PixelFormat */
334 width*3, /* PixelArrayMod (number of bytes per row) */
335 0, /* Left edge */
336 y, /* Top edge */
337 width, /* Width */
338 1)) /* Height (here: one line) */
340 D(bug("ilbm.datatype/ReadRGB: WRITEPIXELARRAY failed\n"));
341 FreeVec(body);
342 SetIoErr(ERROR_UNKNOWN);
343 return FALSE;
346 src += body_bpr * numplanes;
348 break;
349 } /* switch(file_bmhd->bmh_Compression) */
351 FreeVec(body);
352 SetIoErr(0);
354 return TRUE;
357 /**************************************************************************************************/
359 static void FixColRegs(ULONG numcolors, UBYTE *srcstart)
361 WORD i;
362 UBYTE n = 0, *src;
364 /* Check if all color elements have an empty lower nibble */
365 src = srcstart;
366 for (i = 0; i < numcolors * 3; i++)
367 n |= *src++;
368 src = srcstart;
370 /* If so, scale all color elements */
371 if ((n & 0xf) == 0)
373 for (i = 0; i < numcolors * 3; i++)
375 n = *src;
376 n |= n >> 4;
377 *src++ = n;
382 /**************************************************************************************************/
384 static void CopyColRegs(Object *o, ULONG numcolors, UBYTE *srcstart, BOOL ehb)
386 struct ColorRegister *colorregs;
387 ULONG *cregs;
389 SetDTAttrs(o, NULL, NULL, PDTA_NumColors, numcolors, TAG_DONE);
391 if (GetDTAttrs(o, PDTA_ColorRegisters , (IPTR)&colorregs,
392 PDTA_CRegs , (IPTR)&cregs ,
393 TAG_DONE ) == 2)
395 if (colorregs && cregs)
397 LONG i, j;
398 int cnt = 0;
399 int r, g, b;
400 UBYTE *src;
402 if( ehb )
404 cnt = 1;
406 for(j = 0; j <= cnt; j++)
408 src = srcstart;
409 for(i = 0; i < numcolors; i++)
411 r = *src++;
412 g = *src++;
413 b = *src++;
415 /* Halve the brightness on the second (EHB) round */
416 if( j )
418 r >>= 1;
419 g >>= 1;
420 b >>= 1;
423 colorregs->red = r;
424 colorregs->green = g;
425 colorregs->blue = b;
426 colorregs++;
428 *cregs++ = (ULONG)r * 0x01010101;
429 *cregs++ = (ULONG)g * 0x01010101;
430 *cregs++ = (ULONG)b * 0x01010101;
437 /**************************************************************************************************/
438 /**************************************************************************************************/
440 static BOOL ReadILBM(Class *cl, Object *o)
442 struct FileBitMapHeader *file_bmhd;
443 struct BitMapHeader *bmhd;
444 struct IFFHandle *handle;
445 struct StoredProperty *bmhd_prop, *cmap_prop, *camg_prop;
446 struct ContextNode *cn;
447 ULONG numcolors;
448 IPTR sourcetype;
449 LONG error;
451 D(bug("ilbm.datatype/ReadILBM()\n"));
453 if (GetDTAttrs(o, DTA_SourceType , (IPTR)&sourcetype ,
454 DTA_Handle , (IPTR)&handle ,
455 PDTA_BitMapHeader , (IPTR)&bmhd ,
456 TAG_DONE ) != 3)
458 SetIoErr(ERROR_OBJECT_NOT_FOUND);
459 return FALSE;
462 if ((sourcetype != DTST_FILE) && (sourcetype != DTST_CLIPBOARD))
464 SetIoErr(ERROR_OBJECT_NOT_FOUND);
465 return FALSE;
468 if (!handle || !bmhd)
470 SetIoErr(ERROR_OBJECT_NOT_FOUND);
471 return FALSE;
474 if (PropChunks(handle, propchunks, 3) != 0)
476 SetIoErr(ERROR_NO_FREE_STORE);
477 D(bug("ilbm.datatype error propchunks\n"));
478 return FALSE;
481 if (StopChunk(handle, ID_ILBM, ID_BODY) != 0)
483 SetIoErr(ERROR_NO_FREE_STORE);
484 D(bug("ilbm.datatype error stopchunks\n"));
485 return FALSE;
488 error = ParseIFF(handle, IFFPARSE_SCAN);
489 if (error)
491 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
492 D(bug("ilbm.datatype error parseiff\n"));
493 return FALSE;
496 bmhd_prop = FindProp(handle, ID_ILBM, ID_BMHD);
497 cmap_prop = FindProp(handle, ID_ILBM, ID_CMAP);
498 camg_prop = FindProp(handle, ID_ILBM, ID_CAMG);
500 cn = CurrentChunk(handle);
501 if ((cn->cn_Type != ID_ILBM) ||
502 (cn->cn_ID != ID_BODY) ||
503 (bmhd_prop == NULL))
505 SetIoErr(ERROR_REQUIRED_ARG_MISSING);
506 D(bug("ilbm.datatype error currentchunk\n"));
507 return FALSE;
510 file_bmhd = (struct FileBitMapHeader *)bmhd_prop->sp_Data;
511 bmhd->bmh_Width = bmhd->bmh_PageWidth = file_bmhd->bmh_Width [0] * 256 + file_bmhd->bmh_Width [1];
512 bmhd->bmh_Height = bmhd->bmh_PageHeight = file_bmhd->bmh_Height[0] * 256 + file_bmhd->bmh_Height[1];
513 bmhd->bmh_Depth = file_bmhd->bmh_Depth;
514 bmhd->bmh_Masking = file_bmhd->bmh_Masking;
515 bmhd->bmh_Transparent = file_bmhd->bmh_Transparent[0] * 256 + file_bmhd->bmh_Transparent[1];
518 IPTR name = (IPTR) NULL;
520 GetDTAttrs(o, DTA_Name, (IPTR)&name, TAG_DONE);
522 SetDTAttrs(o, NULL, NULL, DTA_ObjName, name,
523 DTA_NominalHoriz, bmhd->bmh_Width ,
524 DTA_NominalVert , bmhd->bmh_Height,
525 TAG_DONE);
528 if ((file_bmhd->bmh_Depth == 24) && (file_bmhd->bmh_Compression <= 1))
530 D(bug("ilbm.datatype/ReadILBM: 24 bit\n"));
531 if( !ReadRGBPic(cl, o, handle, bmhd, file_bmhd, cn, NULL) )
533 D(bug("ilbm.datatype error readrgbpic\n"));
534 return FALSE;
537 else if ( (file_bmhd->bmh_Depth <= 8) && (file_bmhd->bmh_Compression <= 1) && cmap_prop )
539 UBYTE *data;
540 BOOL ham = FALSE;
541 BOOL ehb = FALSE;
543 if ( camg_prop && (camg_prop->sp_Size == 4) )
545 ULONG mode;
547 data = (UBYTE *)camg_prop->sp_Data;
548 mode = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3];
549 if (mode & HAM_KEY)
551 ham = TRUE;
553 if (mode & EXTRAHALFBRITE_KEY)
555 ehb = TRUE;
557 D(bug("ilbm.datatype/ReadILBM: modeid %08lx%s%s\n", mode, ham ? " HAM" : "", ehb ? " EHB" : ""));
560 numcolors = cmap_prop->sp_Size / 3;
561 D(bug("ilbm.datatype/ReadILBM: %d bit %d colors\n", (int)file_bmhd->bmh_Depth, numcolors));
562 data = (UBYTE *)cmap_prop->sp_Data;
563 FixColRegs(numcolors, data);
564 CopyColRegs(o, numcolors, data, ehb);
566 if ( ham )
568 /* picture.datatype can't cope with a transparent colour when we
569 * convert a HAM image to an RGB image */
570 if (bmhd->bmh_Masking == mskHasTransparentColor)
571 bmhd->bmh_Masking = mskNone;
573 if( !ReadRGBPic(cl, o, handle, bmhd, file_bmhd, cn, (UBYTE *)cmap_prop->sp_Data) )
575 D(bug("ilbm.datatype error readrgbpic\n"));
576 return FALSE;
578 bmhd->bmh_Depth = 24;
580 else
582 if( !ReadBitMapPic(cl, o, handle, bmhd, file_bmhd, cn) )
584 D(bug("ilbm.datatype error readbitmappic\n"));
585 return FALSE;
589 else
591 D(bug("ilbm.datatype unknown\n"));
592 SetIoErr(ERROR_NOT_IMPLEMENTED);
593 return FALSE;
596 return TRUE;
599 /**************************************************************************************************/
601 IPTR ILBM__OM_NEW(Class *cl, Object *o, struct opSet *msg)
603 IPTR retval;
605 retval = DoSuperMethodA(cl, o, (Msg)msg);
606 if (retval)
608 if (!ReadILBM(cl, (Object *)retval))
610 CoerceMethod(cl, (Object *)retval, OM_DISPOSE);
611 retval = 0;
615 return retval;
618 /**************************************************************************************************/