home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1997 March / VPR9703A.ISO / VPR_DATA / DOGA / SOURCES / REND.LZH / PIC1600 / F_BMP.C < prev    next >
C/C++ Source or Header  |  1996-07-16  |  14KB  |  524 lines

  1. #include    <stdio.h>
  2. #include    <stdlib.h>
  3. #include    <string.h>
  4. #ifdef WINDOWS
  5. #undef LittleEndian
  6. #include    <windows.h>
  7. #define LittleEndian
  8. #endif
  9. #include    "piclib.h"
  10. #ifndef SEEK_SET
  11.     #define SEEK_SET 0
  12. #endif
  13.  
  14. #ifndef WINDOWS
  15. typedef struct tagBITMAPFILEHEADER {
  16.     unsigned short    bfType;
  17.     unsigned long    bfSize;
  18.     unsigned short    bfReserved1;
  19.     unsigned short    bfReserved2;
  20.     unsigned long    bfOffBits;
  21. }    BITMAPFILEHEADER;
  22.  
  23. typedef struct tagBITMAPINFOHEADER {
  24.     unsigned long    biSize;
  25.     long    biWidth;
  26.     long    biHeight;
  27.     unsigned short    biPlanes;
  28.     unsigned short    biBitCount;
  29.     unsigned long    biCompression;
  30.     unsigned long    biSizeImage;
  31.     long    biXPixPerMeter;
  32.     long    biYPixPerMeter;
  33.     unsigned long    biClrUsed;
  34.     unsigned long    biClrImportant;
  35. }    BITMAPINFOHEADER;
  36. #endif
  37.  
  38. typedef struct {
  39. #ifdef WINDOWS
  40.     HFILE hfile;
  41.     OFSTRUCT openbuf;
  42. #endif
  43.     FILE *fp;
  44.     unsigned char buffer[BUFFERSIZE];
  45.     int bufferlines, buffercount;
  46.  
  47.     int offset, paloffset;
  48.  
  49.     int width, skip;
  50.     unsigned char *p;
  51.     unsigned char *paletdata;
  52.     Pixel palettedata[256];
  53.     int palettecolors;
  54.     int paletteoverflow;
  55.  
  56.     int lines;
  57.  
  58.     PicReduceData *reduce;
  59.     Pixel *pixelbuffer;
  60. }    PicWork;
  61.  
  62. static inline int palettecode(PicWork *work, Pixel c)
  63. {
  64.     int i;
  65.     for (i = 0; i < work->palettecolors; ++i) {
  66.         if (work->palettedata[i] == c) {
  67.             return i;
  68.         }
  69.     }
  70.     if (work->palettecolors >= 256) {
  71.         work->paletteoverflow++;
  72.         return 0;
  73.     }
  74.     work->palettedata[work->palettecolors] = c;
  75.     return work->palettecolors++;
  76. }
  77.  
  78. static void paletteget(PicWork *work, unsigned char *p)
  79. {
  80.     int i;
  81.     for (i = 0; i < work->palettecolors; ++i) {
  82.         *p++ = (unsigned char)((work->palettedata[i] >>  8) & 0xff);
  83.         *p++ = (unsigned char)((work->palettedata[i] >> 24));
  84.         *p++ = (unsigned char)((work->palettedata[i] >> 16) & 0xff);
  85.         *p++ = 0;
  86.     }
  87.     for (; i < 256; ++i) {
  88.         *p++ = 0;
  89.         *p++ = 0;
  90.         *p++ = 0;
  91.         *p++ = 0;
  92.     }
  93. }
  94.  
  95. #define inline
  96.  
  97. #ifdef WINDOWS
  98. static void outputshort(unsigned short n, HFILE hf)
  99. {
  100.     unsigned char c[2];
  101.     c[0] = (unsigned char)( n     & 255);
  102.     c[1] = (unsigned char)((n>>8) & 255);
  103.     _lwrite(hf, (char*)c, 2);
  104. }
  105. static void outputlong(unsigned long n, HFILE hf)
  106. {
  107.     unsigned char c[4];
  108.     c[0] = (unsigned char)( n      & 255);
  109.     c[1] = (unsigned char)((n>> 8) & 255);
  110.     c[2] = (unsigned char)((n>>16) & 255);
  111.     c[3] = (unsigned char)((n>>24) & 255);
  112.     _lwrite(hf, (char*)c, 4);
  113. }
  114. #else
  115.  
  116. static    inline void    outputshort(unsigned short n, FILE *fp)
  117. {
  118.     fputc( n & 255, fp );
  119.     fputc( ( n >> 8 ) & 255, fp );
  120. }
  121.  
  122. static    inline void    outputlong(unsigned long n, FILE *fp)
  123. {
  124.     outputshort((short)( n & 0xffffL ), fp);
  125.     outputshort((short)( ( n >> 16 ) & 0xffffL ), fp);
  126. }
  127. #endif
  128.  
  129. static    inline    unsigned short    inputshort(FILE *fp)
  130. {
  131.     unsigned short i;
  132.     i = (unsigned short)fgetc(fp);
  133.     i += (unsigned short)(fgetc(fp) * 256);
  134.     return i;
  135. }
  136.  
  137. static    inline    unsigned long    inputlong(FILE *fp)
  138. {
  139.     unsigned long i;
  140.     i = fgetc(fp);
  141.     i += fgetc(fp) <<  8;
  142.     i += fgetc(fp) << 16;
  143.     i += fgetc(fp) << 24;
  144.     return i;
  145. }
  146.  
  147.  
  148. int        PicReadHeader_BMP(PicData *pd, FILE *fp, unsigned char *magic)
  149. {
  150.     extern PicFunction PicFunction_BMP;
  151.     if (memcmp(magic, "BM", 2) != 0) {
  152.         return FALSE;
  153.     }
  154.     pd->func = &PicFunction_BMP;
  155.     return TRUE;
  156. }
  157. #define HEADER1 14
  158. #define HEADER2 40
  159. #define HEADERSIZE (HEADER1+HEADER2)
  160. #define DPM 3937
  161.  
  162. static int        PicReadHeader_BMP_Main(PicData *pd, FILE *fp)
  163. {
  164.     int i;
  165.     PicWork *work = pd->work;
  166.  
  167.     inputshort(fp);
  168.     inputlong(fp);                        /*bfSize*/
  169.     inputlong(fp);                        /*bfReserved1, bfReserved2*/
  170.     work->offset = inputlong(fp);        /*bfOffBits*/
  171. /*printf("offset = %x\n", work->offset);*/
  172.     i = inputlong(fp);                        /*biSize*/
  173.     work->paloffset = HEADER1 + i;
  174. /*printf("paletoffset = %x\n", work->paloffset);*/
  175.     pd->pixelX = (short)inputlong(fp);            /*biWidth*/
  176.     pd->pixelY = (short)inputlong(fp);            /*biHeight*/
  177. /*printf("(%d,%d)\n", pd->pixelX, pd->pixelY);*/
  178.     inputshort(fp);                        /*biPlanes*/
  179.     i = inputshort(fp);                    /*biBitCount*/
  180. /*printf("BitCount = %d\n", i);*/
  181.     if (i == 8) {
  182.         pd->mode = BMP_PALETTE;
  183.     } else if (i == 24) {
  184.         pd->mode = BMP_TRUECOLOR;
  185.     } else {
  186.         return FALSE;
  187.     }
  188.     i = inputlong(fp);                    /*biCompression, BI_RGB=0*/
  189. /*printf("BiCompression = %d\n", i);*/
  190.     if (i != 0) {
  191.         return FALSE;
  192.     }
  193. #if 0
  194.     outputlong(length, fp);                /*biSizeImage*/
  195.     outputlong(DPM, fp);                /*biXPixPerMeter*/
  196.     outputlong(DPM, fp);                /*biYPixPerMeter*/
  197.     outputlong(0, fp);                    /*biClrUsed*/
  198.     outputlong(0, fp);                    /*biClrImportant*/
  199. #endif
  200.     return TRUE;
  201. }
  202.  
  203. #ifdef WINDOWS
  204. int        PicWriteHeader_BMP(PicData *pd, HFILE fp)
  205. #else
  206. int        PicWriteHeader_BMP(PicData *pd, FILE *fp)
  207. #endif
  208. {
  209.     PicWork *work = pd->work;
  210.     int length;
  211.  
  212. #ifdef WINDOWS
  213.     _lwrite(fp, "BM", 2);
  214. #else
  215.     fputc('B', fp);
  216.     fputc('M', fp);
  217. #endif
  218.  
  219.     length = work->width * pd->pixelY;
  220. /*printf("length=%dx%d=%d\n",work->width, pd->pixelY, length);*/
  221.     if (pd->mode != BMP_TRUECOLOR) {
  222.         outputlong(length + HEADER1 + HEADER2, fp);
  223.         outputlong(0, fp);
  224.         outputlong((long)(HEADER1+HEADER2+256*4), fp);
  225.     } else {
  226.         outputlong(length + HEADER1 + HEADER2, fp);
  227.         outputlong(0, fp);
  228.         outputlong((long)(HEADER1+HEADER2), fp);
  229.     }
  230.     outputlong((long)HEADER2, fp);        /*biSize*/
  231.     outputlong((long)pd->pixelX, fp);    /*biWidth*/
  232.     outputlong((long)pd->pixelY, fp);    /*biHeight*/
  233.     outputshort(1, fp);                    /*biPlanes*/
  234.     outputshort(pd->mode == BMP_TRUECOLOR ? 24 : 8, fp);
  235.                                         /*biBitCount*/
  236.     outputlong(0L, fp);                    /*biCompression, BI_RGB=0*/
  237.     outputlong(length, fp);                /*biSizeImage*/
  238.     outputlong(DPM, fp);                /*biXPixPerMeter*/
  239.     outputlong(DPM, fp);                /*biYPixPerMeter*/
  240.     outputlong(0, fp);                    /*biClrUsed*/
  241.     outputlong(0, fp);                    /*biClrImportant*/
  242. #ifndef WINDOWS
  243.     if (ferror(fp)) return FALSE;
  244. #endif
  245.     return TRUE;
  246. }
  247.  
  248. static int        PicOpen_BMP(PicData *pd, FILE *fp, int flag)
  249. {
  250.     PicWork *work;
  251.     unsigned char pal[256*4];
  252.     int i;
  253. /*printf("Open BMP\n");*/
  254.  
  255.     if ((work = malloc(sizeof(PicWork))) == NULL) {
  256.         return FALSE;
  257.     }
  258.     pd->work = work;
  259.     work->fp = fp;
  260.     work->lines = 0;
  261.     work->reduce = NULL;
  262.     work->pixelbuffer = NULL;
  263.     if (pd->flag == PIC_READ) {
  264.         if (PicReadHeader_BMP_Main(pd, fp) == FALSE) return FALSE;
  265.         if (pd->mode == BMP_TRUECOLOR) {
  266.             work->width  = ( ( pd->pixelX * 3 + 3 ) / 4 ) * 4;
  267.             work->skip = work->width - pd->pixelX * 3;
  268.         } else {
  269.             work->width = ( ( pd->pixelX + 3 ) / 4 ) * 4;
  270.             work->skip = work->width - pd->pixelX;
  271.  
  272.             fseek(fp, work->paloffset, SEEK_SET);
  273.             if (ferror(work->fp)) return FALSE;
  274.             fread(pal, 1, 256*4, fp);
  275.             if (ferror(work->fp)) return FALSE;
  276.             for (i = 0; i < 256; i++) {
  277.                 work->palettedata[i] = (pal[i*4+1] << 24)
  278.                                      | (pal[i*4+2] << 16)
  279.                                      | (pal[i*4  ] <<  8);
  280.             }
  281.         }
  282. /*printf("width=%d, skip=%d\n", work->width, work->skip);*/
  283.         work->bufferlines = BUFFERSIZE / work->width;
  284.         work->buffercount = work->bufferlines-1;
  285.     } else {
  286.         pd->mode = flag;
  287.         if (pd->mode == BMP_TRUECOLOR) {
  288.             work->width  = ( ( pd->pixelX * 3 + 3 ) / 4 ) * 4;
  289.             work->skip = work->width - pd->pixelX * 3;
  290.         } else {
  291.             work->width = ( ( pd->pixelX + 3 ) / 4 ) * 4;
  292.             work->skip = work->width - pd->pixelX;
  293.  
  294.             work->paletteoverflow = FALSE;
  295.             work->palettecolors = 0;
  296.             if ((work->reduce = PicColorReduceOpen(pd->pixelX, REDUCE_DITHER_ERROR216)) == NULL) {
  297.                 return FALSE;
  298.             }
  299.             if ((work->pixelbuffer = malloc(sizeof(Pixel) * pd->pixelX)) == NULL) {
  300.                 return FALSE;
  301.             }
  302.         }
  303.         work->bufferlines = BUFFERSIZE / work->width;
  304.         work->buffercount = work->bufferlines-1;
  305. #ifdef WINDOWS
  306.         fclose(fp);
  307.         work->hfile = OpenFile(pd->filename, &work->openbuf, OF_WRITE | OF_SHARE_EXCLUSIVE);
  308.         if (work->hfile == HFILE_ERROR) return FALSE;
  309.         if (PicWriteHeader_BMP(pd, work->hfile) == FALSE) return FALSE;
  310. #else
  311.         if (PicWriteHeader_BMP(pd, fp) == FALSE) return FALSE;
  312. #endif
  313.     }
  314.     return TRUE;
  315. }
  316.  
  317.  
  318. static int        PicOutput_BMP(PicData *pd, Pixel *pixel)
  319. {
  320.     unsigned char *p;
  321.     PicWork *work = pd->work;
  322.     Pixel *in;
  323.     int i;
  324.     if (work->reduce && work->pixelbuffer) {
  325.         PicColorReduce(work->reduce, work->pixelbuffer, pixel);
  326.         pixel = work->pixelbuffer;
  327.     }
  328.     if (pd->mode == BMP_TRUECOLOR) {
  329.         p = work->buffer + work->width * work->buffercount;
  330.         in = pixel;
  331.         for (i = 0; i < pd->pixelX; ++i) {
  332.             *p++ = (unsigned char)((*in >>  8) & 0xff);
  333.             *p++ = (unsigned char)((*in >> 24));
  334.             *p++ = (unsigned char)((*in >> 16) & 0xff);
  335.             in++;
  336.         }
  337.         for (i = work->skip; i > 0; --i) {
  338.             *p++ = 0;
  339.         }
  340.         if (work->buffercount-- == 0) {
  341.             work->buffercount = work->bufferlines-1;
  342. #ifdef WINDOWS
  343.             if (_llseek(work->hfile, HEADERSIZE + (pd->pixelY-work->lines-1) * work->width, 0)  == HFILE_ERROR) {
  344.                 return FALSE;
  345.             }
  346.             if (_lwrite(work->hfile, (char*)work->buffer, work->width * work->bufferlines) == HFILE_ERROR) {
  347.                 return FALSE;
  348.             }
  349. #else
  350.             fseek(work->fp, HEADERSIZE + (pd->pixelY-work->lines-1) * work->width, SEEK_SET);
  351.             if (ferror(work->fp)) return FALSE;
  352.             fwrite(work->buffer, 1, work->width * work->bufferlines, work->fp);
  353.             if (ferror(work->fp)) return FALSE;
  354. #endif
  355.         }
  356.     } else {
  357.         p = work->buffer + work->width * work->buffercount;
  358.         in = pixel;
  359.         for (i = 0; i < pd->pixelX; ++i) {
  360.             *p++ = palettecode(work, *in++);
  361.         }
  362.         for (i = work->skip; i > 0; --i) {
  363.             *p++ = 0;
  364.         }
  365.         if (work->buffercount-- == 0) {
  366.             work->buffercount = work->bufferlines-1;
  367. #ifdef WINDOWS
  368.             if (_llseek(work->hfile, HEADERSIZE + 256*4 + (pd->pixelY-work->lines-1) * work->width, 0)  == HFILE_ERROR) {
  369.                 return FALSE;
  370.             }
  371.             if (_lwrite(work->hfile, (char*)work->buffer, work->width * work->bufferlines) == HFILE_ERROR) {
  372.                 return FALSE;
  373.             }
  374. #else
  375.             fseek(work->fp, HEADERSIZE + 256 * 4 + (pd->pixelY-work->lines-1) * work->width, SEEK_SET);
  376.             if (ferror(work->fp)) return FALSE;
  377.             fwrite(work->buffer, 1, work->width * work->bufferlines, work->fp);
  378.             if (ferror(work->fp)) return FALSE;
  379. #endif
  380.         }
  381.     }
  382.     work->lines++;
  383.  
  384.     return TRUE;
  385. }
  386.  
  387. static int        PicInput_BMP(PicData *pd, Pixel *pixel)
  388. {
  389.     unsigned char *p;
  390.     PicWork *work = pd->work;
  391.     Pixel *out;
  392.     int i;
  393.     if (pd->mode == BMP_TRUECOLOR) {
  394.         if (work->buffercount == work->bufferlines-1) {
  395.             if (work->buffercount > pd->pixelY-work->lines - 1) {
  396.                 work->buffercount = pd->pixelY-work->lines - 1;
  397.             }
  398.             fseek(work->fp, work->offset + (pd->pixelY-work->lines-work->buffercount - 1) * work->width, SEEK_SET);
  399.             if (ferror(work->fp)) return FALSE;
  400.             fread(work->buffer, 1, work->width * work->bufferlines, work->fp);
  401.             if (ferror(work->fp)) return FALSE;
  402.         }
  403.         p = work->buffer + work->width * work->buffercount;
  404.         out = pixel;
  405.         for (i = 0; i < pd->pixelX; ++i) {
  406.             *out++ = (p[1] << 24) | (p[0] << 8) | (p[2] << 16);
  407.             p += 3;
  408.         }
  409.         if (work->buffercount-- == 0) {
  410.             work->buffercount = work->bufferlines-1;
  411.         }
  412.     } else {
  413.         if (work->buffercount == work->bufferlines-1) {
  414.             if (work->buffercount > pd->pixelY-work->lines - 1) {
  415.                 work->buffercount = pd->pixelY-work->lines - 1;
  416.             }
  417.             fseek(work->fp, work->offset + (pd->pixelY-work->lines-work->buffercount - 1) * work->width, SEEK_SET);
  418.             if (ferror(work->fp)) return FALSE;
  419.             fread(work->buffer, 1, work->width * work->bufferlines, work->fp);
  420.             if (ferror(work->fp)) return FALSE;
  421.         }
  422.         p = work->buffer + work->width * work->buffercount;
  423.         out = pixel;
  424.         for (i = 0; i < pd->pixelX; ++i) {
  425.             *out++ = work->palettedata[*p++];
  426.         }
  427.         if (work->buffercount-- == 0) {
  428.             work->buffercount = work->bufferlines-1;
  429.         }
  430.     }
  431.     work->lines++;
  432.  
  433.     return TRUE;
  434. }
  435.  
  436. static int        PicClose_BMP(PicData *pd)
  437. {
  438.     int ret = TRUE;
  439.     PicWork *work = pd->work;
  440.     if (pd->flag == PIC_READ) {
  441.     } else {
  442.         if (pd->mode == BMP_TRUECOLOR) {
  443.             if (work->buffercount < work->bufferlines-1) {
  444. #ifdef WINDOWS
  445.                 if (_llseek(work->hfile, HEADERSIZE, 0)  == HFILE_ERROR) {
  446.                     ret = FALSE;
  447.                 }
  448.                 if (_lwrite(work->hfile,
  449.                         (char*)(work->buffer + work->width * (work->buffercount+1)),
  450.                         work->width * (work->bufferlines-1-work->buffercount)) == HFILE_ERROR) {
  451.                     ret = FALSE;
  452.                 }
  453. #else
  454.                 fseek(work->fp, HEADERSIZE, SEEK_SET);
  455.                 if (ferror(work->fp)) ret = FALSE;
  456.                 fwrite(work->buffer + work->width * (work->buffercount+1),
  457.                         1, work->width * (work->bufferlines-1-work->buffercount), work->fp);
  458.                 if (ferror(work->fp)) ret =  FALSE;
  459. #endif
  460.             }
  461.         } else {
  462.             unsigned char pal[256*4];
  463.             if (work->buffercount < work->bufferlines-1) {
  464. #ifdef WINDOWS
  465.                 if (_llseek(work->hfile, HEADERSIZE + 256*4, 0)  == HFILE_ERROR) {
  466.                     ret = FALSE;
  467.                 }
  468.                 if (_lwrite(work->hfile,
  469.                         (char*)(work->buffer + work->width * (work->buffercount+1)),
  470.                         work->width * (work->bufferlines-1-work->buffercount)) == HFILE_ERROR) {
  471.                     ret = FALSE;
  472.                 }
  473. #else
  474.                 fseek(work->fp, HEADERSIZE + 256 * 4, SEEK_SET);
  475.                 if (ferror(work->fp)) ret = FALSE;
  476.                 fwrite(work->buffer + work->width * (work->buffercount+1),
  477.                          1, work->width * (work->bufferlines-1-work->buffercount), work->fp);
  478.                 if (ferror(work->fp)) ret = FALSE;
  479. #endif
  480.             }
  481.             paletteget(work, pal);
  482. #ifdef WINDOWS
  483.             if (_llseek(work->hfile, HEADERSIZE, 0) == HFILE_ERROR) {
  484.                 ret = FALSE;
  485.             }
  486.             if (_lwrite(work->hfile, (char*)pal, 256*4) == HFILE_ERROR) {
  487.                 ret = FALSE;
  488.             }
  489. #else
  490.             fseek(work->fp, HEADERSIZE, SEEK_SET);
  491.             if (ferror(work->fp)) ret = FALSE;
  492.             fwrite(pal, 1, 256*4, work->fp);
  493.             if (ferror(work->fp)) ret=  FALSE;
  494. #endif
  495.         }
  496.         if (work->reduce) {
  497.             PicColorReduceClose(work->reduce);
  498.         }
  499.         free(work->pixelbuffer);
  500.     }
  501. #ifdef WINDOWS
  502.     if (pd->flag == PIC_READ) {
  503.         fclose(work->fp);
  504.     } else {
  505.         _lclose(work->hfile);
  506.     }
  507. #else
  508.     fclose(work->fp);
  509. #endif
  510.     free(work);
  511.     return ret;
  512. }
  513.  
  514. PicFunction PicFunction_BMP = {
  515.     "BMP",
  516.     PicReadHeader_BMP,
  517.     PicOpen_BMP,
  518.     PicOutput_BMP,
  519.     PicInput_BMP,
  520.     PicClose_BMP
  521. };
  522.  
  523.  
  524.