home *** CD-ROM | disk | FTP | other *** search
- /*
- ** our include
- */
-
- #include "classbase.h"
-
- /*
- ** structure(s)
- */
-
- struct ReadData {
- ULONG width,
- height,
- depth,
- padwidth,
- mode,
- gray,
- comp,
- fmt,
- ham;
- APTR obj,
- pool,
- bmhd,
- handle;
- ULONG title;
- union {
- struct RastPort rp[2];
- UBYTE buf[64];
- ULONG p[2];
- } u;
- };
-
- #define r_fh 0
- #define r_src 1
- #define r_lev 0
- #define r_num 1
- #define r_col 0
- #define r_crg 1
-
- struct SaveData {
- ULONG width,
- height,
- depth,
- padwidth,
- numcolors,
- fmt;
- APTR bm,
- pool,
- handle,
- cmap;
- BYTE isHAM,
- isEHB,
- pad[2];
- };
-
- struct hamData {
- UBYTE *cmap;
- ULONG bits,
- mask,
- shift;
- };
-
- #define HD ((struct hamData *)outbuf)[-1]
-
- /*
- ** functions for asynchronous file I/O
- */
-
- #if !defined(ALL_IN_ONE)
-
- APTR OpenFFR(APTR,APTR,LONG,BPTR);
- LONG FFRGetC(APTR);
- LONG FFRRead(APTR,APTR,LONG);
- LONG FFRWrite(APTR,APTR,LONG);
- LONG CloseFFR(APTR);
-
- /*
- ** functions for HAM encoding
- */
-
- VOID CreateHAM6Line(UBYTE *,UBYTE *,UBYTE *,UBYTE *,LONG,ULONG);
- VOID CreateHAM8Line(UBYTE *,UBYTE *,UBYTE *,UBYTE *,LONG,ULONG);
-
- #endif
-
- /*
- ** cybergfx defines for picture.datatype V43
- */
-
- #define RECTFMT_RGB 0
- #define RECTFMT_LUT8 3
-
- /*
- ** easy access of a char-array as a "structure" (IJG sources 5.0b)
- */
-
- #define UCH(x) \
- ((ULONG) (x))
-
- #define GET_2B(array,offset) \
- ((ULONG) (UCH(array[offset]) | (UCH(array[offset+1])<<8)))
-
- #define GET_4B(array,offset) \
- ((ULONG) (GET_2B(array,offset) | (GET_2B(array,offset+2)<<16)))
-
- #define PUT_1B(array,offset,value) \
- array[offset] = (UBYTE)((value) & 0xff);
-
- #define PUT_2B(array,offset,value) \
- { UWORD v = value; \
- PUT_1B(array,offset,v); PUT_1B(array,offset+1,v>>=8); }
-
- #define PUT_4B(array,offset,value) \
- { ULONG v = value; \
- PUT_1B(array,offset+0,v>>=0); PUT_1B(array,offset+1,v>>=8); \
- PUT_1B(array,offset+2,v>>=8); PUT_1B(array,offset+3,v>>=8); }
-
- /*
- ** compression types for BMPs
- */
-
- enum { BI_RGB=0,BI_RLE8=1,BI_RLE4=2 };
-
- /*
- ** redirect library bases
- */
-
- #define SysBase cb->SysBase
- #define DOSBase cb->DOSBase
- #define GfxBase cb->GfxBase
- #define IntuitionBase cb->IntuitionBase
- #define DataTypesBase cb->DataTypesBase
- #define PictureClass cb->PictureClass
-
- #if defined(__GNUC__)
-
- /*
- ** set dt attribute(s)
- */
-
- STATIC ULONG set_dt_attrs(struct ClassBase *cb,Object *obj,Tag tag,...)
- {
- return SetDTAttrsA(obj,NULL,NULL,(struct TagItem *)&tag);
- }
-
- #define SetDTAttrs(a,b,c,d...) set_dt_attrs(cb,a,d)
-
- /*
- ** get dt attribute(s)
- */
-
- STATIC ULONG get_dt_attrs(struct ClassBase *cb,Object *obj,Tag tag,...)
- {
- return GetDTAttrsA(obj,(struct TagItem *)&tag);
- }
-
- #define GetDTAttrs(a...) get_dt_attrs(cb,a)
-
- #endif /* __GNUC__ */
-
- /*
- ** get and parse user settings then start decoder/encoder
- */
-
- #define PREFSFILE (STRPTR)"classes/datatypes/bmp.prefs"
-
- enum {
- RD_V42MODE=0,RD_GRAY,RD_HAM,ARG_LAST
- };
-
- #define TEMPLATE "V42MODE/S,GRAY/S,HAM/K/N"
-
- STATIC LONG startup(struct ClassBase *cb,APTR data,LONG (*start)(struct ClassBase *,LONG *,APTR),APTR pool)
- { LONG prefs[ARG_LAST],result,len;
- struct RDArgs *rdarg;
- UBYTE p[4],*buf;
-
- /* clear argument vector */
- { ULONG *m=(ULONG *)prefs,l=sizeof(prefs)/sizeof(prefs[0]);
- do;while(*m++=0,--l); }
-
- /* get && parse prefs file */
- if (rdarg=NULL,GetVar(PREFSFILE,&p[0],1,0) >= 0)
- if ((buf=AllocPooled(pool,len=1+IoErr())) != NULL)
- if ((len=GetVar(PREFSFILE,buf,len,0)) >= 0)
- if (buf[len++]='\n',(rdarg=AllocDosObject(DOS_RDARGS,NULL)) != NULL) {
- rdarg->RDA_Source.CS_Buffer = buf;
- rdarg->RDA_Source.CS_Length = len;
- rdarg->RDA_Flags = RDAF_NOPROMPT;
- ReadArgs((STRPTR)TEMPLATE,&prefs[0],rdarg);
- }
-
- /* start decoder/encoder */
- result = (*start)(cb,&prefs[0],data);
-
- /* free args */
- if (rdarg) {
- FreeArgs(rdarg); FreeDosObject(DOS_RDARGS,rdarg);
- }
-
- /* status */
- return result;
- }
-
- /*
- ** do nothing
- */
-
- STATIC VOID convert_stub(VOID)
- {
- /* no work */
- }
-
- /*
- ** change color order (BGR -> RGB / RGB -> BGR)
- */
-
- STATIC VOID convert_24bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- {
- do {
- UBYTE c = pixelbuf[0]; pixelbuf[0] = pixelbuf[2]; pixelbuf[2] = c; pixelbuf += 3;
- } while (--width);
- }
-
- /*
- ** reduce 24bit data to 8bit grayscale
- */
-
- STATIC VOID grayscale(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG r,c;
-
- do {
- c = *pixelbuf++; c *= 5; r = *pixelbuf++; c += 16*r; r = *pixelbuf++; c += 11*r; c >>= 5;
- } while (*outbuf++=c,--width);
- }
-
- /*
- ** RGB -> HAM8 encoding
- */
-
- STATIC VOID RGBtoHAM8(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- {
- CreateHAM8Line(pixelbuf+2,pixelbuf+1,pixelbuf+0,outbuf,3,width);
- }
-
- /*
- ** RGB -> HAM6 encoding
- */
-
- STATIC VOID RGBtoHAM6(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- {
- CreateHAM6Line(pixelbuf+2,pixelbuf+1,pixelbuf+0,outbuf,3,width);
- }
-
- /*
- ** perform a simple copy (outbuf is WritePixelLine8() aware...)
- */
-
- STATIC VOID convert_8bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- {
- do;while(*outbuf++=*pixelbuf++,--width);
- }
-
- /*
- ** expand every 4 bits to a byte
- */
-
- STATIC VOID decode_4bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG i;
- UBYTE c;
-
- for(i=width/2; i!=0; i--) {
- c = *pixelbuf++; *outbuf++ = (c >> 4); *outbuf++ = (c & 0xf);
- }
- if (width&1) {
- c = *pixelbuf; c >>= 4; *outbuf = c;
- }
- }
-
- /*
- ** expand every bit to a byte
- */
-
- STATIC VOID decode_1bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG i,j;
- UBYTE c;
-
- for(i=width/8; i!=0; i--)
- for(c=*pixelbuf++,j=8; j!=0; c<<=1,j--)
- *outbuf++ = ((c & 0x80) ? 1 : 0);
- if ((i=width&7))
- for(c=*pixelbuf; i!=0; c<<=1,i--)
- *outbuf++ = ((c & 0x80) ? 1 : 0);
- }
-
- /*
- ** handle 8 bit compression
- */
-
- STATIC LONG decompress_8bit(APTR handle,UBYTE *buffer,ULONG width,ULONG height)
- { LONG (*get)(),xpos,a,c,i;
- UBYTE *end;
-
- end = buffer + width * height; xpos = 0; get = FFRGetC;
-
- do {
-
- if ((c=(*get)(handle)) < 0) return c;
-
- if (!c) {
-
- if ((c=(*get)(handle)) < 0) return c;
-
- if (!c) {
- buffer += (width-xpos); height--; xpos = 0;
- }
- else if (!--c) {
- break;
- }
- else if (!--c) {
- a = (*get)(handle); xpos += a; buffer += a;
- if ((c=(*get)(handle)) < 0) return c;
- height -= c; buffer += width * c;
- }
- else {
- c += 2; i = c;
- do {
- *buffer++ = (*get)(handle);
- } while (--i);
- if (c&1) (*get)(handle);
- xpos += c;
- }
- }
- else {
- i = c; a = (*get)(handle);
- do {
- *buffer++ = a;
- } while (--i);
- xpos += c;
- }
- } while (height && buffer < end);
-
- return 0;
- }
-
- /*
- ** handle 4 bit compression
- */
-
- STATIC LONG decompress_4bit(APTR handle,UBYTE *buffer,ULONG width,ULONG height)
- { LONG (*get)(),xpos,a,b,c,i;
- UBYTE *end;
-
- end = buffer + width * height; xpos = 0; get = FFRGetC;
-
- do {
-
- if ((c=(*get)(handle)) < 0) return c;
-
- if (!c) {
-
- if ((c=(*get)(handle)) < 0) return c;
-
- if (!c) {
- buffer += (width-xpos); height--; xpos = 0;
- }
- else if (!--c) {
- break;
- }
- else if (!--c) {
- a = (*get)(handle); xpos += a; buffer += a;
- if ((c=(*get)(handle)) < 0) return c;
- height -= c; buffer += width * c;
- }
- else {
- c += 2; i = 0;
- do {
- a = (*get)(handle); b = a & 0x0f; a >>= 4;
- *buffer++ = a; *buffer++ = b;
- i += 2;
- } while (i < c);
- if (((c&3) == 1) || ((c&3) == 2)) (*get)(handle);
- xpos += c; if (i > c) --buffer;
- }
- }
- else {
- i = 0; b = (*get)(handle); a = b & 0xf; b >>= 4;
- do {
- *buffer++ = b; *buffer++ = a; i += 2;
- } while (i < c);
- xpos += c; if (i > c) --buffer;
- }
- } while (height && buffer < end);
-
- return 0;
- }
-
- /*
- ** compressed image (4 or 8 bit)
- */
-
- STATIC LONG decode_rle_v42(struct ClassBase *cb,struct ReadData *rd,APTR lbuf)
- { LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
- UBYTE *buffer;
- ULONG height;
- LONG ret;
-
- if ((buffer=AllocPooled(rd->pool,(height=rd->height)*rd->width+260)) != NULL) {
-
- decode = decompress_4bit; if (rd->depth != 4) decode = decompress_8bit;
-
- if ((ret=(*decode)(rd->handle,buffer,rd->width,height)) == 0)
- do {
- convert_8bit(buffer,lbuf,rd->width);
- WritePixelLine8(&rd->u.rp[0],0,--height,rd->width,lbuf,&rd->u.rp[1]);
- buffer += rd->width;
- } while ((ret=height));
-
- return ret;
- }
-
- return ERROR_NO_FREE_STORE;
- }
-
- /*
- ** uncompressed image (1, 4 or 8 bit)
- */
-
- STATIC LONG decode_normal_v42(struct ClassBase *cb,struct ReadData *rd,APTR lbuf)
- { VOID (*convert)(UBYTE *,UBYTE *,ULONG);
- ULONG padwidth,height;
- UBYTE *buffer;
- LONG ret;
-
- if (buffer=lbuf,padwidth=rd->padwidth,convert=grayscale,!rd->gray)
- if (convert=RGBtoHAM6,rd->ham != 6)
- if (convert=RGBtoHAM8,rd->ham != 8)
- if (convert=(VOID (*)())convert_stub,rd->depth != 8) {
- buffer += rd->width; buffer -= padwidth; buffer += 8;
- if (convert=decode_4bit,rd->depth != 4)
- convert = decode_1bit;
- }
-
- height = rd->height;
- do {
- if (FFRRead(rd->handle,buffer,padwidth) != padwidth)
- break;
- (*convert)(buffer,lbuf,rd->width);
- WritePixelLine8(&rd->u.rp[0],0,--height,rd->width,lbuf,&rd->u.rp[1]);
- } while (height);
-
- if ((ret=height)) ret = -1; return ret;
- }
-
- /*
- ** obtain best modeID
- */
-
- INLINE ULONG GetBestModeID(struct ClassBase *cb,struct ReadData *rd,ULONG w,ULONG h)
- { UWORD id = LORES_KEY;
-
- if ((UWORD)w > 362)
- id = HIRES;
- if ((UWORD)h > 283)
- id |= LACE;
- if (rd->ham && ModeNotAvailable(id|=HAM))
- id &= ~HIRES;
- return id;
- }
-
- /*
- ** decode picture (V42 interface)
- */
-
- STATIC LONG decode_picture_v42(struct ClassBase *cb,Object *obj,struct ReadData *rd)
- { LONG (*decode)(struct ClassBase *,struct ReadData *,APTR);
- ULONG height,size;
- UBYTE *lbuf;
- LONG ret = ERROR_NO_FREE_STORE;
-
- InitRastPort(&rd->u.rp[0]);
-
- if ((rd->u.rp[0].BitMap=AllocBitMap(rd->width,height=rd->height,rd->depth,BMF_CLEAR|BMF_DISPLAYABLE|BMF_MINPLANES,NULL)) != NULL) {
-
- InitRastPort(&rd->u.rp[1]);
-
- if ((rd->u.rp[1].BitMap=AllocBitMap(rd->width,1,rd->depth,BMF_CLEAR|BMF_MINPLANES,NULL)) != NULL) {
-
- if ((size=rd->width) < rd->padwidth)
- size = rd->padwidth;
-
- if ((lbuf=AllocPooled(rd->pool,(size+8+15)&~15)) != NULL) {
-
- if (decode=decode_normal_v42,rd->comp)
- decode = decode_rle_v42;
-
- if ((ret=(*decode)(cb,rd,lbuf)) == 0) {
-
- SetDTAttrs(rd->obj, NULL, NULL,
- PDTA_ModeID, GetBestModeID(cb,rd,rd->width,height),
- PDTA_BitMap, rd->u.rp[0].BitMap,
- DTA_NominalHoriz, rd->width,
- DTA_NominalVert, height,
- DTA_ObjName, rd->title,
- TAG_DONE);
-
- rd->u.rp[0].BitMap = NULL;
- }
- }
- FreeBitMap(rd->u.rp[1].BitMap);
- }
- FreeBitMap(rd->u.rp[0].BitMap);
- }
-
- return ret;
- }
-
- /*
- ** compressed image (4 or 8 bit)
- */
-
- STATIC LONG decode_rle_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
- { LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
- UBYTE *buffer;
- ULONG height;
- LONG ret;
-
- if ((buffer=AllocPooled(rd->pool,(height=rd->height)*rd->width+260)) != NULL) {
-
- decode = decompress_4bit; if (rd->depth != 4) decode = decompress_8bit;
-
- if ((ret=(*decode)(rd->handle,buffer,rd->width,height)) == 0)
- do {
- DoSuperMethod(PictureClass,obj,
- PDTM_WRITEPIXELARRAY,buffer,RECTFMT_LUT8,0,0,--height,rd->width,1);
- buffer += rd->width;
- } while ((ret=height));
-
- return ret;
- }
-
- return ERROR_NO_FREE_STORE;
- }
-
- /*
- ** uncompressed image (1, 4, 8 or 24 bit)
- */
-
- STATIC LONG decode_normal_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
- { VOID (*convert)(UBYTE *,UBYTE *,ULONG);
- ULONG padwidth,height,size;
- UBYTE *buffer,*lbuf;
- LONG ret = ERROR_NO_FREE_STORE;
-
- if ((size=rd->width) < (padwidth=rd->padwidth))
- size = padwidth;
-
- if ((lbuf=(buffer=AllocPooled(rd->pool,size+8))) != NULL) {
-
- if (convert=grayscale,!rd->gray)
- if (convert=convert_24bit,rd->fmt != RECTFMT_RGB)
- if (convert=(VOID (*)())convert_stub,rd->depth != 8) {
- buffer += rd->width; buffer -= padwidth; buffer += 8;
- if (convert=decode_4bit,rd->depth != 4)
- convert = decode_1bit;
- }
-
- height = rd->height; ret = -1;
- do {
- if (FFRRead(rd->handle,buffer,padwidth) != padwidth)
- return ret;
- (*convert)(buffer,lbuf,rd->width);
- DoSuperMethod(PictureClass,rd->obj,
- PDTM_WRITEPIXELARRAY,lbuf,rd->fmt,0,0,--height,rd->width,1);
- } while (height);
-
- ret = 0;
- }
-
- return ret;
- }
-
- /*
- ** decode picture (V43 interface)
- */
-
- STATIC LONG decode_picture_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
- { LONG (*decode)(struct ClassBase *,Object *,struct ReadData *);
- LONG ret;
-
- rd->u.p[r_lev] = 0; rd->u.p[r_num] = 0;
-
- SetDTAttrs(obj, NULL, NULL,
- PDTA_SourceMode, PMODE_V43,
- PDTA_ModeID, 0,
- DTA_ErrorLevel, &rd->u.p[r_lev],
- DTA_ErrorNumber, &rd->u.p[r_num],
- DTA_NominalHoriz, rd->width,
- DTA_NominalVert, rd->height,
- DTA_ObjName, rd->title,
- TAG_DONE);
-
- if (ret=rd->u.p[r_num],!rd->u.p[r_lev]) {
- if (decode=decode_normal_v43,rd->comp)
- decode = decode_rle_v43;
- ret = (*decode)(cb,obj,rd);
- }
-
- return ret;
- }
-
- /*
- ** extract all required information from the bmp header
- */
-
- STATIC LONG read_bmp_header(struct ClassBase *cb,LONG *prefs,APTR data)
- { struct ReadData *rd = (struct ReadData *)data;
- ULONG cmapentrysize,*methods,*cregs,tmp,val,r,g,b,c;
- struct BitMapHeader *bmhd;
- UBYTE *coltab,*cmap;
- LONG bfOffBits;
- LONG biSize;
- LONG biDepth;
- LONG biPlanes;
- LONG biCompression;
- LONG biClrUsed;
-
- /* preferences */
- if (rd->gray=prefs[RD_GRAY],!rd->gray && prefs[RD_HAM]) {
- if (val=*(ULONG *)prefs[RD_HAM],val != 6 && val != 8) val = 0;
- } else val = 0;
- rd->ham = val;
-
- if (val=~0,!prefs[RD_V42MODE] && (methods=GetDTMethods(rd->obj)))
- do;while(((val=*methods++) != ~0) && (val-=PDTM_WRITEPIXELARRAY));
- rd->mode = val;
-
- /* lets go */
- if (FFRRead(rd->handle,rd->u.buf,18) != 18)
- return FALSE;
-
- if (((UWORD)GET_2B(rd->u.buf,0)) != 0x4D42)
- return FALSE;
-
- bfOffBits = GET_4B(rd->u.buf,10) - ((biSize=GET_4B(rd->u.buf,14)) + 14);
-
- if (biSize != 12 && biSize != 40 && biSize != 64)
- return FALSE;
-
- if (FFRRead(rd->handle,rd->u.buf+4,biSize-=4) != biSize)
- return FALSE;
-
- if (biSize == 8) { /* OS/2 1.x */
- rd->width = GET_2B(rd->u.buf, 4);
- rd->height = GET_2B(rd->u.buf, 6);
- biDepth = GET_2B(rd->u.buf,10);
- biCompression = 0;
- biClrUsed = 0;
- cmapentrysize = 3;
- biPlanes = GET_2B(rd->u.buf, 8);
- }
- else { /* Windows 3.x or OS/2 2.x */
- rd->width = GET_4B(rd->u.buf, 4);
- rd->height = GET_4B(rd->u.buf, 8);
- biDepth = GET_2B(rd->u.buf,14);
- biCompression = GET_4B(rd->u.buf,16);
- biClrUsed = GET_4B(rd->u.buf,32);
- cmapentrysize = 4;
- biPlanes = GET_2B(rd->u.buf,12);
- }
-
- if (biPlanes != 1)
- return FALSE;
-
- if ((rd->comp=biCompression) &&
- ((biDepth == 4 && biCompression != BI_RLE4) || (biDepth == 8 && biCompression != BI_RLE8)))
- return FALSE;
-
- rd->padwidth = (((biDepth * rd->width) + 31) & ~31) / 8;
-
- if (val=RECTFMT_LUT8,biDepth != 1 && biDepth != 4 && biDepth != 8) {
-
- if (biDepth != 24)
- return FALSE;
-
- if ((biClrUsed=rd->ham))
- rd->mode=biDepth=biClrUsed,biClrUsed=1,biClrUsed<<=(biDepth-2);
-
- if (!biClrUsed && (rd->gray || (rd->gray=rd->mode,rd->gray)))
- biDepth=8,biClrUsed=256;
-
- val = RECTFMT_RGB;
- }
-
- bmhd = (struct BitMapHeader *)rd->bmhd;
- bmhd->bmh_Depth = rd->depth = biDepth;
- if ((bmhd->bmh_PageWidth=bmhd->bmh_Width=rd->width) == 0 ||
- (bmhd->bmh_PageHeight=bmhd->bmh_Height=rd->height) == 0)
- return FALSE;
-
- if ((rd->fmt=val) != RECTFMT_RGB) {
-
- if (biClrUsed > 256)
- return FALSE;
-
- if (biClrUsed <= 0)
- biClrUsed=1,biClrUsed<<=biDepth;
-
- if ((coltab=AllocPooled(rd->pool,val=biClrUsed*cmapentrysize)) == NULL)
- return FALSE;
-
- if (FFRRead(rd->handle,coltab,val) != val)
- return FALSE;
-
- bfOffBits -= val;
- }
-
- if (biClrUsed) {
-
- SetDTAttrs(rd->obj, NULL, NULL, PDTA_NumColors,(ULONG)biClrUsed, TAG_DONE);
- if (GetDTAttrs(rd->obj, PDTA_ColorRegisters,&rd->u.p[r_col],PDTA_CRegs,&rd->u.p[r_crg], TAG_DONE) != 2)
- return FALSE;
-
- /*
- ** do not use "struct ColorRegister" for cmap since with the amiga port
- ** of gcc a sizeof() for this structure is four and not three.. oh well
- */
-
- coltab += 2; cmap = (UBYTE *)rd->u.p[r_col]; cmapentrysize += 2; cregs = (ULONG *)rd->u.p[r_crg];
- if (c=0,rd->fmt == RECTFMT_RGB) {
- if (rd->ham)
- do {
- tmp = ((c * 255) / (biClrUsed - 1)) * 0x01010101;
- *cmap++ = tmp; *cregs++ = tmp;
- *cmap++ = tmp; *cregs++ = tmp;
- *cmap++ = tmp; *cregs++ = tmp;
- } while (++c < biClrUsed);
- else
- do {
- *cmap++ = c; *cregs++ = c;
- *cmap++ = c; *cregs++ = c;
- *cmap++ = c; *cregs++ = c;
- } while (c+=0x01010101,--biClrUsed);
- rd->fmt += RECTFMT_LUT8;
- }
- else {
- if (rd->gray)
- do {
- c = *coltab; c *= 11; r = *--coltab; c += 16*r; r = *--coltab; c += 5*r; c >>= 5; c *= 0x01010101;
- *cmap++ = c; *cregs++ = c;
- *cmap++ = c; *cregs++ = c;
- *cmap++ = c; *cregs++ = c;
- } while (coltab+=cmapentrysize,--biClrUsed);
- else
- do {
- *cmap++ = (r = * coltab); *cregs++ = (r *= 0x01010101);
- *cmap++ = (g = *--coltab); *cregs++ = (g *= 0x01010101);
- *cmap++ = (b = *--coltab); *cregs++ = (b *= 0x01010101);
- } while (coltab+=cmapentrysize,--biClrUsed);
- rd->ham = rd->gray = 0;
- }
- }
-
- if ((val=bfOffBits) > 0)
- do
- if (FFRGetC(rd->handle) < 0) break;
- while (--val);
-
- return (val <= 0 ? TRUE : FALSE);
- }
-
- /*
- ** load a picture
- */
-
- STATIC LONG LoadBMP(struct ClassBase *cb,Object *obj)
- { LONG (*decode)(struct ClassBase *,Object *,struct ReadData *);
- struct ReadData *rd;
- LONG error;
- APTR pool;
-
- if (error=ERROR_NO_FREE_STORE,pool=CreatePool(MEMF_CLEAR,4*1024,4*1024)) {
-
- if ((rd=AllocPooled(pool,sizeof(*rd)))) {
-
- rd->pool = pool; rd->bmhd = NULL; rd->u.p[r_fh] = 0; rd->u.p[r_src] = DTST_FILE; rd->title = 0;
-
- GetDTAttrs(rd->obj=obj,
- PDTA_BitMapHeader, &rd->bmhd,
- DTA_Handle, &rd->u.p[r_fh],
- DTA_SourceType, &rd->u.p[r_src],
- DTA_Name, &rd->title,
- TAG_DONE);
-
- if (error=0,rd->u.p[r_src] != DTST_RAM) {
-
- if (error=ERROR_OBJECT_WRONG_TYPE,rd->u.p[r_src] == DTST_FILE && rd->bmhd && rd->u.p[r_fh]) {
-
- if ((rd->handle=OpenFFR(cb,pool,FFR_MODE_READ,(BPTR)rd->u.p[r_fh]))) {
-
- if (startup(cb,rd,read_bmp_header,pool)) {
-
- if (decode=decode_picture_v42,!rd->mode)
- decode=decode_picture_v43;
- error = (*decode)(cb,obj,rd);
- }
- (VOID)CloseFFR(rd->handle);
- }
- else
- error = ERROR_NO_FREE_STORE;
- }
- }
- }
- DeletePool(pool);
- }
-
- if (error) {
- if (error > 0) SetIoErr(error); return FALSE;
- }
-
- return TRUE;
- }
-
- /*
- ** convert HAM to RGB
- */
-
- STATIC VOID HAMtoRGB(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG bits,mask,shift,pen,v;
- UBYTE *cmap,*p,r,g,b;
-
- shift = HD.shift; mask = HD.mask; bits = HD.bits; cmap = HD.cmap;
-
- for(r=*cmap++,g=*cmap++,b=*cmap,cmap-=2; width; width--) {
- if ((v=((pen=*pixelbuf++)>>bits)&3) == 0) {
- p = cmap+2*pen+pen; r = *p++; g = *p++; b = *p;
- }
- else {
- /*pen &= mask;*/ pen <<= shift;
- if (!--v)
- b = pen;
- else if (!--v)
- r = pen;
- else
- g = pen;
- }
- *outbuf++ = b; *outbuf++ = g; *outbuf++ = r;
- }
- }
-
- /*
- ** convert 2 bytes into one
- */
-
- STATIC VOID encode_4bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG i;
- UBYTE c;
-
- for(i=width/2; i!=0; i--) {
- c = *pixelbuf++ & 0xf; c <<= 4; c |= *pixelbuf++ & 0xf; *outbuf++ = c;
- }
- if (width&1) {
- c = *pixelbuf & 0xf; c <<= 4; *outbuf = c;
- }
- }
-
- /*
- ** convert 8 bytes into one
- */
-
- STATIC VOID encode_1bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
- { ULONG c,i,j;
-
- for(i=width/8; i!=0; *outbuf++=c,i--)
- for(c=0,j=0x80; j!=0; j>>=1)
- if (*pixelbuf++) c |= j;
- if ((i=width&7)) {
- for(c=0,j=0x80; i!=0; j>>=1,i--)
- if (*pixelbuf++) c |= j;
- *outbuf = c;
- }
- }
-
- /*
- ** encode picture (V42 interface)
- */
-
- STATIC LONG encode_picture_v42(struct ClassBase *cb,Object *obj,struct SaveData *sd)
- { VOID (*encode)(UBYTE *,UBYTE *,ULONG);
- ULONG *hd,b,d,height,padwidth;
- struct RastPort trp,rp;
- UBYTE *buffer,*lbuf;
- LONG ret = ERROR_NO_FREE_STORE;
-
- InitRastPort(&rp); rp.BitMap = sd->bm; InitRastPort(&trp); d = GetBitMapAttr(sd->bm,BMA_DEPTH);
-
- if ((trp.BitMap=AllocBitMap(sd->width,1,d,BMF_MINPLANES,sd->bm)) != NULL) {
-
- if ((lbuf=AllocPooled(sd->pool,((sd->width+15)&~15))) != NULL) {
-
- if ((hd=AllocPooled(sd->pool,sizeof(struct hamData)+(padwidth=sd->padwidth))) != NULL) {
-
- if (encode=HAMtoRGB,!sd->isHAM)
- if (encode=convert_8bit,sd->depth != 8)
- if (encode=encode_4bit,sd->depth != 4)
- encode = encode_1bit;
-
- *hd++ = (ULONG)sd->cmap; // cmap
- *hd++ = b = d - 2; // bits
- *hd++ = (1 << b) - 1; // mask
- *hd++ = 8 - b; // shift
-
- buffer = (UBYTE *)hd; height = sd->height;
- do {
- ReadPixelLine8(&rp,0,--height,sd->width,lbuf,&trp);
- (*encode)(lbuf,buffer,sd->width);
- if (FFRWrite(sd->handle,buffer,padwidth) != padwidth)
- break;
- } while (height);
-
- if ((ret=height))
- ret = -1;
- }
- }
- FreeBitMap(trp.BitMap);
- }
-
- return ret;
- }
-
- /*
- ** encode picture (V43 interface)
- */
-
- STATIC LONG encode_picture_v43(struct ClassBase *cb,Object *obj,struct SaveData *sd)
- { VOID (*encode)(UBYTE *,UBYTE *,ULONG);
- ULONG height,padwidth;
- UBYTE *buffer,*lbuf;
- LONG ret;
-
- if ((buffer=AllocPooled(sd->pool,padwidth=sd->padwidth)) != NULL) {
-
- if (lbuf=buffer,encode=convert_24bit,sd->fmt != RECTFMT_RGB)
- if (encode=(VOID (*)())convert_stub,sd->depth != 8) {
- if (encode=encode_4bit,sd->depth != 4)
- encode = encode_1bit;
- if ((lbuf=AllocPooled(sd->pool,sd->width)) == NULL) return ERROR_NO_FREE_STORE;
- }
-
- height = sd->height;
- do {
- DoSuperMethod(PictureClass,obj,
- PDTM_READPIXELARRAY,lbuf,sd->fmt,0,0,--height,sd->width,1);
- (*encode)(lbuf,buffer,sd->width);
- if (FFRWrite(sd->handle,buffer,padwidth) != padwidth)
- break;
- } while (height);
-
- if ((ret=height)) ret = -1; return ret;
- }
-
- return ERROR_NO_FREE_STORE;
- }
-
- /*
- ** setup and write bmp header
- */
-
- STATIC LONG write_bmp_header(struct ClassBase *cb,Object *obj,struct SaveData *sd)
- { ULONG bfSize,bfOffBits,biDepth,cnt,nc;
- UBYTE *header,*coltab,*cmap;
- LONG ret;
-
- if (nc=0,biDepth=24,cnt=0,!sd->isHAM && sd->depth != biDepth) {
- if (nc=sd->numcolors,sd->isEHB)
- nc += (cnt=nc);
- if (biDepth=1,nc > 2)
- if (biDepth=4,nc > 16)
- biDepth = 8;
- }
- sd->padwidth = (((sd->width * (sd->depth=biDepth)) + 31) & ~31) / 8;
-
- bfOffBits = 14 + 40 + 4*nc; bfSize = bfOffBits + sd->height * sd->padwidth;
-
- if ((header=AllocPooled(sd->pool,bfOffBits)) != NULL) {
-
- PUT_2B(header, 0, 0x4D42);
- PUT_4B(header, 2, bfSize);
- //PUT_4B(header, 6, 0);
- PUT_2B(header, 10, bfOffBits);
-
- PUT_1B(header, 14, 40);
- PUT_2B(header, 18, sd->width);
- PUT_2B(header, 22, sd->height);
- PUT_1B(header, 26, 1);
- PUT_1B(header, 28, biDepth);
-
- //PUT_1B(header, 30, BI_RGB);
- //PUT_4B(header, 34, 0);
- //PUT_4B(header, 38, 0);
- //PUT_4B(header, 42, 0);
- if (nc && (nc != (1<<biDepth)))
- PUT_2B(header, 46, nc);
- //PUT_4B(header, 50, 0);
-
- if (nc) {
-
- coltab = &header[14+40+2]; cmap = sd->cmap; if (cnt) nc = cnt;
- do {
- *coltab = *cmap++; *--coltab = *cmap++; *--coltab = *cmap++;
- } while (coltab+=4+2,--nc);
-
- if (cmap=sd->cmap,cnt)
- do {
- *coltab = *cmap++/2; *--coltab = *cmap++/2; *--coltab = *cmap++/2;
- } while (coltab+=4+2,--cnt);
-
- nc = RECTFMT_LUT8;
- }
- //else nc = RECTFMT_RGB;
- sd->fmt = nc;
-
- if ((ret=FFRWrite(sd->handle,header,bfOffBits)-bfOffBits))
- ret = -1;
- }
- else
- ret = ERROR_NO_FREE_STORE;
-
- return ret;
- }
-
- /*
- ** save a picture
- */
-
- #define DTSI(o) ((struct DTSpecialInfo *)(((struct Gadget *)o)->SpecialInfo))
-
- STATIC LONG SaveBMP(struct ClassBase *cb,Object *obj,struct dtWrite *dtw)
- { LONG (*encode)(struct ClassBase *,Object *,struct SaveData *);
- ULONG *methods,depth,mode,id;
- struct BitMapHeader *bmhd;
- struct SaveData sd;
- LONG error;
-
- if (dtw->dtw_FileHandle) {
-
- ObtainSemaphoreShared(&(DTSI(obj)->si_Lock));
-
- if (error=ERROR_NO_FREE_STORE,(sd.pool=CreatePool(MEMF_CLEAR,4*1024,4*1024)) != NULL) {
-
- if ((sd.handle=OpenFFR(cb,sd.pool,FFR_MODE_WRITE,dtw->dtw_FileHandle)) != NULL) {
-
- SetDTAttrs(obj, NULL, NULL, PDTA_SourceMode,PMODE_V43, TAG_DONE);
-
- sd.cmap = NULL; sd.numcolors = 0; sd.bm = NULL; mode = INVALID_ID; bmhd = NULL;
-
- GetDTAttrs(obj,
- PDTA_BitMapHeader, &bmhd,
- PDTA_ModeID, &mode,
- PDTA_BitMap, &sd.bm,
- PDTA_NumColors, &sd.numcolors,
- PDTA_ColorRegisters, &sd.cmap,
- TAG_DONE);
-
- error = ERROR_OBJECT_WRONG_TYPE;
-
- if (bmhd && mode != INVALID_ID && sd.bm && ((depth=bmhd->bmh_Depth) > 8 || (sd.numcolors && sd.cmap))) {
-
- sd.isEHB = ((mode & EXTRAHALFBRITE_KEY) != 0); sd.isHAM = ((mode & HAM_KEY) != 0);
-
- sd.depth = depth; sd.height = bmhd->bmh_Height; sd.width = bmhd->bmh_Width;
-
- if (error=ERROR_NOT_IMPLEMENTED,bmhd->bmh_Compression == cmpNone) {
-
- if ((error=write_bmp_header(cb,obj,&sd)) == 0) {
-
- if (id=~0,depth > 8 && (methods=GetDTMethods(obj)))
- do;while(((id=*methods++) != ~0) && (id-=PDTM_READPIXELARRAY));
-
- if (encode=encode_picture_v42,!id)
- encode=encode_picture_v43;
- error = (*encode)(cb,obj,&sd);
- }
- }
- }
- if (!CloseFFR(sd.handle))
- error = -1;
- }
- DeletePool(sd.pool);
- }
-
- ReleaseSemaphore(&(DTSI(obj)->si_Lock));
-
- if (error) {
- if (error > 0) SetIoErr(error); return FALSE;
- }
- }
-
- return TRUE;
- }
-
- /*
- ** class dispatcher
- */
-
- ASM(Object *) Dispatch(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg))
- { struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
- struct RastPort *rp;
- Object *o = obj;
-
- if ((msg->MethodID == DTM_WRITE) && (((struct dtWrite *)msg)->dtw_Mode == DTWM_RAW))
- return (Object *)SaveBMP(cb,obj,(struct dtWrite *)msg);
-
- if (msg->MethodID != OM_UPDATE || !DoMethod(obj,ICM_CHECKLOOP)) {
- if ((obj=(Object *)DoSuperMethodA(cl,obj,msg))) {
- if (msg->MethodID == OM_NEW) {
- if ((o != (Object *)cl) || !LoadBMP(cb,obj))
- { CoerceMethod(cl,obj,OM_DISPOSE); if (obj) ; obj = NULL; }
- }
- else if (msg->MethodID == OM_UPDATE || msg->MethodID == OM_SET) {
- if ((rp=ObtainGIRPort(((struct opSet *)msg)->ops_GInfo)) != NULL) {
- DoMethod(o,GM_RENDER,((struct opSet *)msg)->ops_GInfo,rp,GREDRAW_UPDATE);
- ReleaseGIRPort(rp); obj = NULL;
- }
- }
- }
- }
- else obj = NULL;
-
- return obj;
- }
-