Malvar-He-Cutler Linear Image Demosaicking

imageio.c

Go to the documentation of this file.
00001 
00037 #include <string.h>
00038 #include <ctype.h>
00039 #include "imageio.h"
00040 
00041 #ifdef LIBPNG_SUPPORT
00042 #include <png.h>
00043 #if PNG_LIBPNG_VER < 10400
00044 /* For compatibility with older libpng */
00045 #define png_set_expand_gray_1_2_4_to_8  png_set_gray_1_2_4_to_8 
00046 #endif
00047 #endif
00048 #ifdef LIBTIFF_SUPPORT
00049 #include <tiffio.h>
00050 #endif
00051 #ifdef LIBJPEG_SUPPORT
00052 #include <jpeglib.h>
00053 #include <setjmp.h>
00054 #endif
00055 
00057 #define FILE_BUFFER_CAPACITY    (1024*4)
00058 
00059 #define ROUNDCLAMPF(x)   ((x < 0.0f) ? 0 : \
00060     ((x > 1.0f) ? 255 : (uint8_t)(255.0f*(x) + 0.5f)))
00061 #define ROUNDCLAMP(x)   ((x < 0.0) ? 0 : \
00062     ((x > 1.0) ? 255 : (uint8_t)(255.0*(x) + 0.5)))
00063 
00064 
00066 static int StringEndsWith(const char *String, const char *Suffix)
00067 {
00068     unsigned i, StringLength = strlen(String), SuffixLength = strlen(Suffix);
00069     
00070     if(StringLength < SuffixLength)
00071         return 0;
00072     
00073     String += StringLength - SuffixLength;
00074     
00075     for(i = 0; i < SuffixLength; i++)
00076         if(tolower(String[i]) != tolower(Suffix[i]))
00077             return 0;
00078     
00079     return 1;
00080 }
00081 
00082 
00084 static void FillImage(uint32_t *Image, int Width, int Height, uint32_t Color)
00085 {
00086     int x, y;
00087     
00088     if(Image)
00089         for(y = 0; y < Height; y++, Image += Width)
00090             for(x = 0; x < Width; x++)
00091                 Image[x] = Color;
00092 }
00093 
00094 
00109 static uint32_t *GetImagePalette(int *NumColors, int *UseColor, int *UseAlpha,
00110     const uint32_t *Image, int Width, int Height)
00111 {
00112     const int MaxColors = 256;
00113     uint32_t *Palette = NULL;
00114     uint32_t Pixel;
00115     int x, y, i, Red, Green, Blue, Alpha;
00116     
00117     
00118     if(!UseColor || !NumColors || !UseAlpha)
00119         return NULL;
00120     else if(!Image 
00121         || !(Palette = (uint32_t *)Malloc(sizeof(uint32_t)*MaxColors)))
00122     {
00123         *NumColors = -1;
00124         *UseColor = *UseAlpha = 1;        
00125         return NULL;
00126     }
00127     
00128     *NumColors = *UseColor = *UseAlpha = 0;
00129    
00130     for(y = 0; y < Height; y++)
00131     {
00132         for(x = 0; x < Width; x++)
00133         {
00134             Pixel = *(Image++);
00135             Red = ((uint8_t *)&Pixel)[0];
00136             Green = ((uint8_t *)&Pixel)[1];
00137             Blue = ((uint8_t *)&Pixel)[2];
00138             Alpha = ((uint8_t *)&Pixel)[3];
00139                         
00140             if(Red != Green || Red != Blue)     /* Check color */
00141                 *UseColor = 1;
00142             
00143             if(Alpha != 255)                    /* Check alpha */
00144                 *UseAlpha = 1;
00145             
00146             /* Check Palette colors (if *NumColors != -1) */
00147             for(i = 0; i < *NumColors; i++)
00148                 if(Pixel == Palette[i])
00149                     break;
00150             
00151             if(i == *NumColors)
00152             {
00153                 if(i < MaxColors)
00154                 {   /* Add new color to Palette */
00155                     Palette[i] = Pixel;
00156                     (*NumColors)++;
00157                 }
00158                 else
00159                 {   /* Maximum size for Palette exceeded */
00160                     Free(Palette);
00161                     Palette = NULL;
00162                     *NumColors = -1;    /* Don't check Palette colors */
00163                 }
00164             }
00165         }
00166     }
00167     
00168     return Palette;
00169 }
00170 
00171 
00173 static uint16_t ReadWordLE(FILE *File)
00174 {
00175     uint16_t w;
00176     w = (uint16_t) getc(File);
00177     w |= ((uint16_t) getc(File) << 8);
00178     return w;
00179 }
00180 
00181 
00183 static uint32_t ReadDWordLE(FILE *File)
00184 {
00185     uint32_t dw;
00186     dw = (uint32_t) getc(File);
00187     dw |= ((uint32_t) getc(File) << 8);
00188     dw |= ((uint32_t) getc(File) << 16);
00189     dw |= ((uint32_t) getc(File) << 24);
00190     return dw;
00191 }
00192 
00193 
00195 static void WriteWordLE(uint16_t w, FILE *File)
00196 {
00197     putc(w & 0xFF, File);
00198     putc((w & 0xFF00) >> 8, File);
00199 }
00200 
00201 
00203 static void WriteDWordLE(uint32_t dw, FILE *File)
00204 {
00205     putc(dw & 0xFF, File);
00206     putc((dw & 0xFF00) >> 8, File);
00207     putc((dw & 0xFF0000) >> 16, File);
00208     putc((dw & 0xFF000000) >> 24, File);
00209 }
00210 
00211 
00213 static int ReadBmp1Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
00214 {
00215     int RowPadding = (-(Width+7)/8)&3;
00216     int x, y, Bit;
00217     unsigned Code;
00218     
00219     Image += ((long int)Width)*((long int)Height - 1);
00220     
00221     for(y = Height; y; y--, Image -= Width)
00222     {
00223         if(feof(File))
00224             return 0;
00225         
00226         for(x = 0; x < Width;)
00227         {
00228             Code = getc(File);
00229             
00230             for(Bit = 7; Bit >= 0 && x < Width; Bit--, Code <<= 1)
00231                 Image[x++] = Palette[(Code & 0x80) ? 1:0];
00232         }
00233         
00234         for(x = RowPadding; x; x--)
00235             getc(File); /* Skip padding bytes at the end of the row */
00236     }
00237     
00238     return 1;
00239 }
00240 
00241 
00243 static int ReadBmp4Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
00244 {
00245     int RowPadding = (-(Width+1)/2)&3;
00246     int x, y;
00247     unsigned Code;
00248 
00249     Image += ((long int)Width)*((long int)Height - 1);
00250     
00251     for(y = Height; y; y--, Image -= Width)
00252     {
00253         if(feof(File))
00254             return 0;
00255         
00256         for(x = 0; x < Width;)
00257         {
00258             Code = getc(File);
00259             Image[x++] = Palette[(Code & 0xF0) >> 4];
00260             
00261             if(x < Width)
00262                 Image[x++] = Palette[Code & 0x0F];
00263         }
00264         
00265         for(x = RowPadding; x; x--)
00266             getc(File); /* Skip padding bytes at the end of the row */
00267     }
00268     
00269     return 1;
00270 }
00271 
00272 
00274 static int ReadBmp4BitRle(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
00275 {
00276     int x, y, dy, k;
00277     unsigned Count, Value;
00278     uint32_t ColorH, ColorL;
00279     
00280     FillImage(Image, Width, Height, Palette[0]);
00281     Image += ((long int)Width)*((long int)Height - 1);
00282     
00283     for(x = 0, y = Height; y;)
00284     {
00285         if(feof(File))
00286             return 0;
00287         
00288         Count = getc(File);
00289         Value = getc(File);
00290         
00291         if(!Count) 
00292         {       /* Count = 0 is the escape code */
00293             switch(Value)
00294             {
00295             case 0:     /* End of line */
00296                 Image -= Width;
00297                 x = 0;
00298                 y--;
00299                 break;
00300             case 1:     /* End of bitmap */
00301                 return 1;
00302             case 2:     /* Delta */
00303                 x += getc(File);
00304                 dy = getc(File);
00305                 y -= dy;
00306                 Image -= dy*Width;
00307                 
00308                 if(x >= Width || y < 0)
00309                     return 0;
00310                 break;
00311             default:    /* Read a run of uncompressed data (Value = length of run) */
00312                 Count = k = Value;
00313                 
00314                 if(x >= Width)
00315                     return 0;
00316 
00317                 do
00318                 {
00319                     Value = getc(File);
00320                     Image[x++] = Palette[(Value & 0xF0) >> 4];
00321                     
00322                     if(x >= Width)
00323                         break;
00324                         
00325                     if(--k)
00326                     {
00327                         Image[x++] = Palette[Value & 0x0F];
00328                         k--;
00329                         
00330                         if(x >= Width)
00331                             break;
00332                     }
00333                 }while(k);
00334                 
00335                 if(((Count + 1)/2) & 1)
00336                     getc(File); /* Padding for word align */
00337             }
00338         }
00339         else
00340         {       /* Run of pixels (Count = length of run) */
00341             ColorH = Palette[(Value & 0xF0) >> 4];
00342             ColorL = Palette[Value & 0xF];
00343             
00344             if(x >= Width)
00345                 return 0;
00346             
00347             do
00348             {
00349                 Image[x++] = ColorH;
00350                 Count--;
00351                 
00352                 if(x >= Width)
00353                     break;
00354                 
00355                 if(Count)
00356                 {
00357                     Image[x++] = ColorL;
00358                     Count--;
00359                     
00360                     if(x >= Width)
00361                         break;
00362                 }
00363             }while(Count);
00364         }
00365     }
00366     
00367     return 1;
00368 }
00369 
00370 
00372 static int ReadBmp8Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
00373 {
00374     int RowPadding = (-Width)&3;
00375     int x, y;
00376     
00377     Image += ((long int)Width)*((long int)Height - 1);
00378     
00379     for(y = Height; y; y--, Image -= Width)
00380     {
00381         if(feof(File))
00382             return 0;
00383         
00384         for(x = 0; x < Width; x++)
00385             Image[x] = Palette[getc(File) & 0xFF];
00386         
00387         for(x = RowPadding; x; x--)
00388             getc(File); /* Skip padding bytes at the end of the row */
00389     }
00390     
00391     return 1;
00392 }
00393 
00394 
00396 static int ReadBmp8BitRle(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
00397 {
00398     int x, y, dy, k;
00399     unsigned Count, Value;
00400     uint32_t Color;
00401     
00402     FillImage(Image, Width, Height, Palette[0]);
00403     Image += ((long int)Width)*((long int)Height - 1);
00404     
00405     for(x = 0, y = Height; y;)
00406     {
00407         if(feof(File))
00408             return 0;
00409             
00410         Count = getc(File);
00411         Value = getc(File);
00412         
00413         if(!Count) 
00414         {       /* Count = 0 is the escape code */
00415             switch(Value)
00416             {
00417             case 0:     /* End of line */
00418                 Image -= Width;
00419                 x = 0;
00420                 y--;
00421                 break;
00422             case 1:     /* End of bitmap */
00423                 return 1;
00424             case 2:     /* Delta */
00425                 x += getc(File);
00426                 dy = getc(File);
00427                 y -= dy;
00428                 Image -= dy*Width;
00429                 
00430                 if(x >= Width || y < 0)
00431                     return 0;
00432                 break;
00433             default:    /* Read a run of uncompressed data (Value = length of run) */
00434                 Count = k = Value;
00435                 
00436                 do
00437                 {
00438                     if(x >= Width)
00439                         break;
00440                     
00441                     Image[x++] = Palette[getc(File) & 0xFF];
00442                 }while(--k);
00443                 
00444                 if(Count&1)
00445                     getc(File); /* Padding for word align */
00446             }
00447         }
00448         else
00449         {       /* Run of pixels equal to Value (Count = length of run) */
00450             Color = Palette[Value & 0xFF];
00451             
00452             do
00453             {
00454                 if(x >= Width)
00455                     break;
00456                 
00457                 Image[x++] = Color;
00458             }while(--Count);
00459         }
00460     }
00461     
00462     return 1;
00463 }
00464 
00465 
00467 static int ReadBmp24Bit(uint32_t *Image, int Width, int Height, FILE *File)
00468 {
00469     uint8_t *ImagePtr = (uint8_t *)Image;
00470     int RowPadding = (-3*Width)&3;
00471     int x, y;
00472 
00473     
00474     Width <<= 2;
00475     ImagePtr += ((long int)Width)*((long int)Height - 1);
00476     
00477     for(y = Height; y; y--, ImagePtr -= Width)
00478     {
00479         if(feof(File))
00480             return 0;
00481         
00482         for(x = 0; x < Width; x += 4)
00483         {
00484             ImagePtr[x+3] = 255;        /* Set alpha            */
00485             ImagePtr[x+2] = getc(File); /* Read blue component  */
00486             ImagePtr[x+1] = getc(File); /* Read green component */
00487             ImagePtr[x+0] = getc(File); /* Read red component   */
00488         }
00489         
00490         for(x = RowPadding; x; x--)
00491             getc(File); /* Skip padding bytes at the end of the row */
00492     }
00493     
00494     return 1;
00495 }
00496 
00498 static void GetMaskShifts(uint32_t Mask, int *LeftShift, int *RightShift)
00499 {
00500     int Shift = 0, BitCount = 0;
00501     
00502     if(!Mask)
00503     {
00504         *LeftShift = 0;
00505         *RightShift = 0;
00506         return;
00507     }
00508     
00509     while(!(Mask & 1))  /* Find the first true bit */
00510     {
00511         Mask >>= 1;
00512         ++Shift;
00513     }
00514     
00515     /* Adjust the result for scaling to 8-bit quantities */
00516     while(Mask & 1)             /* Count the number of true bits */
00517     {
00518         Mask >>= 1;
00519         ++BitCount;
00520     }
00521     
00522     /* Compute a signed shift (right is positive) */
00523     Shift += BitCount - 8;
00524     
00525     if(Shift >= 0)
00526     {
00527         *LeftShift = 0;
00528         *RightShift = Shift;
00529     }
00530     else
00531     {
00532         *LeftShift = -Shift;
00533         *RightShift = 0;
00534     }
00535 }
00536 
00538 static int ReadBmp16Bit(uint32_t *Image, int Width, int Height, FILE *File, 
00539     uint32_t RedMask, uint32_t GreenMask, uint32_t BlueMask, uint32_t AlphaMask)
00540 {
00541     uint8_t *ImagePtr = (uint8_t *)Image;
00542     uint32_t Code;
00543     int RowPadding = (-2*Width)&3;
00544     int RedLeftShift, GreenLeftShift, BlueLeftShift, AlphaLeftShift;
00545     int RedRightShift, GreenRightShift, BlueRightShift, AlphaRightShift;
00546     int x, y;
00547     
00548     GetMaskShifts(RedMask, &RedLeftShift, &RedRightShift);
00549     GetMaskShifts(GreenMask, &GreenLeftShift, &GreenRightShift);
00550     GetMaskShifts(BlueMask, &BlueLeftShift, &BlueRightShift);
00551     GetMaskShifts(AlphaMask, &AlphaLeftShift, &AlphaRightShift);
00552     Width <<= 2;
00553     ImagePtr += ((long int)Width)*((long int)Height - 1);
00554     
00555     for(y = Height; y; y--, ImagePtr -= Width)
00556     {
00557         if(feof(File))
00558             return 0;
00559         
00560         for(x = 0; x < Width; x += 4)
00561         {
00562             Code = ReadWordLE(File);
00563             /* By the Windows 4.x BMP specification, color component masks must be contiguous
00564             [http://www.fileformat.info/format/bmp/egff.htm].  So we can decode the bitfields
00565             by bitwise AND with the mask and applying a bitshift.*/
00566             ImagePtr[x+3] = ((Code & AlphaMask) >> AlphaRightShift) << AlphaLeftShift;
00567             ImagePtr[x+2] = ((Code & BlueMask ) >> BlueRightShift ) << BlueLeftShift;
00568             ImagePtr[x+1] = ((Code & GreenMask) >> GreenRightShift) << GreenLeftShift;
00569             ImagePtr[x+0] = ((Code & RedMask  ) >> RedRightShift  ) << RedLeftShift;
00570         }
00571         
00572         for(x = RowPadding; x; x--)
00573             getc(File); /* Skip padding bytes at the end of the row */
00574     }
00575 
00576     return 1;
00577 }
00578 
00579 
00581 static int ReadBmp32Bit(uint32_t *Image, int Width, int Height, FILE *File,
00582     uint32_t RedMask, uint32_t GreenMask, uint32_t BlueMask, uint32_t AlphaMask)
00583 {
00584     uint8_t *ImagePtr;
00585     uint32_t Code;
00586     int RedLeftShift, GreenLeftShift, BlueLeftShift, AlphaLeftShift;
00587     int RedRightShift, GreenRightShift, BlueRightShift, AlphaRightShift;
00588     int x, y;
00589     
00590     GetMaskShifts(RedMask, &RedLeftShift, &RedRightShift);
00591     GetMaskShifts(GreenMask, &GreenLeftShift, &GreenRightShift);
00592     GetMaskShifts(BlueMask, &BlueLeftShift, &BlueRightShift);
00593     GetMaskShifts(AlphaMask, &AlphaLeftShift, &AlphaRightShift);
00594     Width <<= 2;
00595     ImagePtr = (uint8_t *)Image + ((long int)Width)*((long int)Height - 1);
00596     
00597     for(y = Height; y; y--, ImagePtr -= Width)
00598     {
00599         if(feof(File))
00600             return 0;
00601         
00602         for(x = 0; x < Width; x += 4)
00603         {
00604             Code = ReadDWordLE(File);
00605             /* By the Windows 4.x BMP specification, color component masks must be contiguous
00606             [http://www.fileformat.info/format/bmp/egff.htm].  So we can decode the bitfields
00607             by bitwise AND with the mask and applying a bitshift.*/
00608             ImagePtr[x+3] = ((Code & AlphaMask) >> AlphaRightShift) << AlphaLeftShift;
00609             ImagePtr[x+2] = ((Code & BlueMask ) >> BlueRightShift ) << BlueLeftShift;
00610             ImagePtr[x+1] = ((Code & GreenMask) >> GreenRightShift) << GreenLeftShift;
00611             ImagePtr[x+0] = ((Code & RedMask  ) >> RedRightShift  ) << RedLeftShift;
00612         }
00613     }
00614 
00615     return 1;
00616 }
00617 
00631 static int ReadBmp(uint32_t **Image, int *Width, int *Height, FILE *File)
00632 {
00633     uint32_t *Palette = NULL;
00634     uint8_t *PalettePtr;
00635     long int ImageDataOffset, InfoSize;
00636     unsigned i, NumPlanes, BitsPerPixel, Compression, NumColors;
00637     uint32_t RedMask, GreenMask, BlueMask, AlphaMask;
00638     int Success = 0, Os2Bmp;
00639     uint8_t Magic[2];
00640     
00641     *Image = NULL;
00642     *Width = *Height = 0;
00643     fseek(File, 0, SEEK_SET);
00644 
00645     Magic[0] = getc(File);
00646     Magic[1] = getc(File);
00647 
00648     if(!(Magic[0] == 0x42 && Magic[1] == 0x4D) /* Verify the magic numbers */
00649         || fseek(File, 8, SEEK_CUR))         /* Skip the reserved fields */
00650     {
00651         ErrorMessage("Invalid BMP header.\n");
00652         goto Catch;
00653     }
00654     
00655     ImageDataOffset = ReadDWordLE(File);
00656     InfoSize = ReadDWordLE(File);
00657     
00658     /* Read the info header */
00659     if(InfoSize < 12)
00660     {
00661         ErrorMessage("Invalid BMP info header.\n");
00662         goto Catch;
00663     }
00664     
00665     if((Os2Bmp = (InfoSize == 12)))  /* This is an OS/2 V1 infoheader */
00666     {
00667         *Width = (int)ReadWordLE(File);
00668         *Height = (int)ReadWordLE(File);
00669         NumPlanes = (unsigned)ReadWordLE(File);
00670         BitsPerPixel = (unsigned)ReadWordLE(File);
00671         Compression = 0;
00672         NumColors = 0;
00673         RedMask = 0x00FF0000;
00674         GreenMask = 0x0000FF00;
00675         BlueMask = 0x000000FF;
00676         AlphaMask = 0xFF000000;
00677     }
00678     else
00679     {
00680         *Width = abs((int)ReadDWordLE(File));
00681         *Height = abs((int)ReadDWordLE(File));
00682         NumPlanes = (unsigned)ReadWordLE(File);
00683         BitsPerPixel = (unsigned)ReadWordLE(File);
00684         Compression = (unsigned)ReadDWordLE(File);
00685         fseek(File, 12, SEEK_CUR);
00686         NumColors = (unsigned)ReadDWordLE(File);
00687         fseek(File, 4, SEEK_CUR);
00688         RedMask = ReadDWordLE(File);
00689         GreenMask = ReadDWordLE(File);
00690         BlueMask = ReadDWordLE(File);
00691         AlphaMask = ReadDWordLE(File);
00692     }
00693     
00694     /* Check for problems or unsupported compression modes */
00695     if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
00696     {
00697         ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
00698         goto Catch;
00699     }
00700     
00701     if(feof(File) || NumPlanes != 1 || Compression > 3)
00702         goto Catch;
00703     
00704     /* Allocate the image data */
00705     if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)*((long int)*Width)*((long int)*Height))))
00706         goto Catch;
00707     
00708     /* Read palette */
00709     if(BitsPerPixel <= 8)
00710     {
00711         fseek(File, 14 + InfoSize, SEEK_SET);
00712         
00713         if(!NumColors)
00714             NumColors = 1 << BitsPerPixel;
00715         
00716         if(!(Palette = (uint32_t *)Malloc(sizeof(uint32_t)*256)))
00717             goto Catch;
00718         
00719         for(i = 0, PalettePtr = (uint8_t *)Palette; i < NumColors; i++)
00720         {
00721             PalettePtr[3] = 255;          /* Set alpha            */
00722             PalettePtr[2] = getc(File);   /* Read blue component  */
00723             PalettePtr[1] = getc(File);   /* Read green component */
00724             PalettePtr[0] = getc(File);   /* Read red component   */
00725             PalettePtr += 4;
00726             
00727             if(!Os2Bmp)
00728                 getc(File); /* Skip extra byte (for non-OS/2 bitmaps) */
00729         }
00730         
00731         for(; i < 256; i++)  /* Fill the rest of the palette with the first color */
00732             Palette[i] = Palette[0];
00733     }
00734     
00735     if(fseek(File, ImageDataOffset, SEEK_SET) || feof(File))
00736     {
00737         ErrorMessage("File error.\n");
00738         goto Catch;
00739     }
00740     
00741     /*** Read the bitmap image data ***/
00742     switch(Compression)
00743     {
00744         case 0: /* Uncompressed data */
00745             switch(BitsPerPixel)
00746             {
00747             case 1: /* Read 1-bit uncompressed indexed data */
00748                 Success = ReadBmp1Bit(*Image, *Width, *Height, File, Palette);
00749                 break;
00750             case 4: /* Read 4-bit uncompressed indexed data */
00751                 Success = ReadBmp4Bit(*Image, *Width, *Height, File, Palette);
00752                 break;
00753             case 8: /* Read 8-bit uncompressed indexed data */
00754                 Success = ReadBmp8Bit(*Image, *Width, *Height, File, Palette);
00755                 break;
00756             case 24: /* Read 24-bit BGR image data */
00757                 Success = ReadBmp24Bit(*Image, *Width, *Height, File);
00758                 break;
00759             case 16: /* Read 16-bit data */
00760                 Success = ReadBmp16Bit(*Image, *Width, *Height, File,
00761                     0x001F << 10, 0x001F << 5, 0x0001F, 0);
00762                 break;
00763             case 32: /* Read 32-bit BGRA image data */
00764                 Success = ReadBmp32Bit(*Image, *Width, *Height, File,
00765                     0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
00766                 break;
00767             }
00768             break;
00769         case 1: /* 8-bit RLE */
00770             if(BitsPerPixel == 8)
00771                 Success = ReadBmp8BitRle(*Image, *Width, *Height, File, Palette);
00772             break;
00773         case 2: /* 4-bit RLE */
00774             if(BitsPerPixel == 4)
00775                 Success = ReadBmp4BitRle(*Image, *Width, *Height, File, Palette);
00776             break;
00777         case 3: /* Bitfields data */
00778             switch(BitsPerPixel)
00779             {
00780             case 16: /* Read 16-bit bitfields data */
00781                 Success = ReadBmp16Bit(*Image, *Width, *Height, File, 
00782                     RedMask, GreenMask, BlueMask, AlphaMask);
00783                 break;
00784             case 32: /* Read 32-bit bitfields data */
00785                 Success = ReadBmp32Bit(*Image, *Width, *Height, File, 
00786                     RedMask, GreenMask, BlueMask, AlphaMask);
00787                 break;
00788             }
00789             break;
00790     }
00791     
00792     if(!Success)
00793         ErrorMessage("Error reading BMP data.\n");
00794     
00795 Catch:  /* There was a problem, clean up and exit */
00796     if(Palette)
00797         Free(Palette);
00798     
00799     if(!Success && *Image)
00800         Free(*Image);
00801     
00802     return Success;
00803 }
00804 
00805 
00827 static int WriteBmp(const uint32_t *Image, int Width, int Height, FILE *File)
00828 {
00829     const uint8_t *ImagePtr = (uint8_t *)Image;
00830     uint32_t *Palette = NULL;
00831     uint32_t Pixel;
00832     long int ImageSize; 
00833     int UsePalette, NumColors, UseColor, UseAlpha;
00834     int x, y, i, RowPadding, Success = 0;
00835 
00836     
00837     if(!Image)
00838         return 0;
00839     
00840     Palette = GetImagePalette(&NumColors, &UseColor, &UseAlpha,
00841         Image, Width, Height);
00842     
00843     /* Decide whether to use 8-bit palette or 24-bit RGB format */     
00844     if(Palette && 2*NumColors < Width*Height)
00845         UsePalette = 1;        
00846     else
00847         UsePalette = NumColors = 0;
00848     
00849     /* Tell File to use buffering */
00850     setvbuf(File, 0, _IOFBF, FILE_BUFFER_CAPACITY);
00851     
00852     if(UsePalette)
00853     {
00854         RowPadding = (-Width)&3;
00855         ImageSize = (Width + RowPadding)*((long int)Height);
00856     }
00857     else
00858     {
00859         RowPadding = (-3*Width)&3;
00860         ImageSize = (3*Width + RowPadding)*((long int)Height);
00861     }
00862     
00863     /*** Write the header ***/
00864     
00865     /* Write the BMP header */
00866     putc(0x42, File);                       /* Magic numbers             */
00867     putc(0x4D, File);
00868     
00869     /* Filesize */
00870     WriteDWordLE(54 + 4*NumColors + ImageSize, File);
00871     
00872     WriteDWordLE(0, File);                  /* Reserved fields           */
00873     WriteDWordLE(54 + 4*NumColors, File);   /* Image data offset */
00874     
00875     /* Write the infoheader */
00876     WriteDWordLE(40, File);                 /* Infoheader size           */
00877     WriteDWordLE(Width, File);              /* Image width               */
00878     WriteDWordLE(Height, File);             /* Image height              */
00879     WriteWordLE(1, File);                   /* Number of colorplanes     */        
00880     WriteWordLE((UsePalette) ? 8:24, File); /* Bits per pixel */    
00881     WriteDWordLE(0, File);                  /* Compression method (none) */
00882     WriteDWordLE(ImageSize, File);          /* Image size                */
00883     WriteDWordLE(2835, File);               /* HResolution (2835=72dpi)  */
00884     WriteDWordLE(2835, File);               /* VResolution               */
00885     
00886     /* Number of colors */
00887     WriteDWordLE((!UsePalette || NumColors == 256) ? 0:NumColors, File);
00888     
00889     WriteDWordLE(0, File);                  /* Important colors          */
00890     
00891     if(ferror(File))
00892     {
00893         ErrorMessage("Error during write to file.\n");
00894         goto Catch;
00895     }
00896     
00897     if(UsePalette)
00898     {   /* Write the Palette */
00899         for(i = 0; i < NumColors; i++)
00900         {
00901             Pixel = Palette[i];
00902             putc(((uint8_t *)&Pixel)[2], File);     /* Blue   */
00903             putc(((uint8_t *)&Pixel)[1], File);     /* Green  */
00904             putc(((uint8_t *)&Pixel)[0], File);     /* Red    */
00905             putc(0, File);                          /* Unused */
00906         }
00907     }
00908     
00909     /* Write the image data */
00910     Width <<= 2;
00911     ImagePtr += ((long int)Width)*((long int)Height - 1);
00912             
00913     for(y = Height; y; y--, ImagePtr -= Width)
00914     {
00915         if(UsePalette)
00916         {   /* 8-bit palette image data */
00917             for(x = 0; x < Width; x += 4)
00918             {
00919                 Pixel = *((uint32_t *)(ImagePtr + x));
00920                 
00921                 for(i = 0; i < NumColors; i++)
00922                     if(Pixel == Palette[i])
00923                         break;
00924                 
00925                 putc(i, File);
00926             }
00927         }
00928         else 
00929         {   /* 24-bit RGB image data */
00930             for(x = 0; x < Width; x += 4)
00931             {
00932                 putc(ImagePtr[x+2], File);  /* Write blue component  */
00933                 putc(ImagePtr[x+1], File);  /* Write green component */
00934                 putc(ImagePtr[x+0], File);  /* Write red component   */
00935             }
00936         }
00937         
00938         for(x = RowPadding; x; x--)         /* Write row padding */
00939             putc(0, File);
00940     }    
00941     
00942     if(ferror(File))
00943     {
00944         ErrorMessage("Error during write to file.\n");
00945         goto Catch;
00946     }
00947     
00948     Success = 1;
00949 Catch:    
00950     if(Palette)
00951         Free(Palette);
00952     return Success;
00953 }
00954 
00955 
00956 #ifdef LIBJPEG_SUPPORT
00957 
00963 typedef struct{
00964     struct jpeg_error_mgr pub;
00965     jmp_buf jmpbuf;
00966 } hooked_jerr;
00967 
00968 
00970 METHODDEF(void) JerrExit(j_common_ptr cinfo)
00971 {
00972     hooked_jerr *Jerr = (hooked_jerr *) cinfo->err;
00973     (*cinfo->err->output_message)(cinfo);
00974     longjmp(Jerr->jmpbuf, 1);
00975 }
00976 
00977 
00991 static int ReadJpeg(uint32_t **Image, int *Width, int *Height, FILE *File)
00992 {
00993     struct jpeg_decompress_struct cinfo;
00994     hooked_jerr Jerr;
00995     JSAMPARRAY Buffer;
00996     uint8_t *ImagePtr;
00997     unsigned i, RowSize;
00998     
00999     *Image = 0;
01000     *Width = *Height = 0;
01001     cinfo.err = jpeg_std_error(&Jerr.pub);
01002     Jerr.pub.error_exit = JerrExit;
01003     
01004     if(setjmp(Jerr.jmpbuf))     
01005         goto Catch;     /* If this code is reached, libjpeg has signaled an error. */
01006     
01007     jpeg_create_decompress(&cinfo);
01008     jpeg_stdio_src(&cinfo, File);
01009     jpeg_read_header(&cinfo, 1);
01010     cinfo.out_color_space = JCS_RGB;   /* Ask for RGB image data */
01011     jpeg_start_decompress(&cinfo);
01012     *Width = (int)cinfo.output_width;
01013     *Height = (int)cinfo.output_height;
01014     
01015     if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
01016     {
01017         ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
01018         jpeg_abort_decompress(&cinfo);
01019         goto Catch;
01020     }
01021     
01022     /* Allocate image memory */
01023     if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)
01024         *((size_t)*Width)*((size_t)*Height))))
01025     {
01026         jpeg_abort_decompress(&cinfo);
01027         goto Catch;
01028     }
01029     
01030     /* Allocate a one-row-high array that will go away when done */
01031     RowSize = cinfo.output_width * cinfo.output_components;
01032     Buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, 
01033         JPOOL_IMAGE, RowSize, 1);
01034     ImagePtr = (uint8_t *)*Image;
01035     
01036     while(cinfo.output_scanline < cinfo.output_height)
01037         for(jpeg_read_scanlines(&cinfo, Buffer, 1), i = 0; i < RowSize; i += 3)
01038         {
01039             *(ImagePtr++) = Buffer[0][i];   /* Red   */
01040             *(ImagePtr++) = Buffer[0][i+1]; /* Green */
01041             *(ImagePtr++) = Buffer[0][i+2]; /* Blue  */
01042             *(ImagePtr++) = 0xFF;
01043         }
01044 
01045     jpeg_finish_decompress(&cinfo);
01046     jpeg_destroy_decompress(&cinfo);
01047     return 1;
01048     
01049 Catch:
01050     if(*Image)
01051         Free(*Image);
01052     
01053     *Width = *Height = 0;
01054     jpeg_destroy_decompress(&cinfo);
01055     return 0;
01056 }
01057 
01058 
01077 static int WriteJpeg(const uint32_t *Image, int Width, int Height, 
01078     FILE *File, int Quality)
01079 {
01080     struct jpeg_compress_struct cinfo;
01081     hooked_jerr Jerr;
01082     uint8_t *Buffer = 0, *ImagePtr;
01083     unsigned i, RowSize;
01084 
01085 
01086     if(!Image)
01087         return 0;
01088     
01089     cinfo.err = jpeg_std_error(&Jerr.pub);
01090     Jerr.pub.error_exit = JerrExit;
01091     
01092     if(setjmp(Jerr.jmpbuf))
01093         goto Catch;     /* If this code is reached, libjpeg has signaled an error. */
01094     
01095     jpeg_create_compress(&cinfo);
01096     jpeg_stdio_dest(&cinfo, File);
01097     cinfo.image_width = Width;
01098     cinfo.image_height = Height;
01099     cinfo.input_components = 3;
01100     cinfo.in_color_space = JCS_RGB;
01101     jpeg_set_defaults(&cinfo);
01102     jpeg_set_quality(&cinfo, (Quality < 100) ? Quality : 100, 1);
01103     jpeg_start_compress(&cinfo, 1);
01104 
01105     RowSize = 3*Width;
01106     ImagePtr = (uint8_t *)Image;
01107 
01108     if(!(Buffer = (uint8_t *)Malloc(RowSize)))
01109         goto Catch;
01110     
01111     while(cinfo.next_scanline < cinfo.image_height)
01112     {
01113         for(i = 0; i < RowSize; i += 3)
01114         {
01115             Buffer[i] = ImagePtr[0];   /* Red   */
01116             Buffer[i+1] = ImagePtr[1]; /* Green */
01117             Buffer[i+2] = ImagePtr[2]; /* Blue  */
01118             ImagePtr += 4;
01119         }
01120 
01121         jpeg_write_scanlines(&cinfo, &Buffer, 1);
01122     }
01123 
01124     if(Buffer)
01125         Free(Buffer);
01126 
01127     jpeg_finish_compress(&cinfo);
01128     jpeg_destroy_compress(&cinfo);
01129     return 1;
01130 Catch:
01131     if(Buffer)
01132         Free(Buffer);
01133 
01134     jpeg_destroy_compress(&cinfo);
01135     return 0;
01136 }
01137 #endif /* LIBJPEG_SUPPORT */
01138 
01139 
01140 #ifdef LIBPNG_SUPPORT
01141 
01154 static int ReadPng(uint32_t **Image, int *Width, int *Height, FILE *File)
01155 {
01156     png_bytep *RowPointers;
01157     png_byte Header[8];
01158     png_structp Png;
01159     png_infop Info;
01160     png_uint_32 PngWidth, PngHeight;
01161     int BitDepth, ColorType, InterlaceType;
01162     unsigned Row;
01163     
01164     *Image = 0;
01165     *Width = *Height = 0;
01166     
01167     /* Check that file is a PNG file */
01168     if(fread(Header, 1, 8, File) != 8 || png_sig_cmp(Header, 0, 8))
01169         return 0;
01170     
01171     /* Read the info header */
01172     if(!(Png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))
01173         || !(Info = png_create_info_struct(Png)))
01174     {
01175         if(Png)
01176             png_destroy_read_struct(&Png, (png_infopp)NULL, (png_infopp)NULL);
01177         
01178         return 0;
01179     }
01180         
01181     if(setjmp(png_jmpbuf(Png)))
01182         goto Catch; /* If this code is reached, libpng has signaled an error. */
01183     
01184     png_init_io(Png, File);
01185     png_set_sig_bytes(Png, 8);
01186     png_set_user_limits(Png, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
01187     png_read_info(Png, Info);
01188     png_get_IHDR(Png, Info, &PngWidth, &PngHeight, &BitDepth, &ColorType,
01189         &InterlaceType, (int*)NULL, (int*)NULL);
01190     *Width = (int)PngWidth;
01191     *Height = (int)PngHeight;
01192     
01193     /* Tell libpng to convert everything to 32-bit RGBA */
01194     if(ColorType == PNG_COLOR_TYPE_PALETTE)
01195         png_set_palette_to_rgb(Png);
01196     if(ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
01197         png_set_expand_gray_1_2_4_to_8(Png);
01198     if(ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
01199         png_set_gray_to_rgb(Png);
01200     if(png_get_valid(Png, Info, PNG_INFO_tRNS))
01201         png_set_tRNS_to_alpha(Png);
01202     
01203     png_set_strip_16(Png);
01204     png_set_filler(Png, 0xFF, PNG_FILLER_AFTER);
01205 
01206     png_set_interlace_handling(Png);
01207     png_read_update_info(Png, Info);
01208     
01209     /* Allocate image memory and row pointers */
01210     if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)
01211         *((size_t)*Width)*((size_t)*Height)))
01212         || !(RowPointers = (png_bytep *)Malloc(sizeof(png_bytep)
01213         *PngHeight)))
01214         goto Catch;
01215 
01216     for(Row = 0; Row < PngHeight; Row++)
01217         RowPointers[Row] = (png_bytep)(*Image + PngWidth*Row);
01218     
01219     /* Read the image data */
01220     png_read_image(Png, RowPointers);
01221     Free(RowPointers);
01222     png_destroy_read_struct(&Png, &Info, (png_infopp)NULL);
01223     return 1;
01224     
01225 Catch:
01226     if(*Image)
01227         Free(*Image);
01228     
01229     *Width = *Height = 0;
01230     png_destroy_read_struct(&Png, &Info, (png_infopp)NULL);
01231     return 0;
01232 }
01233 
01234 
01255 static int WritePng(const uint32_t *Image, int Width, int Height, FILE *File)
01256 {
01257     const uint32_t *ImagePtr;
01258     uint32_t *Palette = NULL;
01259     uint8_t *RowBuffer;
01260     png_structp Png;
01261     png_infop Info;
01262     png_color PngPalette[256];
01263     png_byte PngTrans[256];    
01264     uint32_t Pixel;
01265     int PngColorType, NumColors, UseColor, UseAlpha;
01266     int x, y, i, Success = 0;
01267 
01268     
01269     if(!Image)
01270         return 0;
01271     
01272     if(!(RowBuffer = (uint8_t *)Malloc(4*Width)))
01273         return 0;
01274     
01275     if(!(Png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
01276         NULL, NULL, NULL))
01277         || !(Info = png_create_info_struct(Png)))
01278     {
01279         if(Png)
01280             png_destroy_write_struct(&Png, (png_infopp)NULL);
01281     
01282         Free(RowBuffer);
01283         return 0;
01284     }
01285         
01286     if(setjmp(png_jmpbuf(Png)))
01287     {   /* If this code is reached, libpng has signaled an error. */
01288         goto Catch;
01289     }
01290 
01291     /* Configure PNG output */
01292     png_init_io(Png, File);
01293     png_set_compression_level(Png, Z_BEST_COMPRESSION);
01294     
01295     Palette = GetImagePalette(&NumColors, &UseColor, &UseAlpha,
01296         Image, Width, Height);    
01297         
01298     /* The PNG image is written according to the analysis of GetImagePalette */
01299     if(Palette && UseColor)
01300         PngColorType = PNG_COLOR_TYPE_PALETTE;
01301     else if(UseAlpha)
01302         PngColorType = PNG_COLOR_TYPE_RGB_ALPHA;
01303     else if(UseColor)
01304         PngColorType = PNG_COLOR_TYPE_RGB;
01305     else
01306         PngColorType = PNG_COLOR_TYPE_GRAY;
01307     
01308     png_set_IHDR(Png, Info, Width, Height, 8, PngColorType,
01309         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
01310         
01311     if(PngColorType == PNG_COLOR_TYPE_PALETTE)
01312     {
01313         for(i = 0; i < NumColors; i++)
01314         {
01315             Pixel = Palette[i];
01316             PngPalette[i].red = ((uint8_t *)&Pixel)[0];
01317             PngPalette[i].green = ((uint8_t *)&Pixel)[1];
01318             PngPalette[i].blue = ((uint8_t *)&Pixel)[2];
01319             PngTrans[i] = ((uint8_t *)&Pixel)[3];
01320         }
01321         
01322         png_set_PLTE(Png, Info, PngPalette, NumColors);
01323         
01324         if(UseAlpha)
01325             png_set_tRNS(Png, Info, PngTrans, NumColors, NULL);
01326     }
01327     
01328     png_write_info(Png, Info);
01329     
01330     for(y = 0, ImagePtr = Image; y < Height; y++, ImagePtr += Width)
01331     {
01332         switch(PngColorType)
01333         {
01334         case PNG_COLOR_TYPE_RGB_ALPHA:               
01335             png_write_row(Png, (png_bytep)Image);
01336             break;
01337         case PNG_COLOR_TYPE_RGB:
01338             for(x = 0; x < Width; x++)
01339             {
01340                 Pixel = ImagePtr[x];
01341                 RowBuffer[3*x + 0] = ((uint8_t *)&Pixel)[0];
01342                 RowBuffer[3*x + 1] = ((uint8_t *)&Pixel)[1];
01343                 RowBuffer[3*x + 2] = ((uint8_t *)&Pixel)[2];
01344             }
01345             
01346             png_write_row(Png, (png_bytep)RowBuffer);
01347             break;
01348         case PNG_COLOR_TYPE_GRAY:
01349             for(x = 0; x < Width; x++)
01350             {
01351                 Pixel = ImagePtr[x];
01352                 RowBuffer[x] = ((uint8_t *)&Pixel)[0];
01353             }
01354             
01355             png_write_row(Png, (png_bytep)RowBuffer);
01356             break;
01357         case PNG_COLOR_TYPE_PALETTE:
01358             for(x = 0; x < Width; x++)
01359             {
01360                 Pixel = ImagePtr[x];
01361                 
01362                 for(i = 0; i < NumColors; i++)
01363                     if(Pixel == Palette[i])
01364                         break;
01365                                     
01366                 RowBuffer[x] = i;
01367             }
01368             
01369             png_write_row(Png, (png_bytep)RowBuffer);
01370             break;
01371         }
01372     }
01373 
01374     png_write_end(Png, Info);
01375     Success = 1;
01376 Catch:        
01377     if(Palette)
01378         Free(Palette);
01379     png_destroy_write_struct(&Png, &Info);        
01380     Free(RowBuffer);
01381     return Success;
01382 }
01383 #endif /* LIBPNG_SUPPORT */
01384 
01385 
01386 #ifdef LIBTIFF_SUPPORT
01387 
01400 static int ReadTiff(uint32_t **Image, int *Width, int *Height, 
01401     const char *FileName, unsigned Directory)
01402 {
01403     TIFF *Tiff;
01404     uint32 ImageWidth, ImageHeight;
01405 
01406     *Image = 0;
01407     *Width = *Height = 0;
01408     
01409     if(!(Tiff = TIFFOpen(FileName, "r")))
01410     {
01411         ErrorMessage("TIFFOpen failed to open file.\n");
01412         return 0;
01413     }
01414     
01415     TIFFSetDirectory(Tiff, Directory);
01416     TIFFGetField(Tiff, TIFFTAG_IMAGEWIDTH, &ImageWidth);
01417     TIFFGetField(Tiff, TIFFTAG_IMAGELENGTH, &ImageHeight);
01418     *Width = (int)ImageWidth;
01419     *Height = (int)ImageHeight;
01420     
01421     if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
01422     {
01423         ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
01424         goto Catch;
01425     }
01426     
01427     if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)*ImageWidth*ImageHeight)))
01428         goto Catch;
01429     
01430     if(!TIFFReadRGBAImageOriented(Tiff, ImageWidth, ImageHeight, *Image, 
01431         ORIENTATION_TOPLEFT, 1))
01432         goto Catch;
01433     
01434     TIFFClose(Tiff);
01435     return 1;
01436     
01437 Catch:
01438     if(*Image)
01439         Free(*Image);
01440     
01441     *Width = *Height = 0;
01442     TIFFClose(Tiff);
01443     return 0;
01444 }
01445 
01446 
01460 static int WriteTiff(const uint32_t *Image, int Width, int Height, 
01461     const char *FileName)
01462 {
01463     TIFF *Tiff;
01464     uint16 Alpha = EXTRASAMPLE_ASSOCALPHA;
01465 
01466     if(!Image)
01467         return 0;
01468     
01469     if(!(Tiff = TIFFOpen(FileName, "w")))
01470     {
01471         ErrorMessage("TIFFOpen failed to open file.\n");
01472         return 0;
01473     }
01474     
01475     if(TIFFSetField(Tiff, TIFFTAG_IMAGEWIDTH, Width) != 1
01476         || TIFFSetField(Tiff, TIFFTAG_IMAGELENGTH, Height) != 1
01477         || TIFFSetField(Tiff, TIFFTAG_SAMPLESPERPIXEL, 4) != 1
01478         || TIFFSetField(Tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) != 1
01479         || TIFFSetField(Tiff, TIFFTAG_EXTRASAMPLES, 1, &Alpha) != 1
01480         || TIFFSetField(Tiff, TIFFTAG_BITSPERSAMPLE, 8) != 1
01481         || TIFFSetField(Tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT) != 1
01482         || TIFFSetField(Tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) != 1
01483         /* Compression can be COMPRESSION_NONE, COMPRESSION_DEFLATE, 
01484         COMPRESSION_LZW, or COMPRESSION_JPEG */
01485         || TIFFSetField(Tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE) != 1)
01486     {
01487         ErrorMessage("TIFFSetField failed.\n");
01488         TIFFClose(Tiff);
01489         return 0;
01490     }
01491     
01492     if(TIFFWriteEncodedStrip(Tiff, 0, (tdata_t)Image, 4*((size_t)Width)*((size_t)Height)) < 0)
01493     {
01494         ErrorMessage("Error writing data to file.\n");
01495         TIFFClose(Tiff);
01496         return 0;
01497     }
01498 
01499     TIFFClose(Tiff);
01500     return 1;
01501 }
01502 #endif /* LIBTIFF_SUPPORT */
01503 
01504 
01506 static void *ConvertToFormat(uint32_t *Src, int Width, int Height, 
01507     unsigned Format)
01508 {
01509     const int NumPixels = Width*Height;
01510     const int NumChannels = (Format & IMAGEIO_GRAYSCALE) ? 
01511         1 : ((Format & IMAGEIO_STRIP_ALPHA) ? 3 : 4);    
01512     const int ChannelStride = (Format & IMAGEIO_PLANAR) ? NumPixels : 1;
01513     const int ChannelStride2 = 2*ChannelStride;
01514     const int ChannelStride3 = 3*ChannelStride;
01515     double *DestD;
01516     float *DestF;
01517     uint8_t *DestU8;
01518     uint32_t Pixel;
01519     int Order[4] = {0, 1, 2, 3};
01520     int i, x, y, PixelStride, RowStride;
01521     
01522     
01523     PixelStride = (Format & IMAGEIO_PLANAR) ? 1 : NumChannels;
01524     
01525     if(Format & IMAGEIO_COLUMNMAJOR)
01526     {
01527         RowStride = PixelStride;
01528         PixelStride *= Height;
01529     }
01530     else
01531         RowStride = Width*PixelStride;
01532     
01533     if(Format & IMAGEIO_BGRFLIP)
01534     {
01535         Order[0] = 2;
01536         Order[2] = 0;
01537     }
01538     
01539     if((Format & IMAGEIO_AFLIP) && !(Format & IMAGEIO_STRIP_ALPHA))
01540     {
01541         Order[3] = Order[2];
01542         Order[2] = Order[1];
01543         Order[1] = Order[0];
01544         Order[0] = 3;
01545     }   
01546     
01547     switch(Format & (IMAGEIO_U8 | IMAGEIO_SINGLE | IMAGEIO_DOUBLE))
01548     {
01549     case IMAGEIO_U8:  /* Destination type is uint8_t */
01550         if(!(DestU8  = (uint8_t *)Malloc(sizeof(uint8_t)*NumChannels*NumPixels)))
01551             return NULL;
01552         
01553         switch(NumChannels)
01554         {
01555         case 1: /* Convert RGBA U8 to grayscale U8 */
01556             for(y = 0; y < Height; y++, Src += Width)
01557                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01558                 {
01559                     Pixel = Src[x];
01560                     DestU8[i] = (uint8_t)(0.299f*((uint8_t *)&Pixel)[0] 
01561                         + 0.587f*((uint8_t *)&Pixel)[1] 
01562                         + 0.114f*((uint8_t *)&Pixel)[2] + 0.5f);
01563                 }
01564             break;        
01565         case 3: /* Convert RGBA U8 to RGB (or BGR) U8 */
01566             for(y = 0; y < Height; y++, Src += Width)
01567                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01568                 {
01569                     Pixel = Src[x];
01570                     DestU8[i] = ((uint8_t *)&Pixel)[Order[0]];
01571                     DestU8[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]];
01572                     DestU8[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]];
01573                 }
01574             break;
01575         case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) U8 */
01576             for(y = 0; y < Height; y++, Src += Width)
01577                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01578                 {
01579                     Pixel = Src[x];
01580                     DestU8[i] = ((uint8_t *)&Pixel)[Order[0]];
01581                     DestU8[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]];
01582                     DestU8[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]];
01583                     DestU8[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]];  
01584                 }            
01585             break;
01586         }
01587         return DestU8;
01588     case IMAGEIO_SINGLE:  /* Destination type is float */
01589         if(!(DestF = (float *)Malloc(sizeof(float)*NumChannels*NumPixels)))
01590             return NULL;
01591         
01592         switch(NumChannels)
01593         {
01594         case 1: /* Convert RGBA U8 to grayscale float */
01595             for(y = 0; y < Height; y++, Src += Width)
01596                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01597                 {
01598                     Pixel = Src[x];
01599                     DestF[i] = 1.172549019607843070675535e-3f*((uint8_t *)&Pixel)[0]
01600                         + 2.301960784313725357840079e-3f*((uint8_t *)&Pixel)[1] 
01601                         + 4.470588235294117808150007e-4f*((uint8_t *)&Pixel)[2];
01602                 }
01603             break;        
01604         case 3: /* Convert RGBA U8 to RGB (or BGR) float */
01605             for(y = 0; y < Height; y++, Src += Width)
01606                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01607                 {
01608                     Pixel = Src[x];
01609                     DestF[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0f;
01610                     DestF[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0f;
01611                     DestF[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0f;
01612                 }
01613             break;
01614         case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) float */
01615             for(y = 0; y < Height; y++, Src += Width)
01616                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01617                 {
01618                     Pixel = Src[x];
01619                     DestF[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0f;
01620                     DestF[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0f;
01621                     DestF[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0f;
01622                     DestF[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]]/255.0f;
01623                 }            
01624             break;
01625         }
01626         return DestF;
01627     case IMAGEIO_DOUBLE:  /* Destination type is double */
01628         if(!(DestD = (double *)Malloc(sizeof(double)*NumChannels*NumPixels)))
01629             return NULL;
01630         
01631         switch(NumChannels)
01632         {
01633         case 1: /* Convert RGBA U8 to grayscale double */
01634             for(y = 0; y < Height; y++, Src += Width)
01635                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01636                 {
01637                     Pixel = Src[x];
01638                     DestD[i] = 1.172549019607843070675535e-3*((uint8_t *)&Pixel)[0]
01639                         + 2.301960784313725357840079e-3*((uint8_t *)&Pixel)[1] 
01640                         + 4.470588235294117808150007e-4*((uint8_t *)&Pixel)[2];
01641                 }
01642             break;        
01643         case 3: /* Convert RGBA U8 to RGB (or BGR) double */
01644             for(y = 0; y < Height; y++, Src += Width)
01645                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01646                 {
01647                     Pixel = Src[x];
01648                     DestD[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0;
01649                     DestD[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0;
01650                     DestD[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0;
01651                 }
01652             break;
01653         case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) double */
01654             for(y = 0; y < Height; y++, Src += Width)
01655                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01656                 {
01657                     Pixel = Src[x];
01658                     DestD[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0;
01659                     DestD[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0;
01660                     DestD[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0;
01661                     DestD[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]]/255.0;
01662                 }            
01663             break;
01664         }
01665         return DestD;
01666     default:
01667         return NULL;
01668     }    
01669 }
01670 
01671 
01673 static uint32_t *ConvertFromFormat(void *Src, int Width, int Height, 
01674     unsigned Format)
01675 {
01676     const int NumPixels = Width*Height;
01677     const int NumChannels = (Format & IMAGEIO_GRAYSCALE) ? 
01678         1 : ((Format & IMAGEIO_STRIP_ALPHA) ? 3 : 4);    
01679     const int ChannelStride = (Format & IMAGEIO_PLANAR) ? NumPixels : 1;
01680     const int ChannelStride2 = 2*ChannelStride;
01681     const int ChannelStride3 = 3*ChannelStride;
01682     double *SrcD = (double *)Src;
01683     float *SrcF = (float *)Src;
01684     uint8_t *SrcU8 = (uint8_t *)Src;
01685     uint8_t *Dest, *DestPtr;
01686     int Order[4] = {0, 1, 2, 3};
01687     int i, x, y, PixelStride, RowStride;
01688     
01689     
01690     if(!(Dest = (uint8_t *)Malloc(sizeof(uint32_t)*NumPixels)))
01691         return NULL;
01692     
01693     DestPtr = Dest;
01694     PixelStride = (Format & IMAGEIO_PLANAR) ? 1 : NumChannels;
01695     
01696     if(Format & IMAGEIO_COLUMNMAJOR)
01697     {
01698         RowStride = PixelStride;
01699         PixelStride *= Height;
01700     }
01701     else
01702         RowStride = Width*PixelStride;
01703     
01704     if(Format & IMAGEIO_BGRFLIP)
01705     {
01706         Order[0] = 2;
01707         Order[2] = 0;
01708     }
01709     
01710     if((Format & IMAGEIO_AFLIP) && !(Format & IMAGEIO_STRIP_ALPHA))
01711     {
01712         Order[3] = Order[2];
01713         Order[2] = Order[1];
01714         Order[1] = Order[0];
01715         Order[0] = 3;
01716     }   
01717     
01718     switch(Format & (IMAGEIO_U8 | IMAGEIO_SINGLE | IMAGEIO_DOUBLE))
01719     {
01720     case IMAGEIO_U8:  /* Source type is uint8_t */
01721         switch(NumChannels)
01722         {
01723         case 1: /* Convert grayscale U8 to RGBA U8 */
01724             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01725                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01726                 {
01727                     DestPtr[4*x] = 
01728                     DestPtr[4*x + 1] =
01729                     DestPtr[4*x + 2] = SrcU8[i];                    
01730                     DestPtr[4*x + 3] = 255;
01731                 }
01732             break;        
01733         case 3: /* Convert RGB (or BGR) U8 to RGBA U8 */
01734             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01735                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01736                 {
01737                     DestPtr[4*x + Order[0]] = SrcU8[i];
01738                     DestPtr[4*x + Order[1]] = SrcU8[i + ChannelStride];
01739                     DestPtr[4*x + Order[2]] = SrcU8[i + ChannelStride2];
01740                     DestPtr[4*x + 3] = 255;
01741                 }
01742             break;
01743         case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) U8 */
01744             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01745                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01746                 {
01747                     DestPtr[4*x + Order[0]] = SrcU8[i];
01748                     DestPtr[4*x + Order[1]] = SrcU8[i + ChannelStride];
01749                     DestPtr[4*x + Order[2]] = SrcU8[i + ChannelStride2];
01750                     DestPtr[4*x + Order[3]] = SrcU8[i + ChannelStride3];                    
01751                 }            
01752             break;
01753         }
01754         break;
01755     case IMAGEIO_SINGLE:  /* Source type is float */
01756         switch(NumChannels)
01757         {
01758         case 1: /* Convert grayscale float to RGBA U8 */
01759             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01760                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01761                 {
01762                     DestPtr[4*x] = 
01763                     DestPtr[4*x + 1] =
01764                     DestPtr[4*x + 2] = ROUNDCLAMPF(SrcF[i]);
01765                     DestPtr[4*x + 3] = 255;
01766                 }
01767             break;        
01768         case 3: /* Convert RGBA U8 to RGB (or BGR) float */
01769             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01770                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01771                 {
01772                     DestPtr[4*x + Order[0]] = ROUNDCLAMPF(SrcF[i]);
01773                     DestPtr[4*x + Order[1]] = ROUNDCLAMPF(SrcF[i + ChannelStride]);
01774                     DestPtr[4*x + Order[2]] = ROUNDCLAMPF(SrcF[i + ChannelStride2]);
01775                     DestPtr[4*x + 3] = 255;
01776                 }
01777             break;
01778         case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) float */
01779             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01780                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01781                 {
01782                     DestPtr[4*x + Order[0]] = ROUNDCLAMPF(SrcF[i]);
01783                     DestPtr[4*x + Order[1]] = ROUNDCLAMPF(SrcF[i + ChannelStride]);
01784                     DestPtr[4*x + Order[2]] = ROUNDCLAMPF(SrcF[i + ChannelStride2]);
01785                     DestPtr[4*x + Order[3]] = ROUNDCLAMPF(SrcF[i + ChannelStride3]);
01786                 }            
01787             break;
01788         }
01789         break;
01790     case IMAGEIO_DOUBLE:  /* Source type is double */
01791         switch(NumChannels)
01792         {
01793         case 1: /* Convert grayscale double to RGBA U8 */
01794             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01795                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01796                 {
01797                     DestPtr[4*x] = 
01798                     DestPtr[4*x + 1] =
01799                     DestPtr[4*x + 2] = ROUNDCLAMP(SrcD[i]);
01800                     DestPtr[4*x + 3] = 255;
01801                 }
01802             break;        
01803         case 3: /* Convert RGB (or BGR) double to RGBA U8 */
01804             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01805                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01806                 {
01807                     DestPtr[4*x + Order[0]] = ROUNDCLAMP(SrcD[i]);
01808                     DestPtr[4*x + Order[1]] = ROUNDCLAMP(SrcD[i + ChannelStride]);
01809                     DestPtr[4*x + Order[2]] = ROUNDCLAMP(SrcD[i + ChannelStride2]);
01810                     DestPtr[4*x + 3] = 255;;
01811                 }
01812             break;
01813         case 4: /* Convert RGBA (or BGRA, ARGB, or ABGR) double to RGBA U8 */
01814             for(y = 0; y < Height; y++, DestPtr += 4*Width)
01815                 for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
01816                 {
01817                     DestPtr[4*x + Order[0]] = ROUNDCLAMP(SrcD[i]);
01818                     DestPtr[4*x + Order[1]] = ROUNDCLAMP(SrcD[i + ChannelStride]);
01819                     DestPtr[4*x + Order[2]] = ROUNDCLAMP(SrcD[i + ChannelStride2]);
01820                     DestPtr[4*x + Order[3]] = ROUNDCLAMP(SrcD[i + ChannelStride3]);
01821                 }            
01822             break;
01823         }
01824         break;
01825     default:
01826         return NULL;
01827     }    
01828     
01829     return (uint32_t *)Dest;
01830 }
01831 
01832 
01842 int IdentifyImageType(char *Type, const char *FileName)
01843 {
01844     FILE *File;
01845     uint32_t Magic;
01846     
01847     
01848     Type[0] = '\0';
01849     
01850     if(!(File = fopen(FileName, "rb")))
01851         return 0;
01852     
01853     /* Determine the file format by reading the first 4 bytes */
01854     Magic = ((uint32_t)getc(File));
01855     Magic |= ((uint32_t)getc(File)) << 8;
01856     Magic |= ((uint32_t)getc(File)) << 16;
01857     Magic |= ((uint32_t)getc(File)) << 24;
01858     
01859     /* Test for errors */
01860     if(ferror(File))
01861     {
01862         fclose(File);
01863         return 0;
01864     }
01865     
01866     fclose(File);
01867     
01868     if((Magic & 0x0000FFFFL) == 0x00004D42L)                /* BMP */
01869         strcpy(Type, "BMP");
01870     else if((Magic & 0x00FFFFFFL) == 0x00FFD8FFL)           /* JPEG/JFIF */
01871         strcpy(Type, "JPEG");
01872     else if(Magic == 0x474E5089L)                           /* PNG */
01873         strcpy(Type, "PNG");
01874     else if(Magic == 0x002A4949L || Magic == 0x2A004D4DL)   /* TIFF */
01875         strcpy(Type, "TIFF");
01876     else if(Magic == 0x38464947L)                           /* GIF */
01877         strcpy(Type, "GIF");
01878     else if(Magic == 0x474E4D8AL)                           /* MNG */
01879         strcpy(Type, "MNG");
01880     else if((Magic & 0xF0FF00FFL) == 0x0001000AL            /* PCX */
01881         && ((Magic >> 8) & 0xFF) < 6)   
01882         strcpy(Type, "PCX");
01883     else
01884         return 0;
01885     
01886     return 1;
01887 }
01888 
01889 
01971 void *ReadImage(int *Width, int *Height, 
01972     const char *FileName, unsigned Format)
01973 {
01974     void *Image = NULL;
01975     uint32_t *ImageU8 = NULL;    
01976     FILE *File;
01977     char Type[8];
01978     
01979     
01980     IdentifyImageType(Type, FileName);        
01981     
01982     if(!(File = fopen(FileName, "rb")))
01983     {
01984         ErrorMessage("Unable to open file \"%s\".\n", FileName);
01985         return 0;
01986     }
01987     
01988     if(!strcmp(Type, "BMP"))
01989     {
01990         if(!ReadBmp(&ImageU8, Width, Height, File))
01991             ErrorMessage("Failed to read \"%s\".\n", FileName);
01992     }
01993     else if(!strcmp(Type, "JPEG"))
01994     {
01995 #ifdef LIBJPEG_SUPPORT
01996         if(!(ReadJpeg(&ImageU8, Width, Height, File)))
01997             ErrorMessage("Failed to read \"%s\".\n", FileName);
01998 #else
01999         ErrorMessage("File \"%s\" is a JPEG image.\n"
02000                      "Compile with LIBJPEG_SUPPORT to enable JPEG reading.\n",
02001                      FileName);
02002 #endif
02003     }
02004     else if(!strcmp(Type, "PNG"))
02005     {
02006 #ifdef LIBPNG_SUPPORT
02007         if(!(ReadPng(&ImageU8, Width, Height, File)))
02008             ErrorMessage("Failed to read \"%s\".\n", FileName);
02009 #else
02010         ErrorMessage("File \"%s\" is a PNG image.\n"
02011                      "Compile with LIBPNG_SUPPORT to enable PNG reading.\n",
02012                      FileName);
02013 #endif
02014     }
02015     else if(!strcmp(Type, "TIFF"))
02016     {
02017 #ifdef LIBTIFF_SUPPORT
02018         fclose(File);
02019         
02020         if(!(ReadTiff(&ImageU8, Width, Height, FileName, 0)))
02021             ErrorMessage("Failed to read \"%s\".\n", FileName);
02022         
02023         File = NULL;
02024 #else
02025         ErrorMessage("File \"%s\" is a TIFF image.\n"
02026                      "Compile with LIBTIFF_SUPPORT to enable TIFF reading.\n",
02027                      FileName);
02028 #endif
02029     }
02030     else
02031     {
02032         /* File format is unsupported. */
02033         if(Type[0])
02034             ErrorMessage("File \"%s\" is a %s image.", FileName, Type);
02035         else
02036             ErrorMessage("File \"%s\" is an unrecognized format.", FileName);
02037         fprintf(stderr, "\nSorry, only " READIMAGE_FORMATS_SUPPORTED " reading is supported.\n");
02038     }
02039     
02040     if(File)
02041         fclose(File);
02042     
02043     if(ImageU8 && Format)
02044     {
02045         Image = ConvertToFormat(ImageU8, *Width, *Height, Format);
02046         Free(ImageU8);
02047     }
02048     else
02049         Image = ImageU8;
02050     
02051     return Image;
02052 }
02053 
02054 
02074 int WriteImage(void *Image, int Width, int Height, 
02075     const char *FileName, unsigned Format, int Quality)
02076 {
02077     FILE *File;
02078     uint32_t *ImageU8;
02079     enum {BMP_FORMAT, JPEG_FORMAT, PNG_FORMAT, TIFF_FORMAT} FileFormat;
02080     int Success = 0;
02081     
02082     if(!Image || Width <= 0 || Height <= 0)
02083     {
02084         ErrorMessage("Null image.\n");
02085         ErrorMessage("Failed to write \"%s\".\n", FileName);
02086         return 0;
02087     }
02088     
02089     if(StringEndsWith(FileName, ".bmp"))
02090         FileFormat = BMP_FORMAT;
02091     else if(StringEndsWith(FileName, ".jpg")
02092         || StringEndsWith(FileName, ".jpeg"))
02093     {
02094         FileFormat = JPEG_FORMAT;
02095 #ifndef LIBJPEG_SUPPORT
02096         ErrorMessage("Failed to write \"%s\".\n", FileName);
02097         ErrorMessage("Compile with LIBJPEG_SUPPORT to enable JPEG writing.\n");
02098         return 0;
02099 #endif
02100     }
02101     else if(StringEndsWith(FileName, ".png"))
02102     {
02103         FileFormat = PNG_FORMAT;
02104 #ifndef LIBPNG_SUPPORT
02105         ErrorMessage("Failed to write \"%s\".\n", FileName);
02106         ErrorMessage("Compile with LIBPNG_SUPPORT to enable PNG writing.\n");
02107         return 0;
02108 #endif
02109     }
02110     else if(StringEndsWith(FileName, ".tif")
02111         || StringEndsWith(FileName, ".tiff"))
02112     {
02113         FileFormat = TIFF_FORMAT;
02114 #ifndef LIBTIFF_SUPPORT
02115         ErrorMessage("Failed to write \"%s\".\n", FileName);
02116         ErrorMessage("Compile with LIBTIFF_SUPPORT to enable TIFF writing.\n");
02117         return 0;
02118 #endif
02119     }
02120     else 
02121     {
02122         ErrorMessage("Failed to write \"%s\".\n", FileName);
02123         
02124         if(StringEndsWith(FileName, ".gif"))
02125             ErrorMessage("GIF is not supported.  ");
02126         else if(StringEndsWith(FileName, ".mng"))
02127             ErrorMessage("MNG is not supported.  ");
02128         else if(StringEndsWith(FileName, ".pcx"))
02129             ErrorMessage("PCX is not supported.  ");
02130         else
02131             ErrorMessage("Unable to determine format from extension.\n");
02132         
02133         ErrorMessage("Sorry, only " WRITEIMAGE_FORMATS_SUPPORTED " writing is supported.\n");
02134         return 0;
02135     }
02136     
02137     if(!(File = fopen(FileName, "wb")))
02138     {
02139         ErrorMessage("Unable to write to file \"%s\".\n", FileName);
02140         return 0;
02141     }
02142     
02143     if(!(ImageU8 = ConvertFromFormat(Image, Width, Height, Format)))
02144         return 0;
02145     
02146     switch(FileFormat)
02147     {
02148     case BMP_FORMAT:
02149         Success = WriteBmp(ImageU8, Width, Height, File);
02150         break;
02151     case JPEG_FORMAT:
02152 #ifdef LIBJPEG_SUPPORT
02153         Success = WriteJpeg(ImageU8, Width, Height, File, Quality);
02154 #else
02155         /* Dummy operation to avoid unused variable warning if compiled without
02156         libjpeg.  Note that execution returns above if Format == JPEG_FORMAT
02157         and LIBJPEG_SUPPORT is undefined. */
02158         Success = Quality;
02159 #endif
02160         break;
02161     case PNG_FORMAT:
02162 #ifdef LIBPNG_SUPPORT
02163         Success = WritePng(ImageU8, Width, Height, File);
02164 #endif
02165         break;
02166     case TIFF_FORMAT:
02167 #ifdef LIBTIFF_SUPPORT
02168         fclose(File);
02169         Success = WriteTiff(ImageU8, Width, Height, FileName);
02170         File = 0;
02171 #endif
02172         break;
02173     }
02174     
02175     if(!Success)
02176         ErrorMessage("Failed to write \"%s\".\n", FileName);
02177     
02178     Free(ImageU8);
02179     
02180     if(File)
02181         fclose(File);
02182     
02183     return Success;
02184 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines