Linear Methods for Image Interpolation
|
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 }