IBMP.c
资源名称:ilib [点击查看]
上传用户:changbiao
上传日期:2007-01-13
资源大小:141k
文件大小:9k
源码类别:

图片显示

开发平台:

C/C++

  1. /*
  2.  * IBMP.c
  3.  *
  4.  * Image library
  5.  *
  6.  * Description:
  7.  * Read BMP files.
  8.  *
  9.  * History:
  10.  * 01-Apr-00 Jim Winstead jimw@trainedmonkey.com
  11.  * Created
  12.  *
  13.  ****************************************************************************/
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <ctype.h>
  17. #include <memory.h>
  18. #include <string.h>
  19. #include "Ilib.h"
  20. #include "IlibP.h"
  21. #define BMP_HEADER ('B' + ('M' << 8))
  22. /* Compression formats */
  23. #define BI_RGB                0
  24. #define BI_RLE8                1
  25. #define BI_RLE4                2
  26. #define BI_BITFIELDS        3
  27. #define SET_PIXEL(buffer, byte) 
  28. do { 
  29. *(buffer+0) = (colortable[byte&0xff]&(0xff<<16))>>16; 
  30. *(buffer+1) = (colortable[byte&0xff]&(0xff<<8))>>8; 
  31. *(buffer+2) = (colortable[byte&0xff]&(0xff<<0))>>0; 
  32. } while (0);
  33. static int ReadShort (fp, ret)
  34. FILE *fp;
  35. int *ret;
  36. {
  37.   int c = fgetc(fp);
  38.   if (c == EOF) return 0;
  39.   *ret = (c&0xff);
  40.   c = fgetc(fp);
  41.   if (c == EOF) return 0;
  42.   *ret |= (c&0xff) << 8;
  43.   return 1;
  44. }
  45. static int ReadLong (fp, ret)
  46. FILE *fp;
  47. int *ret;
  48. {
  49.   int c = fgetc(fp);
  50.   if (c == EOF) return 0;
  51.   *ret = (c&0xff);
  52.   c = fgetc(fp);
  53.   if (c == EOF) return 0;
  54.   *ret |= (c&0xff) << 8;
  55.   c = fgetc(fp);
  56.   if (c == EOF) return 0;
  57.   *ret |= (c&0xff) << 16;
  58.   c = fgetc(fp);
  59.   if (c == EOF) return 0;
  60.   *ret |= (c&0xff) << 24;
  61.   return 1;
  62. }
  63. IError _IReadBMP ( fp, options, image_return )
  64. FILE *fp;
  65. IOptions options;
  66. IImageP **image_return;
  67. {
  68.   IImageP *image = NULL;
  69.   int scratch, fileSize, offset, w, h, depth, compression,
  70.       imagesize, xpelspermeter, ypelspermeter, colorsused, colorsimportant;
  71.   int redmask, greenmask, bluemask,
  72.       redshift, greenshift, blueshift,
  73.       redbits, greenbits, bluebits;
  74.   int *colortable = NULL;
  75.   /* read the header and make sure this is a BMP file */
  76.   if (!ReadShort(fp, &scratch) || scratch != BMP_HEADER) return IInvalidFormat;
  77.   /* read the file size (not sure this is useful) */
  78.   if (!ReadLong(fp, &fileSize)) return (IInvalidFormat);
  79.   /* read the two reserved fields (must be zero, according to spec) */
  80.   if (!ReadShort(fp, &scratch) || scratch != 0) return (IInvalidFormat);
  81.   if (!ReadShort(fp, &scratch) || scratch != 0) return (IInvalidFormat);
  82.   /* read the offset of the actual graphic bits */
  83.   if (!ReadLong(fp, &offset)) return (IInvalidFormat);
  84.   /*fprintf(stderr, "offset = %dn", offset);*/
  85.   /* verify that the header is 40 bytes */
  86.   /* XXX: really should save this and just skip bytes we don't understand. */
  87.   /* and we could be using this to detect things in OS/2 format */
  88.   if (!ReadLong(fp, &scratch) || scratch != 40) return (IInvalidFormat);
  89.   /* get image size and depth */
  90.   if (!ReadLong(fp, &w)) return (IInvalidFormat);
  91.   if (!ReadLong(fp, &h)) return (IInvalidFormat);
  92.   if (!ReadShort(fp, &scratch) || scratch != 1) return (IInvalidFormat);
  93.   if (!ReadShort(fp, &depth)) return (IInvalidFormat);
  94.   /*fprintf(stderr, "image size: %dx%dx%dn", w, h, depth);*/
  95.   if (!ReadLong(fp, &compression)) return (IInvalidFormat);
  96.   if (!ReadLong(fp, &imagesize)) return (IInvalidFormat);
  97.   if (!ReadLong(fp, &xpelspermeter)) return (IInvalidFormat);
  98.   if (!ReadLong(fp, &ypelspermeter)) return (IInvalidFormat);
  99.   if (!ReadLong(fp, &colorsused)) return (IInvalidFormat);
  100.   if (!ReadLong(fp, &colorsimportant)) return (IInvalidFormat);
  101.   /* we have read 40 bytes of header */
  102.   /* we have read 54 bytes of data from the file */
  103. /*
  104.   fprintf(stderr, "compression=%d, imagesize=%d, colorsused=%dn",
  105.       compression,
  106.       imagesize,
  107.       colorsused);
  108. */
  109.   /* get the masks, shifts, and bits for bitfields (16 and 32 bits) */
  110.   if (compression == BI_BITFIELDS) {
  111.     if (!ReadLong(fp,&redmask)) return IInvalidImage;
  112.     for (redshift = 0; !(redmask&(1<<redshift)) && redshift<32; redshift++);
  113.     for (redbits = 0; (redmask&(1<<(redshift+redbits))) && redshift<32; redbits++);
  114.     if (!ReadLong(fp,&greenmask)) return IInvalidImage;
  115.     for (greenshift = 0; !(greenmask&(1<<greenshift)) && greenshift<32; greenshift++);
  116.     for (greenbits = 0; (greenmask&(1<<(greenshift+greenbits))) && greenshift<32; greenbits++);
  117.     if (!ReadLong(fp,&bluemask)) return IInvalidImage;
  118.     for (blueshift = 0; !(bluemask&(1<<blueshift)) && blueshift<32; blueshift++);
  119.     for (bluebits = 0; (bluemask&(1<<(blueshift+bluebits))) && blueshift<32; bluebits++);
  120.     /*fprintf(stderr, "masks: %x %x %xn", redmask, greenmask, bluemask);*/
  121.     /*fprintf(stderr, "shifts: %d %d %dn", redshift, greenshift, blueshift);*/
  122.     /*fprintf(stderr, "bits: %d %d %dn", redbits, greenbits, bluebits);*/
  123.   }
  124.   if (depth <= 8) {
  125.     if (!colorsused) colorsused = 2<<depth;
  126.     colortable = malloc(colorsused*sizeof(int));
  127.     for (scratch = 0; scratch < colorsused; scratch++) {
  128.       if (!ReadLong(fp,(colortable+scratch))) return (IInvalidFormat);
  129.     }
  130.   }
  131.   /* seek to the beginning of the image data */
  132.   if (fseek(fp, offset, SEEK_SET) < 0) return (IInvalidFormat);
  133.   /* create a new image object */
  134.   image = (IImageP *) ICreateImage ( w, h, options );
  135.   if (depth == 24 && compression == BI_RGB) {
  136.     int x, y;
  137.     /* slurp in the data */
  138.     for (y = h - 1; y >= 0; y--) {
  139.       for (x = 0; x < w; x++) {
  140.         int r,g,b;
  141.         r = fgetc(fp); g = fgetc(fp); b = fgetc(fp);
  142.         /* this leaks the image object if we hit a premature EOF */
  143.         if (r == EOF || g == EOF || b == EOF) return (IInvalidFormat);
  144.         *(image->data + (y*3*w) + (x*3)) = b;
  145.         *(image->data + (y*3*w) + (x*3) + 1) = g;
  146.         *(image->data + (y*3*w) + (x*3) + 2) = r;
  147.       }
  148.     }
  149.   }
  150.   else if (depth == 16 && compression == BI_BITFIELDS) {
  151.     int x, y;
  152.     /* slurp in the data */
  153.     for (y = h - 1; y >= 0; y--) {
  154.       for (x = 0; x < w; x++) {
  155.         char *pixel = image->data + (y*3*w) + (x*3);
  156.         int color;
  157.         /* this leaks the image object if we hit a premature EOF */
  158.         if (!ReadShort(fp, &color)) return (IInvalidFormat);
  159.         /* scale 5/6 bit values to 8 bits */
  160.         *(pixel + 0) = (((color&redmask)>>redshift)<<8)>>redbits;
  161.         *(pixel + 1) = (((color&greenmask)>>greenshift)<<8)>>greenbits;
  162.         *(pixel + 2) = (((color&bluemask)>>blueshift)<<8)>>bluebits;
  163.       }
  164.     }
  165.   }
  166.   else if (depth == 8 && compression == BI_RGB) {
  167.     int x, y;
  168.     /*fprintf(stderr, "8 bit, no compressionn");*/
  169.     for (y = h - 1; y >= 0; y--) {
  170.       for (x = 0; x < w; x++) {
  171.         char *pixel = image->data+(y*w*3)+(x*3);
  172.         int byte = fgetc(fp); if (byte == EOF) return IInvalidFormat;
  173.         SET_PIXEL(pixel, byte);
  174.       }
  175.     }
  176.   } else if (depth <= 8 && compression) {
  177.     int byte, count, x, y;
  178.     char *buffer = image->data+w*(h-1)*3;
  179.     for (y = 0; y < h; ) {
  180.       count = fgetc(fp);
  181.       if (count == EOF) return (IInvalidFormat);
  182.       if (count != 0) {
  183.         /*fprintf(stderr, "stretch of %d bytesn", count);*/
  184.         byte = fgetc(fp); if (byte == EOF) return (IInvalidFormat);
  185.         for (scratch = 0; scratch < count; scratch++) {
  186.           if (compression == 1) {
  187.             SET_PIXEL(buffer, byte);
  188.           }
  189.           else {
  190.             int thisbyte = (scratch & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f);
  191.             SET_PIXEL(buffer, thisbyte);
  192.           }
  193.           buffer += 3;
  194.         }
  195.       }
  196.       else {
  197.         count = fgetc(fp);
  198.         if (count == EOF) return (IInvalidFormat);
  199.         if (count == 0x01) break; /* end of bitmap */
  200.         switch (count) {
  201.         case 0x00: /* end of the line */
  202.           /*fprintf(stderr, "hit end of line %dn", y);*/
  203.           y++;
  204.           buffer = image->data+w*(h-y-1)*3;
  205.           break;
  206.         case 0x02: /* goto specific position */
  207.           x = fgetc(fp);
  208.           y = fgetc(fp);
  209.           /*fprintf(stderr, "going to %d,%dn", x, y);*/
  210.           if (x == EOF || y == EOF) return (IInvalidFormat);
  211.           buffer = image->data+w*(h-y-1)*3+(x*3);
  212.           break;
  213.         default: /* a bunch of literal bytes */
  214.           /*fprintf(stderr, "handling %d literal bytesn", count);*/
  215.           for (scratch = 0; scratch < count; scratch++) {
  216.             byte = fgetc(fp); if (byte == EOF) return (IInvalidFormat);
  217.             if (compression == 1) {
  218.               SET_PIXEL(buffer, byte);
  219.             }
  220.             else {
  221.               int thisbyte = (scratch & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f);
  222.               SET_PIXEL(buffer, thisbyte);
  223.             }
  224.             buffer += 3;
  225.           }
  226.           /* handle padding */
  227.           if (compression == 1) {
  228.             if (count & 0x01) {
  229.               /*fprintf(stderr, "eating paddingn");*/
  230.               (void)fgetc(fp);
  231.             }
  232.           }
  233.           else if ((count & 0x03) == 1 || ((count & 0x03) == 2)) {
  234.             (void)fgetc(fp);
  235.           }
  236.           break;
  237.         }
  238.       }
  239.     }
  240.   }
  241.   else {
  242.     _IFreeImage(image);
  243.     return (IInvalidFormat);
  244.   }
  245.   if (colortable) free(colortable);
  246.   *image_return = image;
  247.   return ( INoError );
  248. }