home *** CD-ROM | disk | FTP | other *** search
/ Merciful 3 / Merciful_Release_3.bin / software / b / bmpdatatypev40.5.lha / BMPdt / Source / getbmp.c < prev    next >
C/C++ Source or Header  |  1996-04-21  |  15KB  |  638 lines

  1. /*
  2. ** our include
  3. */
  4.  
  5. #include "getbmp.h"
  6.  
  7. /*
  8. ** functions for asynchronous file I/O
  9. */
  10.  
  11. APTR OpenFFR(BPTR,LONG);
  12. LONG FFRGetC(APTR);
  13. LONG FFRRead(APTR,APTR,LONG);
  14. VOID CloseFFR(APTR);
  15.  
  16. /*
  17. ** cybergfx defines for picture.datatype V43
  18. */
  19.  
  20. #define RECTFMT_RGB  0
  21. #define RECTFMT_LUT8 3
  22.  
  23. /*
  24. ** easy access of a char-array as a "structure" (IJG sources v5.0b)
  25. */
  26.  
  27. #define UCH(x) \
  28.   ((int) (x))
  29.  
  30. #define GET_2B(array,offset) \
  31.   ((unsigned int) UCH(array[offset]) + \
  32.    (((unsigned int) UCH(array[offset+1])) << 8))
  33.  
  34. #define GET_4B(array,offset) \
  35.   ((ULONG) UCH(array[offset]) + \
  36.    (((ULONG) UCH(array[offset+1])) << 8) + \
  37.    (((ULONG) UCH(array[offset+2])) << 16) + \
  38.    (((ULONG) UCH(array[offset+3])) << 24))
  39.  
  40. /*
  41. ** compression types for BMPs
  42. */
  43.  
  44. enum { BI_RGB=0,BI_RLE8=1,BI_RLE4=2 };
  45.  
  46. /*
  47. ** get dt attribute(s)
  48. */
  49.  
  50. ULONG set_dt_attrs(Object *obj, ULONG data, ...)
  51. {
  52.   return (SetDTAttrsA(obj,NULL,NULL,(struct TagItem *)&data));
  53. }
  54.  
  55. /*
  56. ** get dt attribute(s)
  57. */
  58.  
  59. ULONG get_dt_attrs(Object *obj, ULONG data, ...)
  60. {
  61.   return (GetDTAttrsA(obj,(struct TagItem *)&data));
  62. }
  63.  
  64. /*
  65. ** expand every bit to a byte
  66. */
  67.  
  68. VOID convert_1bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
  69. {
  70.   ULONG i,j;
  71.   UBYTE c;
  72.  
  73.   for(i=width/8; i!=0; i--)
  74.     for(c=*pixelbuf++,j=8; j!=0; j--) {
  75.       *outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
  76.     }
  77.   if ((i=width%8)) {
  78.     c = *pixelbuf;
  79.     do {
  80.       *outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
  81.     } while (--i);
  82.   }
  83. }
  84.  
  85. /*
  86. ** expand every 4 bits to a byte
  87. */
  88.  
  89. VOID convert_4bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
  90. {
  91.   ULONG i;
  92.   UBYTE c;
  93.  
  94.   for(i=width/2; i!=0; i--) {
  95.     c = *pixelbuf++; *outbuf++ = (c >> 4); *outbuf++ = (c & 0xf);
  96.   }
  97.   if (width&1) {
  98.     c = *pixelbuf; c >>= 4; *outbuf = c;
  99.   }
  100. }
  101.  
  102. /*
  103. ** perform a simple copy (outbuf is WritePixelLine8() aware..)
  104. */
  105.  
  106. VOID convert_8bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
  107. {
  108.   CopyMem(pixelbuf,outbuf,width);
  109. }
  110.  
  111. /*
  112. ** correct color order (BGR -> RGB)
  113. */
  114.  
  115. VOID convert_24bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
  116. {
  117.   UBYTE *p,c;
  118.  
  119.   p = pixelbuf;
  120.   do {
  121.     c = p[0]; p[0] = p[2]; p[2] = c; p += 3;
  122.   } while (p < &pixelbuf[width*3]);
  123. }
  124.  
  125. /*
  126. ** handle 4bit compression
  127. */
  128.  
  129. LONG decompress_4bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
  130. {
  131.   LONG xpos,a,b,c,i;
  132.   UBYTE *end;
  133.  
  134.   end = buffer+width*height; xpos = 0;
  135.  
  136.   do {
  137.  
  138.     if ((c=FFRGetC(handle)) < 0) return c;
  139.  
  140.     if (c == 0) {
  141.  
  142.       if ((c=FFRGetC(handle)) < 0) return c;
  143.  
  144.       if (c == 0) {
  145.         buffer += (width-xpos); height--; xpos = 0;
  146.       }
  147.       else if (!--c) {
  148.         break;
  149.       }
  150.       else if (!--c) {
  151.         a = FFRGetC(handle); xpos += a; buffer += a;
  152.         if ((c=FFRGetC(handle)) < 0) return c;
  153.         height -= c; buffer += width*c;
  154.       }
  155.       else {
  156.         c += 2; i = 0;
  157.         do {
  158.           a = FFRGetC(handle); b = a & 0x0f; a >>= 4;
  159.           *buffer++ = a; *buffer++ = b;
  160.           i += 2;
  161.         } while (i < c);
  162.         if (((c&3)==1) || ((c&3)==2)) FFRGetC(handle);
  163.         xpos += c; if (i>c) --buffer;
  164.       }
  165.     }
  166.     else {
  167.       i = 0; b = FFRGetC(handle); a = b & 0xf; b >>= 4;
  168.       do {
  169.         *buffer++ = b; *buffer++ = a; i += 2;
  170.       } while (i < c);
  171.       xpos += c; if (i>c) --buffer;
  172.     }
  173.   } while (height && buffer < end);
  174.  
  175.   return 0;
  176. }
  177.  
  178. /*
  179. ** handle 8bit compression
  180. */
  181.  
  182. LONG decompress_8bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
  183. {
  184.   LONG xpos,a,c,i;
  185.   UBYTE *end;
  186.  
  187.   end = buffer+width*height; xpos = 0;
  188.  
  189.   do {
  190.  
  191.     if ((c=FFRGetC(handle)) < 0) return c;
  192.  
  193.     if (c == 0) {
  194.  
  195.       if ((c=FFRGetC(handle)) < 0) return c;
  196.  
  197.       if (c == 0) {
  198.         buffer += (width-xpos); height--; xpos = 0;
  199.       }
  200.       else if (!--c) {
  201.         break;
  202.       }
  203.       else if (!--c) {
  204.         a = FFRGetC(handle); xpos += a; buffer += a;
  205.         if ((c=FFRGetC(handle)) < 0) return c;
  206.         height -= c; buffer += width*c;
  207.       }
  208.       else {
  209.         c += 2; i = c;
  210.         do {
  211.           *buffer++ = FFRGetC(handle);
  212.         } while (--i);
  213.         if (c&1) FFRGetC(handle);
  214.         xpos += c;
  215.       }
  216.     }
  217.     else {
  218.       i = c; a = FFRGetC(handle);
  219.       do {
  220.         *buffer++ = a;
  221.       } while (--i);
  222.       xpos += c;
  223.     }
  224.   } while (height && buffer < end);
  225.  
  226.   return 0;
  227. }
  228.  
  229. /*
  230. ** compressed image (4 or 8 bit)
  231. */
  232.  
  233. LONG decode_rle_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
  234.                     UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
  235. {
  236.   LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
  237.   UBYTE *buffer;
  238.   LONG ret=ERROR_NO_FREE_STORE;
  239.  
  240.   if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
  241.   {
  242.     decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
  243.  
  244.     if ((ret=(*decode)(handle,buffer,width,height)) == 0)
  245.       do {
  246.         convert_8bit(buffer,lbuf,width);
  247.         WritePixelLine8(rp,0,height-1,width,lbuf,trp);
  248.         buffer+=width;
  249.       } while (--height);
  250.   }
  251.  
  252.   return ret;
  253. }
  254.  
  255. /*
  256. ** uncompressed image (1, 4 or 8 bit)
  257. */
  258.  
  259. LONG decode_normal_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
  260.                        UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
  261. {
  262.   VOID (*convert)(UBYTE *,UBYTE *,ULONG);
  263.   ULONG padwidth;
  264.   UBYTE *buffer;
  265.   LONG ret=ERROR_NO_FREE_STORE;
  266.  
  267.   padwidth = ((((width * depth) + 31) & ~31) / 8);
  268.  
  269.   if ((buffer=AllocPooled(pool,padwidth)) != NULL)
  270.   {
  271.     convert = convert_8bit;
  272.     if (depth != 8) {
  273.       convert = convert_4bit;
  274.       if (depth != 4)
  275.         convert = convert_1bit;
  276.     }
  277.  
  278.     ret = -1;
  279.  
  280.     do {
  281.       if (FFRRead(handle,buffer,padwidth) != padwidth)
  282.         return ret;
  283.       (*convert)(buffer,lbuf,width);
  284.       WritePixelLine8(rp,0,height-1,width,lbuf,trp);
  285.     } while (--height);
  286.  
  287.     ret = 0;
  288.   }
  289.  
  290.   return ret;
  291. }
  292.  
  293. /*
  294. ** convert 24 bit to HAM6/8 (not yet)
  295. */
  296.  
  297. LONG decode_truecolor_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
  298.                           UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
  299. {
  300.   return ERROR_NOT_IMPLEMENTED;
  301. }
  302.  
  303. /*
  304. ** create the bitmap (V42 interface)
  305. */
  306.  
  307. LONG decode_picture_v42(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
  308. {
  309.   LONG (*decode)(APTR,APTR,ULONG,ULONG,ULONG,UBYTE *,struct RastPort *,struct RastPort *);
  310.   ULONG modeid,width,height,depth;
  311.   struct BitMap *tbm,*bm;
  312.   struct RastPort trp,rp;
  313.   UBYTE *lbuf;
  314.   LONG ret=ERROR_NO_FREE_STORE;
  315.  
  316.   width = bmhd->bmh_Width; height = bmhd->bmh_Height; depth = bmhd->bmh_Depth;
  317.  
  318.   if (depth == 24) depth /= 3;
  319.  
  320.   if ((bm=AllocBitMap(width,height,depth,BMF_CLEAR|BMF_DISPLAYABLE,NULL)) != NULL)
  321.   {
  322.     InitRastPort(&rp); rp.BitMap = bm;
  323.  
  324.     if ((tbm=AllocBitMap(width,1,depth,BMF_CLEAR,NULL)) != NULL)
  325.     {
  326.       InitRastPort(&trp); trp.BitMap = tbm;
  327.  
  328.       if ((lbuf=AllocPooled(pool,((width+15)&~15))) != NULL)
  329.       {
  330.         decode = decode_truecolor_v42;
  331.         if (bmhd->bmh_Depth != 24) {
  332.           decode = decode_normal_v42;
  333.           if (bmhd->bmh_Compression) {
  334.             bmhd->bmh_Compression = 0; decode = decode_rle_v42;
  335.           }
  336.         }
  337.  
  338.         if ((ret=(*decode)(pool,handle,width,height,depth,lbuf,&rp,&trp)) == 0)
  339.         {
  340.           modeid = LORES_KEY;
  341.           if ((UWORD)width >= 640)
  342.             modeid = HIRES;
  343.           if ((UWORD)height >= 400)
  344.             modeid |= LACE;
  345.  
  346.           set_dt_attrs(obj,
  347.                        DTA_ObjName,      title,
  348.                        DTA_NominalHoriz, width,
  349.                        DTA_NominalVert,  height,
  350.                        PDTA_BitMap,      bm,
  351.                        PDTA_ModeID,      modeid,
  352.                        TAG_DONE);
  353.         }
  354.       }
  355.  
  356.       FreeBitMap(tbm);
  357.     }
  358.  
  359.     if (ret)
  360.       FreeBitMap(bm);
  361.   }
  362.  
  363.   return ret;
  364. }
  365.  
  366. /*
  367. ** compressed image (4 or 8 bit)
  368. */
  369.  
  370. LONG decode_rle_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
  371. {
  372.   LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
  373.   UBYTE *buffer;
  374.   LONG ret=ERROR_NO_FREE_STORE;
  375.  
  376.   if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
  377.   {
  378.     decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
  379.  
  380.     if ((ret=(*decode)(handle,buffer,width,height)) == 0)
  381.       do {
  382.         DoSuperMethod(cl,obj,
  383.                       DTM_WRITEPIXELARRAY,buffer,RECTFMT_LUT8,width,0,height-1,width,1);
  384.         buffer+=width;
  385.       } while (--height);
  386.   }
  387.  
  388.   return ret;
  389. }
  390.  
  391. /*
  392. ** uncompressed image (1, 4, 8 or 24 bit)
  393. */
  394.  
  395. LONG decode_normal_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
  396. {
  397.   VOID (*convert)(UBYTE *,UBYTE *,ULONG);
  398.   ULONG padwidth,rectfmt;
  399.   UBYTE *buffer,*lbuf;
  400.   LONG ret=ERROR_NO_FREE_STORE;
  401.  
  402.   padwidth = ((((width * depth) + 31) & ~31) / 8);
  403.   
  404.   if ((buffer=AllocPooled(pool,padwidth)) != NULL)
  405.   {
  406.     lbuf = buffer; rectfmt = RECTFMT_RGB; convert = convert_24bit;
  407.  
  408.     if (depth != 24) {
  409.       convert = convert_8bit;
  410.       if (depth != 8) {
  411.         convert = convert_4bit;
  412.         if (depth != 4) {
  413.           convert = convert_1bit;
  414.         }
  415.       }
  416.       rectfmt = RECTFMT_LUT8; lbuf = AllocPooled(pool,width);
  417.     }
  418.  
  419.     if (lbuf != NULL)
  420.     {
  421.       ret = -1;
  422.  
  423.       do {
  424.         if (FFRRead(handle,buffer,padwidth) != padwidth)
  425.           return ret;
  426.         (*convert)(buffer,lbuf,width);
  427.         DoSuperMethod(cl,obj,
  428.                       DTM_WRITEPIXELARRAY,lbuf,rectfmt,0,0,height-1,width,1);
  429.       } while (--height);
  430.  
  431.       ret = 0;
  432.     }
  433.   }
  434.  
  435.   return ret;
  436. }
  437.  
  438. /*
  439. ** decode picture (V43 interface)
  440. */
  441.  
  442. LONG decode_picture_v43(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
  443. {
  444.   LONG (*decode)(Class *,Object *,APTR,APTR,ULONG,ULONG,ULONG);
  445.   ULONG width,height,depth;
  446.   LONG level,number,ret;
  447.  
  448.   level = 0; number = 0;
  449.  
  450.   set_dt_attrs(obj,
  451.                PDTA_SourceMode,  MODE_V43,
  452.                PDTA_ModeID,      0,
  453.                DTA_ObjName,      title,
  454.                DTA_NominalHoriz, width=bmhd->bmh_Width,
  455.                DTA_NominalVert,  height=bmhd->bmh_Height,
  456.                DTA_ErrorLevel,   &level,
  457.                DTA_ErrorNumber,  &number,
  458.                TAG_DONE);
  459.  
  460.   ret = number;
  461.  
  462.   if (!level) {
  463.     decode = decode_normal_v43;
  464.     if (bmhd->bmh_Compression)
  465.       {bmhd->bmh_Compression = 0; decode = decode_rle_v43; }
  466.     ret = (*decode)(cl,obj,pool,handle,width,height,bmhd->bmh_Depth);
  467.   }
  468.  
  469.   return ret;
  470. }
  471.  
  472. /*
  473. ** extract all required information from the bmp header
  474. */
  475.  
  476. LONG read_bmp_header(Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd)
  477. {
  478.   UBYTE header[64],*p[2],*coltab,*cmap,r,g,b;
  479.   LONG headerSize;
  480.   LONG bfOffBits;
  481.   LONG biDepth;
  482.   LONG biPlanes;
  483.   LONG biCompression;
  484.   LONG biClrUsed;
  485.   LONG cmapentrysize;
  486.   LONG coltabsize;
  487.   LONG *cregs;
  488.  
  489.   if (FFRRead(handle,header,18) != 18)
  490.     return FALSE;
  491.  
  492.   if (((UWORD)GET_2B(header,0)) != 0x4D42)
  493.     return FALSE;
  494.  
  495.   bfOffBits  = GET_4B(header,10);
  496.   headerSize = GET_4B(header,14);
  497.  
  498.   if (headerSize != 12 && headerSize != 40 && headerSize != 64)
  499.     return FALSE;
  500.  
  501.   if (FFRRead(handle,header+4,headerSize-4) != (headerSize-4))
  502.     return FALSE;
  503.  
  504.   if (headerSize == 12) { /* OS/2 1.x */
  505.     bmhd->bmh_Width  = GET_2B(header, 4);
  506.     bmhd->bmh_Height = GET_2B(header, 6);
  507.     biPlanes         = GET_2B(header, 8);
  508.     biDepth          = GET_2B(header,10);
  509.     biCompression    = 0;
  510.     biClrUsed        = 0;
  511.     cmapentrysize    = 3;
  512.   }
  513.   else { /* Windows 3.x or OS/2 2.x */
  514.     bmhd->bmh_Width  = GET_4B(header, 4);
  515.     bmhd->bmh_Height = GET_4B(header, 8);
  516.     biPlanes         = GET_2B(header,12);
  517.     biDepth          = GET_2B(header,14);
  518.     biCompression    = GET_4B(header,16);
  519.     biClrUsed        = GET_4B(header,32);
  520.     cmapentrysize    = 4;
  521.   }
  522.  
  523.   if (biPlanes != 1)
  524.     return FALSE;
  525.  
  526.   if (biDepth != 1 && biDepth != 4 && biDepth != 8) {
  527.     if (biDepth == 24)
  528.       cmapentrysize = 0;
  529.     else
  530.       return FALSE;
  531.   }
  532.  
  533.   if ((bmhd->bmh_PageWidth=bmhd->bmh_Width) == 0 ||
  534.       (bmhd->bmh_PageHeight=bmhd->bmh_Height) == 0)
  535.     return FALSE;
  536.  
  537.   bmhd->bmh_Depth = biDepth;
  538.  
  539.   bmhd->bmh_Compression = biCompression;
  540.  
  541.   if (bmhd->bmh_Compression && ((biDepth == 4 && biCompression != BI_RLE4) ||
  542.                                 (biDepth == 8 && biCompression != BI_RLE8)))
  543.     return FALSE;
  544.  
  545.   if ((coltabsize=cmapentrysize) != 0)
  546.   {
  547.     if (biClrUsed <= 0)
  548.       biClrUsed = 1L << biDepth;
  549.  
  550.     if (biClrUsed > 256)
  551.       return FALSE;
  552.  
  553.     (void)set_dt_attrs(obj, PDTA_NumColors,(ULONG)biClrUsed, TAG_DONE);
  554.  
  555.     if ((get_dt_attrs(obj, PDTA_ColorRegisters,(ULONG)&p[0],PDTA_CRegs,(ULONG)&p[1], TAG_DONE)) != 2)
  556.       return FALSE;
  557.  
  558.     coltabsize = biClrUsed * cmapentrysize;
  559.  
  560.     if ((coltab=AllocPooled(pool,coltabsize)) == NULL)
  561.       return FALSE;
  562.  
  563.     if (FFRRead(handle,coltab,coltabsize) != coltabsize)
  564.       return FALSE;
  565.  
  566.     /*
  567.     ** do not use "struct ColorRegister" for cmap since with the amiga port
  568.     ** of gcc a sizeof() for this structure is four and not three.. oh well
  569.     */
  570.  
  571.     cmap = (UBYTE *)p[0]; cregs = (LONG *)p[1];
  572.     do {
  573.       r = coltab[2]; *cmap++ = r; *cregs++ = r << 24;
  574.       g = coltab[1]; *cmap++ = g; *cregs++ = g << 24;
  575.       b = coltab[0]; *cmap++ = b; *cregs++ = b << 24;
  576.       coltab += cmapentrysize;
  577.     } while (--biClrUsed);
  578.   }
  579.  
  580.   if ((biClrUsed = bfOffBits - (14 + headerSize + coltabsize)) > 0)
  581.     do
  582.       if (FFRGetC(handle) < 0) break;
  583.     while (--biClrUsed);
  584.  
  585.   return (biClrUsed == 0 ? TRUE : FALSE);
  586. }
  587.  
  588. /*
  589. ** load the picture
  590. */
  591.  
  592. LONG GetBMP(Class *cl, Object *obj, struct TagItem *attrs)
  593. {
  594.   LONG (*decode)(Class *,Object *,APTR,APTR,struct BitMapHeader *,ULONG);
  595.   struct BitMapHeader *bmhd;
  596.   ULONG *methods,*mptr,id;
  597.   LONG error,success;
  598.   APTR pool,handle;
  599.   BPTR fh;
  600.  
  601.   success = FALSE; error = ERROR_NO_FREE_STORE;
  602.  
  603.   if ((pool=CreatePool(MEMF_CLEAR,1024,1024)) != NULL)
  604.   {
  605.     if ((get_dt_attrs(obj, DTA_Handle,&fh,PDTA_BitMapHeader,&bmhd, TAG_DONE) == 2) && fh)
  606.     {
  607.       if ((handle=OpenFFR(fh,0)) != NULL)
  608.       {
  609.         error = ERROR_OBJECT_WRONG_TYPE;
  610.  
  611.         if (read_bmp_header(obj,pool,handle,bmhd) != FALSE)
  612.         {
  613.           decode = decode_picture_v42;
  614.  
  615.           if ((get_dt_attrs(obj, DTA_Methods,&methods, TAG_DONE) == 1) && methods)
  616.           {
  617.             mptr=methods;
  618.             do
  619.               id=*mptr++;
  620.             while ((id != ~0) && (id-=DTM_WRITEPIXELARRAY));
  621.  
  622.             if (!id) decode = decode_picture_v43;
  623.           }
  624.  
  625.           if ((error=(*decode)(cl,obj,pool,handle,bmhd,GetTagData(DTA_Name,NULL,attrs))) == 0)
  626.             success = TRUE;
  627.         }
  628.         CloseFFR(handle);
  629.       }
  630.     }
  631.     DeletePool(pool);
  632.   }
  633.  
  634.   if (!success && error > 0) SetIoErr(error);
  635.  
  636.   return success;
  637. }
  638.