home *** CD-ROM | disk | FTP | other *** search
- /*
- ** our include
- */
-
- #include "getbmp.h"
-
- /*
- ** functions for asynchronous file I/O
- */
-
- APTR OpenFFR(BPTR,LONG);
- LONG FFRGetC(APTR);
- LONG FFRRead(APTR,APTR,LONG);
- VOID CloseFFR(APTR);
-
- /*
- ** 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 v5.0b)
- */
-
- #define UCH(x) \
- ((int) (x))
-
- #define GET_2B(array,offset) \
- ((unsigned int) UCH(array[offset]) + \
- (((unsigned int) UCH(array[offset+1])) << 8))
-
- #define GET_4B(array,offset) \
- ((ULONG) UCH(array[offset]) + \
- (((ULONG) UCH(array[offset+1])) << 8) + \
- (((ULONG) UCH(array[offset+2])) << 16) + \
- (((ULONG) UCH(array[offset+3])) << 24))
-
- /*
- ** compression types for BMPs
- */
-
- enum { BI_RGB=0,BI_RLE8=1,BI_RLE4=2 };
-
- /*
- ** get dt attribute(s)
- */
-
- ULONG set_dt_attrs(Object *obj, ULONG data, ...)
- {
- return (SetDTAttrsA(obj,NULL,NULL,(struct TagItem *)&data));
- }
-
- /*
- ** get dt attribute(s)
- */
-
- ULONG get_dt_attrs(Object *obj, ULONG data, ...)
- {
- return (GetDTAttrsA(obj,(struct TagItem *)&data));
- }
-
- /*
- ** expand every bit to a byte
- */
-
- VOID convert_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; j--) {
- *outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
- }
- if ((i=width%8)) {
- c = *pixelbuf;
- do {
- *outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
- } while (--i);
- }
- }
-
- /*
- ** expand every 4 bits to a byte
- */
-
- VOID convert_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;
- }
- }
-
- /*
- ** perform a simple copy (outbuf is WritePixelLine8() aware..)
- */
-
- VOID convert_8bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
- {
- CopyMem(pixelbuf,outbuf,width);
- }
-
- /*
- ** correct color order (BGR -> RGB)
- */
-
- VOID convert_24bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
- {
- UBYTE *p,c;
-
- p = pixelbuf;
- do {
- c = p[0]; p[0] = p[2]; p[2] = c; p += 3;
- } while (p < &pixelbuf[width*3]);
- }
-
- /*
- ** handle 4bit compression
- */
-
- LONG decompress_4bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
- {
- LONG xpos,a,b,c,i;
- UBYTE *end;
-
- end = buffer+width*height; xpos = 0;
-
- do {
-
- if ((c=FFRGetC(handle)) < 0) return c;
-
- if (c == 0) {
-
- if ((c=FFRGetC(handle)) < 0) return c;
-
- if (c == 0) {
- buffer += (width-xpos); height--; xpos = 0;
- }
- else if (!--c) {
- break;
- }
- else if (!--c) {
- a = FFRGetC(handle); xpos += a; buffer += a;
- if ((c=FFRGetC(handle)) < 0) return c;
- height -= c; buffer += width*c;
- }
- else {
- c += 2; i = 0;
- do {
- a = FFRGetC(handle); b = a & 0x0f; a >>= 4;
- *buffer++ = a; *buffer++ = b;
- i += 2;
- } while (i < c);
- if (((c&3)==1) || ((c&3)==2)) FFRGetC(handle);
- xpos += c; if (i>c) --buffer;
- }
- }
- else {
- i = 0; b = FFRGetC(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;
- }
-
- /*
- ** handle 8bit compression
- */
-
- LONG decompress_8bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
- {
- LONG xpos,a,c,i;
- UBYTE *end;
-
- end = buffer+width*height; xpos = 0;
-
- do {
-
- if ((c=FFRGetC(handle)) < 0) return c;
-
- if (c == 0) {
-
- if ((c=FFRGetC(handle)) < 0) return c;
-
- if (c == 0) {
- buffer += (width-xpos); height--; xpos = 0;
- }
- else if (!--c) {
- break;
- }
- else if (!--c) {
- a = FFRGetC(handle); xpos += a; buffer += a;
- if ((c=FFRGetC(handle)) < 0) return c;
- height -= c; buffer += width*c;
- }
- else {
- c += 2; i = c;
- do {
- *buffer++ = FFRGetC(handle);
- } while (--i);
- if (c&1) FFRGetC(handle);
- xpos += c;
- }
- }
- else {
- i = c; a = FFRGetC(handle);
- do {
- *buffer++ = a;
- } while (--i);
- xpos += c;
- }
- } while (height && buffer < end);
-
- return 0;
- }
-
- /*
- ** compressed image (4 or 8 bit)
- */
-
- LONG decode_rle_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
- UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
- {
- LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
- UBYTE *buffer;
- LONG ret=ERROR_NO_FREE_STORE;
-
- if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
- {
- decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
-
- if ((ret=(*decode)(handle,buffer,width,height)) == 0)
- do {
- convert_8bit(buffer,lbuf,width);
- WritePixelLine8(rp,0,height-1,width,lbuf,trp);
- buffer+=width;
- } while (--height);
- }
-
- return ret;
- }
-
- /*
- ** uncompressed image (1, 4 or 8 bit)
- */
-
- LONG decode_normal_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
- UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
- {
- VOID (*convert)(UBYTE *,UBYTE *,ULONG);
- ULONG padwidth;
- UBYTE *buffer;
- LONG ret=ERROR_NO_FREE_STORE;
-
- padwidth = ((((width * depth) + 31) & ~31) / 8);
-
- if ((buffer=AllocPooled(pool,padwidth)) != NULL)
- {
- convert = convert_8bit;
- if (depth != 8) {
- convert = convert_4bit;
- if (depth != 4)
- convert = convert_1bit;
- }
-
- ret = -1;
-
- do {
- if (FFRRead(handle,buffer,padwidth) != padwidth)
- return ret;
- (*convert)(buffer,lbuf,width);
- WritePixelLine8(rp,0,height-1,width,lbuf,trp);
- } while (--height);
-
- ret = 0;
- }
-
- return ret;
- }
-
- /*
- ** convert 24 bit to HAM6/8 (not yet)
- */
-
- LONG decode_truecolor_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
- UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
- {
- return ERROR_NOT_IMPLEMENTED;
- }
-
- /*
- ** create the bitmap (V42 interface)
- */
-
- LONG decode_picture_v42(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
- {
- LONG (*decode)(APTR,APTR,ULONG,ULONG,ULONG,UBYTE *,struct RastPort *,struct RastPort *);
- ULONG modeid,width,height,depth;
- struct BitMap *tbm,*bm;
- struct RastPort trp,rp;
- UBYTE *lbuf;
- LONG ret=ERROR_NO_FREE_STORE;
-
- width = bmhd->bmh_Width; height = bmhd->bmh_Height; depth = bmhd->bmh_Depth;
-
- if (depth == 24) depth /= 3;
-
- if ((bm=AllocBitMap(width,height,depth,BMF_CLEAR|BMF_DISPLAYABLE,NULL)) != NULL)
- {
- InitRastPort(&rp); rp.BitMap = bm;
-
- if ((tbm=AllocBitMap(width,1,depth,BMF_CLEAR,NULL)) != NULL)
- {
- InitRastPort(&trp); trp.BitMap = tbm;
-
- if ((lbuf=AllocPooled(pool,((width+15)&~15))) != NULL)
- {
- decode = decode_truecolor_v42;
- if (bmhd->bmh_Depth != 24) {
- decode = decode_normal_v42;
- if (bmhd->bmh_Compression) {
- bmhd->bmh_Compression = 0; decode = decode_rle_v42;
- }
- }
-
- if ((ret=(*decode)(pool,handle,width,height,depth,lbuf,&rp,&trp)) == 0)
- {
- modeid = LORES_KEY;
- if ((UWORD)width >= 640)
- modeid = HIRES;
- if ((UWORD)height >= 400)
- modeid |= LACE;
-
- set_dt_attrs(obj,
- DTA_ObjName, title,
- DTA_NominalHoriz, width,
- DTA_NominalVert, height,
- PDTA_BitMap, bm,
- PDTA_ModeID, modeid,
- TAG_DONE);
- }
- }
-
- FreeBitMap(tbm);
- }
-
- if (ret)
- FreeBitMap(bm);
- }
-
- return ret;
- }
-
- /*
- ** compressed image (4 or 8 bit)
- */
-
- LONG decode_rle_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
- {
- LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
- UBYTE *buffer;
- LONG ret=ERROR_NO_FREE_STORE;
-
- if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
- {
- decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
-
- if ((ret=(*decode)(handle,buffer,width,height)) == 0)
- do {
- DoSuperMethod(cl,obj,
- DTM_WRITEPIXELARRAY,buffer,RECTFMT_LUT8,width,0,height-1,width,1);
- buffer+=width;
- } while (--height);
- }
-
- return ret;
- }
-
- /*
- ** uncompressed image (1, 4, 8 or 24 bit)
- */
-
- LONG decode_normal_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
- {
- VOID (*convert)(UBYTE *,UBYTE *,ULONG);
- ULONG padwidth,rectfmt;
- UBYTE *buffer,*lbuf;
- LONG ret=ERROR_NO_FREE_STORE;
-
- padwidth = ((((width * depth) + 31) & ~31) / 8);
-
- if ((buffer=AllocPooled(pool,padwidth)) != NULL)
- {
- lbuf = buffer; rectfmt = RECTFMT_RGB; convert = convert_24bit;
-
- if (depth != 24) {
- convert = convert_8bit;
- if (depth != 8) {
- convert = convert_4bit;
- if (depth != 4) {
- convert = convert_1bit;
- }
- }
- rectfmt = RECTFMT_LUT8; lbuf = AllocPooled(pool,width);
- }
-
- if (lbuf != NULL)
- {
- ret = -1;
-
- do {
- if (FFRRead(handle,buffer,padwidth) != padwidth)
- return ret;
- (*convert)(buffer,lbuf,width);
- DoSuperMethod(cl,obj,
- DTM_WRITEPIXELARRAY,lbuf,rectfmt,0,0,height-1,width,1);
- } while (--height);
-
- ret = 0;
- }
- }
-
- return ret;
- }
-
- /*
- ** decode picture (V43 interface)
- */
-
- LONG decode_picture_v43(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
- {
- LONG (*decode)(Class *,Object *,APTR,APTR,ULONG,ULONG,ULONG);
- ULONG width,height,depth;
- LONG level,number,ret;
-
- level = 0; number = 0;
-
- set_dt_attrs(obj,
- PDTA_SourceMode, MODE_V43,
- PDTA_ModeID, 0,
- DTA_ObjName, title,
- DTA_NominalHoriz, width=bmhd->bmh_Width,
- DTA_NominalVert, height=bmhd->bmh_Height,
- DTA_ErrorLevel, &level,
- DTA_ErrorNumber, &number,
- TAG_DONE);
-
- ret = number;
-
- if (!level) {
- decode = decode_normal_v43;
- if (bmhd->bmh_Compression)
- {bmhd->bmh_Compression = 0; decode = decode_rle_v43; }
- ret = (*decode)(cl,obj,pool,handle,width,height,bmhd->bmh_Depth);
- }
-
- return ret;
- }
-
- /*
- ** extract all required information from the bmp header
- */
-
- LONG read_bmp_header(Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd)
- {
- UBYTE header[64],*p[2],*coltab,*cmap,r,g,b;
- LONG headerSize;
- LONG bfOffBits;
- LONG biDepth;
- LONG biPlanes;
- LONG biCompression;
- LONG biClrUsed;
- LONG cmapentrysize;
- LONG coltabsize;
- LONG *cregs;
-
- if (FFRRead(handle,header,18) != 18)
- return FALSE;
-
- if (((UWORD)GET_2B(header,0)) != 0x4D42)
- return FALSE;
-
- bfOffBits = GET_4B(header,10);
- headerSize = GET_4B(header,14);
-
- if (headerSize != 12 && headerSize != 40 && headerSize != 64)
- return FALSE;
-
- if (FFRRead(handle,header+4,headerSize-4) != (headerSize-4))
- return FALSE;
-
- if (headerSize == 12) { /* OS/2 1.x */
- bmhd->bmh_Width = GET_2B(header, 4);
- bmhd->bmh_Height = GET_2B(header, 6);
- biPlanes = GET_2B(header, 8);
- biDepth = GET_2B(header,10);
- biCompression = 0;
- biClrUsed = 0;
- cmapentrysize = 3;
- }
- else { /* Windows 3.x or OS/2 2.x */
- bmhd->bmh_Width = GET_4B(header, 4);
- bmhd->bmh_Height = GET_4B(header, 8);
- biPlanes = GET_2B(header,12);
- biDepth = GET_2B(header,14);
- biCompression = GET_4B(header,16);
- biClrUsed = GET_4B(header,32);
- cmapentrysize = 4;
- }
-
- if (biPlanes != 1)
- return FALSE;
-
- if (biDepth != 1 && biDepth != 4 && biDepth != 8) {
- if (biDepth == 24)
- cmapentrysize = 0;
- else
- return FALSE;
- }
-
- if ((bmhd->bmh_PageWidth=bmhd->bmh_Width) == 0 ||
- (bmhd->bmh_PageHeight=bmhd->bmh_Height) == 0)
- return FALSE;
-
- bmhd->bmh_Depth = biDepth;
-
- bmhd->bmh_Compression = biCompression;
-
- if (bmhd->bmh_Compression && ((biDepth == 4 && biCompression != BI_RLE4) ||
- (biDepth == 8 && biCompression != BI_RLE8)))
- return FALSE;
-
- if ((coltabsize=cmapentrysize) != 0)
- {
- if (biClrUsed <= 0)
- biClrUsed = 1L << biDepth;
-
- if (biClrUsed > 256)
- return FALSE;
-
- (void)set_dt_attrs(obj, PDTA_NumColors,(ULONG)biClrUsed, TAG_DONE);
-
- if ((get_dt_attrs(obj, PDTA_ColorRegisters,(ULONG)&p[0],PDTA_CRegs,(ULONG)&p[1], TAG_DONE)) != 2)
- return FALSE;
-
- coltabsize = biClrUsed * cmapentrysize;
-
- if ((coltab=AllocPooled(pool,coltabsize)) == NULL)
- return FALSE;
-
- if (FFRRead(handle,coltab,coltabsize) != coltabsize)
- 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
- */
-
- cmap = (UBYTE *)p[0]; cregs = (LONG *)p[1];
- do {
- r = coltab[2]; *cmap++ = r; *cregs++ = r << 24;
- g = coltab[1]; *cmap++ = g; *cregs++ = g << 24;
- b = coltab[0]; *cmap++ = b; *cregs++ = b << 24;
- coltab += cmapentrysize;
- } while (--biClrUsed);
- }
-
- if ((biClrUsed = bfOffBits - (14 + headerSize + coltabsize)) > 0)
- do
- if (FFRGetC(handle) < 0) break;
- while (--biClrUsed);
-
- return (biClrUsed == 0 ? TRUE : FALSE);
- }
-
- /*
- ** load the picture
- */
-
- LONG GetBMP(Class *cl, Object *obj, struct TagItem *attrs)
- {
- LONG (*decode)(Class *,Object *,APTR,APTR,struct BitMapHeader *,ULONG);
- struct BitMapHeader *bmhd;
- ULONG *methods,*mptr,id;
- LONG error,success;
- APTR pool,handle;
- BPTR fh;
-
- success = FALSE; error = ERROR_NO_FREE_STORE;
-
- if ((pool=CreatePool(MEMF_CLEAR,1024,1024)) != NULL)
- {
- if ((get_dt_attrs(obj, DTA_Handle,&fh,PDTA_BitMapHeader,&bmhd, TAG_DONE) == 2) && fh)
- {
- if ((handle=OpenFFR(fh,0)) != NULL)
- {
- error = ERROR_OBJECT_WRONG_TYPE;
-
- if (read_bmp_header(obj,pool,handle,bmhd) != FALSE)
- {
- decode = decode_picture_v42;
-
- if ((get_dt_attrs(obj, DTA_Methods,&methods, TAG_DONE) == 1) && methods)
- {
- mptr=methods;
- do
- id=*mptr++;
- while ((id != ~0) && (id-=DTM_WRITEPIXELARRAY));
-
- if (!id) decode = decode_picture_v43;
- }
-
- if ((error=(*decode)(cl,obj,pool,handle,bmhd,GetTagData(DTA_Name,NULL,attrs))) == 0)
- success = TRUE;
- }
- CloseFFR(handle);
- }
- }
- DeletePool(pool);
- }
-
- if (!success && error > 0) SetIoErr(error);
-
- return success;
- }
-