Linear Methods for Image Interpolation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
imageio.c
Go to the documentation of this file.
1 
37 #include <string.h>
38 #include <ctype.h>
39 #include "imageio.h"
40 
41 #ifdef USE_LIBPNG
42 #include <zlib.h>
43 #include <png.h>
44 #if PNG_LIBPNG_VER < 10400
45 /* For compatibility with older libpng */
46 #define png_set_expand_gray_1_2_4_to_8 png_set_gray_1_2_4_to_8
47 #endif
48 #endif
49 #ifdef USE_LIBTIFF
50 #include <tiffio.h>
51 #endif
52 #ifdef USE_LIBJPEG
53 #include <jpeglib.h>
54 #include <setjmp.h>
55 #endif
56 
58 #define FILE_BUFFER_CAPACITY (1024*4)
59 
60 #define ROUNDCLAMPF(x) ((x < 0.0f) ? 0 : \
61  ((x > 1.0f) ? 255 : (uint8_t)(255.0f*(x) + 0.5f)))
62 #define ROUNDCLAMP(x) ((x < 0.0) ? 0 : \
63  ((x > 1.0) ? 255 : (uint8_t)(255.0*(x) + 0.5)))
64 
65 
67 static int StringEndsWith(const char *String, const char *Suffix)
68 {
69  unsigned i, StringLength = strlen(String), SuffixLength = strlen(Suffix);
70 
71  if(StringLength < SuffixLength)
72  return 0;
73 
74  String += StringLength - SuffixLength;
75 
76  for(i = 0; i < SuffixLength; i++)
77  if(tolower(String[i]) != tolower(Suffix[i]))
78  return 0;
79 
80  return 1;
81 }
82 
83 
85 static void FillImage(uint32_t *Image, int Width, int Height, uint32_t Color)
86 {
87  int x, y;
88 
89  if(Image)
90  for(y = 0; y < Height; y++, Image += Width)
91  for(x = 0; x < Width; x++)
92  Image[x] = Color;
93 }
94 
95 
110 static uint32_t *GetImagePalette(int *NumColors, int *UseColor, int *UseAlpha,
111  const uint32_t *Image, int Width, int Height)
112 {
113  const int MaxColors = 256;
114  uint32_t *Palette = NULL;
115  uint32_t Pixel;
116  int x, y, i, Red, Green, Blue, Alpha;
117 
118 
119  if(!UseColor || !NumColors || !UseAlpha)
120  return NULL;
121  else if(!Image
122  || !(Palette = (uint32_t *)Malloc(sizeof(uint32_t)*MaxColors)))
123  {
124  *NumColors = -1;
125  *UseColor = *UseAlpha = 1;
126  return NULL;
127  }
128 
129  *NumColors = *UseColor = *UseAlpha = 0;
130 
131  for(y = 0; y < Height; y++)
132  {
133  for(x = 0; x < Width; x++)
134  {
135  Pixel = *(Image++);
136  Red = ((uint8_t *)&Pixel)[0];
137  Green = ((uint8_t *)&Pixel)[1];
138  Blue = ((uint8_t *)&Pixel)[2];
139  Alpha = ((uint8_t *)&Pixel)[3];
140 
141  if(Red != Green || Red != Blue) /* Check color */
142  *UseColor = 1;
143 
144  if(Alpha != 255) /* Check alpha */
145  *UseAlpha = 1;
146 
147  /* Check Palette colors (if *NumColors != -1) */
148  for(i = 0; i < *NumColors; i++)
149  if(Pixel == Palette[i])
150  break;
151 
152  if(i == *NumColors)
153  {
154  if(i < MaxColors)
155  { /* Add new color to Palette */
156  Palette[i] = Pixel;
157  (*NumColors)++;
158  }
159  else
160  { /* Maximum size for Palette exceeded */
161  Free(Palette);
162  Palette = NULL;
163  *NumColors = -1; /* Don't check Palette colors */
164  }
165  }
166  }
167  }
168 
169  return Palette;
170 }
171 
172 
174 static uint16_t ReadWordLE(FILE *File)
175 {
176  uint16_t w;
177  w = (uint16_t) getc(File);
178  w |= ((uint16_t) getc(File) << 8);
179  return w;
180 }
181 
182 
184 static uint32_t ReadDWordLE(FILE *File)
185 {
186  uint32_t dw;
187  dw = (uint32_t) getc(File);
188  dw |= ((uint32_t) getc(File) << 8);
189  dw |= ((uint32_t) getc(File) << 16);
190  dw |= ((uint32_t) getc(File) << 24);
191  return dw;
192 }
193 
194 
196 static void WriteWordLE(uint16_t w, FILE *File)
197 {
198  putc(w & 0xFF, File);
199  putc((w & 0xFF00) >> 8, File);
200 }
201 
202 
204 static void WriteDWordLE(uint32_t dw, FILE *File)
205 {
206  putc(dw & 0xFF, File);
207  putc((dw & 0xFF00) >> 8, File);
208  putc((dw & 0xFF0000) >> 16, File);
209  putc((dw & 0xFF000000) >> 24, File);
210 }
211 
212 
214 static int ReadBmp1Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
215 {
216  int RowPadding = (-(Width+7)/8)&3;
217  int x, y, Bit;
218  unsigned Code;
219 
220  Image += ((long int)Width)*((long int)Height - 1);
221 
222  for(y = Height; y; y--, Image -= Width)
223  {
224  if(feof(File))
225  return 0;
226 
227  for(x = 0; x < Width;)
228  {
229  Code = getc(File);
230 
231  for(Bit = 7; Bit >= 0 && x < Width; Bit--, Code <<= 1)
232  Image[x++] = Palette[(Code & 0x80) ? 1:0];
233  }
234 
235  for(x = RowPadding; x; x--)
236  getc(File); /* Skip padding bytes at the end of the row */
237  }
238 
239  return 1;
240 }
241 
242 
244 static int ReadBmp4Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
245 {
246  int RowPadding = (-(Width+1)/2)&3;
247  int x, y;
248  unsigned Code;
249 
250  Image += ((long int)Width)*((long int)Height - 1);
251 
252  for(y = Height; y; y--, Image -= Width)
253  {
254  if(feof(File))
255  return 0;
256 
257  for(x = 0; x < Width;)
258  {
259  Code = getc(File);
260  Image[x++] = Palette[(Code & 0xF0) >> 4];
261 
262  if(x < Width)
263  Image[x++] = Palette[Code & 0x0F];
264  }
265 
266  for(x = RowPadding; x; x--)
267  getc(File); /* Skip padding bytes at the end of the row */
268  }
269 
270  return 1;
271 }
272 
273 
275 static int ReadBmp4BitRle(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
276 {
277  int x, y, dy, k;
278  unsigned Count, Value;
279  uint32_t ColorH, ColorL;
280 
281  FillImage(Image, Width, Height, Palette[0]);
282  Image += ((long int)Width)*((long int)Height - 1);
283 
284  for(x = 0, y = Height; y;)
285  {
286  if(feof(File))
287  return 0;
288 
289  Count = getc(File);
290  Value = getc(File);
291 
292  if(!Count)
293  { /* Count = 0 is the escape code */
294  switch(Value)
295  {
296  case 0: /* End of line */
297  Image -= Width;
298  x = 0;
299  y--;
300  break;
301  case 1: /* End of bitmap */
302  return 1;
303  case 2: /* Delta */
304  x += getc(File);
305  dy = getc(File);
306  y -= dy;
307  Image -= dy*Width;
308 
309  if(x >= Width || y < 0)
310  return 0;
311  break;
312  default: /* Read a run of uncompressed data (Value = length of run) */
313  Count = k = Value;
314 
315  if(x >= Width)
316  return 0;
317 
318  do
319  {
320  Value = getc(File);
321  Image[x++] = Palette[(Value & 0xF0) >> 4];
322 
323  if(x >= Width)
324  break;
325 
326  if(--k)
327  {
328  Image[x++] = Palette[Value & 0x0F];
329  k--;
330 
331  if(x >= Width)
332  break;
333  }
334  }while(k);
335 
336  if(((Count + 1)/2) & 1)
337  getc(File); /* Padding for word align */
338  }
339  }
340  else
341  { /* Run of pixels (Count = length of run) */
342  ColorH = Palette[(Value & 0xF0) >> 4];
343  ColorL = Palette[Value & 0xF];
344 
345  if(x >= Width)
346  return 0;
347 
348  do
349  {
350  Image[x++] = ColorH;
351  Count--;
352 
353  if(x >= Width)
354  break;
355 
356  if(Count)
357  {
358  Image[x++] = ColorL;
359  Count--;
360 
361  if(x >= Width)
362  break;
363  }
364  }while(Count);
365  }
366  }
367 
368  return 1;
369 }
370 
371 
373 static int ReadBmp8Bit(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
374 {
375  int RowPadding = (-Width)&3;
376  int x, y;
377 
378  Image += ((long int)Width)*((long int)Height - 1);
379 
380  for(y = Height; y; y--, Image -= Width)
381  {
382  if(feof(File))
383  return 0;
384 
385  for(x = 0; x < Width; x++)
386  Image[x] = Palette[getc(File) & 0xFF];
387 
388  for(x = RowPadding; x; x--)
389  getc(File); /* Skip padding bytes at the end of the row */
390  }
391 
392  return 1;
393 }
394 
395 
397 static int ReadBmp8BitRle(uint32_t *Image, int Width, int Height, FILE *File, const uint32_t *Palette)
398 {
399  int x, y, dy, k;
400  unsigned Count, Value;
401  uint32_t Color;
402 
403  FillImage(Image, Width, Height, Palette[0]);
404  Image += ((long int)Width)*((long int)Height - 1);
405 
406  for(x = 0, y = Height; y;)
407  {
408  if(feof(File))
409  return 0;
410 
411  Count = getc(File);
412  Value = getc(File);
413 
414  if(!Count)
415  { /* Count = 0 is the escape code */
416  switch(Value)
417  {
418  case 0: /* End of line */
419  Image -= Width;
420  x = 0;
421  y--;
422  break;
423  case 1: /* End of bitmap */
424  return 1;
425  case 2: /* Delta */
426  x += getc(File);
427  dy = getc(File);
428  y -= dy;
429  Image -= dy*Width;
430 
431  if(x >= Width || y < 0)
432  return 0;
433  break;
434  default: /* Read a run of uncompressed data (Value = length of run) */
435  Count = k = Value;
436 
437  do
438  {
439  if(x >= Width)
440  break;
441 
442  Image[x++] = Palette[getc(File) & 0xFF];
443  }while(--k);
444 
445  if(Count&1)
446  getc(File); /* Padding for word align */
447  }
448  }
449  else
450  { /* Run of pixels equal to Value (Count = length of run) */
451  Color = Palette[Value & 0xFF];
452 
453  do
454  {
455  if(x >= Width)
456  break;
457 
458  Image[x++] = Color;
459  }while(--Count);
460  }
461  }
462 
463  return 1;
464 }
465 
466 
468 static int ReadBmp24Bit(uint32_t *Image, int Width, int Height, FILE *File)
469 {
470  uint8_t *ImagePtr = (uint8_t *)Image;
471  int RowPadding = (-3*Width)&3;
472  int x, y;
473 
474 
475  Width <<= 2;
476  ImagePtr += ((long int)Width)*((long int)Height - 1);
477 
478  for(y = Height; y; y--, ImagePtr -= Width)
479  {
480  if(feof(File))
481  return 0;
482 
483  for(x = 0; x < Width; x += 4)
484  {
485  ImagePtr[x+3] = 255; /* Set alpha */
486  ImagePtr[x+2] = getc(File); /* Read blue component */
487  ImagePtr[x+1] = getc(File); /* Read green component */
488  ImagePtr[x+0] = getc(File); /* Read red component */
489  }
490 
491  for(x = RowPadding; x; x--)
492  getc(File); /* Skip padding bytes at the end of the row */
493  }
494 
495  return 1;
496 }
497 
499 static void GetMaskShifts(uint32_t Mask, int *LeftShift, int *RightShift)
500 {
501  int Shift = 0, BitCount = 0;
502 
503  if(!Mask)
504  {
505  *LeftShift = 0;
506  *RightShift = 0;
507  return;
508  }
509 
510  while(!(Mask & 1)) /* Find the first true bit */
511  {
512  Mask >>= 1;
513  ++Shift;
514  }
515 
516  /* Adjust the result for scaling to 8-bit quantities */
517  while(Mask & 1) /* Count the number of true bits */
518  {
519  Mask >>= 1;
520  ++BitCount;
521  }
522 
523  /* Compute a signed shift (right is positive) */
524  Shift += BitCount - 8;
525 
526  if(Shift >= 0)
527  {
528  *LeftShift = 0;
529  *RightShift = Shift;
530  }
531  else
532  {
533  *LeftShift = -Shift;
534  *RightShift = 0;
535  }
536 }
537 
539 static int ReadBmp16Bit(uint32_t *Image, int Width, int Height, FILE *File,
540  uint32_t RedMask, uint32_t GreenMask, uint32_t BlueMask, uint32_t AlphaMask)
541 {
542  uint8_t *ImagePtr = (uint8_t *)Image;
543  uint32_t Code;
544  int RowPadding = (-2*Width)&3;
545  int RedLeftShift, GreenLeftShift, BlueLeftShift, AlphaLeftShift;
546  int RedRightShift, GreenRightShift, BlueRightShift, AlphaRightShift;
547  int x, y;
548 
549  GetMaskShifts(RedMask, &RedLeftShift, &RedRightShift);
550  GetMaskShifts(GreenMask, &GreenLeftShift, &GreenRightShift);
551  GetMaskShifts(BlueMask, &BlueLeftShift, &BlueRightShift);
552  GetMaskShifts(AlphaMask, &AlphaLeftShift, &AlphaRightShift);
553  Width <<= 2;
554  ImagePtr += ((long int)Width)*((long int)Height - 1);
555 
556  for(y = Height; y; y--, ImagePtr -= Width)
557  {
558  if(feof(File))
559  return 0;
560 
561  for(x = 0; x < Width; x += 4)
562  {
563  Code = ReadWordLE(File);
564  /* By the Windows 4.x BMP specification, color component masks must be contiguous
565  [http://www.fileformat.info/format/bmp/egff.htm]. So we can decode the bitfields
566  by bitwise AND with the mask and applying a bitshift.*/
567  ImagePtr[x+3] = ((Code & AlphaMask) >> AlphaRightShift) << AlphaLeftShift;
568  ImagePtr[x+2] = ((Code & BlueMask ) >> BlueRightShift ) << BlueLeftShift;
569  ImagePtr[x+1] = ((Code & GreenMask) >> GreenRightShift) << GreenLeftShift;
570  ImagePtr[x+0] = ((Code & RedMask ) >> RedRightShift ) << RedLeftShift;
571  }
572 
573  for(x = RowPadding; x; x--)
574  getc(File); /* Skip padding bytes at the end of the row */
575  }
576 
577  return 1;
578 }
579 
580 
582 static int ReadBmp32Bit(uint32_t *Image, int Width, int Height, FILE *File,
583  uint32_t RedMask, uint32_t GreenMask, uint32_t BlueMask, uint32_t AlphaMask)
584 {
585  uint8_t *ImagePtr;
586  uint32_t Code;
587  int RedLeftShift, GreenLeftShift, BlueLeftShift, AlphaLeftShift;
588  int RedRightShift, GreenRightShift, BlueRightShift, AlphaRightShift;
589  int x, y;
590 
591  GetMaskShifts(RedMask, &RedLeftShift, &RedRightShift);
592  GetMaskShifts(GreenMask, &GreenLeftShift, &GreenRightShift);
593  GetMaskShifts(BlueMask, &BlueLeftShift, &BlueRightShift);
594  GetMaskShifts(AlphaMask, &AlphaLeftShift, &AlphaRightShift);
595  Width <<= 2;
596  ImagePtr = (uint8_t *)Image + ((long int)Width)*((long int)Height - 1);
597 
598  for(y = Height; y; y--, ImagePtr -= Width)
599  {
600  if(feof(File))
601  return 0;
602 
603  for(x = 0; x < Width; x += 4)
604  {
605  Code = ReadDWordLE(File);
606  /* By the Windows 4.x BMP specification, color component masks must be contiguous
607  [http://www.fileformat.info/format/bmp/egff.htm]. So we can decode the bitfields
608  by bitwise AND with the mask and applying a bitshift.*/
609  ImagePtr[x+3] = ((Code & AlphaMask) >> AlphaRightShift) << AlphaLeftShift;
610  ImagePtr[x+2] = ((Code & BlueMask ) >> BlueRightShift ) << BlueLeftShift;
611  ImagePtr[x+1] = ((Code & GreenMask) >> GreenRightShift) << GreenLeftShift;
612  ImagePtr[x+0] = ((Code & RedMask ) >> RedRightShift ) << RedLeftShift;
613  }
614  }
615 
616  return 1;
617 }
618 
632 static int ReadBmp(uint32_t **Image, int *Width, int *Height, FILE *File)
633 {
634  uint32_t *Palette = NULL;
635  uint8_t *PalettePtr;
636  long int ImageDataOffset, InfoSize;
637  unsigned i, NumPlanes, BitsPerPixel, Compression, NumColors;
638  uint32_t RedMask, GreenMask, BlueMask, AlphaMask;
639  int Success = 0, Os2Bmp;
640  uint8_t Magic[2];
641 
642  *Image = NULL;
643  *Width = *Height = 0;
644  fseek(File, 0, SEEK_SET);
645 
646  Magic[0] = getc(File);
647  Magic[1] = getc(File);
648 
649  if(!(Magic[0] == 0x42 && Magic[1] == 0x4D) /* Verify the magic numbers */
650  || fseek(File, 8, SEEK_CUR)) /* Skip the reserved fields */
651  {
652  ErrorMessage("Invalid BMP header.\n");
653  goto Catch;
654  }
655 
656  ImageDataOffset = ReadDWordLE(File);
657  InfoSize = ReadDWordLE(File);
658 
659  /* Read the info header */
660  if(InfoSize < 12)
661  {
662  ErrorMessage("Invalid BMP info header.\n");
663  goto Catch;
664  }
665 
666  if((Os2Bmp = (InfoSize == 12))) /* This is an OS/2 V1 infoheader */
667  {
668  *Width = (int)ReadWordLE(File);
669  *Height = (int)ReadWordLE(File);
670  NumPlanes = (unsigned)ReadWordLE(File);
671  BitsPerPixel = (unsigned)ReadWordLE(File);
672  Compression = 0;
673  NumColors = 0;
674  RedMask = 0x00FF0000;
675  GreenMask = 0x0000FF00;
676  BlueMask = 0x000000FF;
677  AlphaMask = 0xFF000000;
678  }
679  else
680  {
681  *Width = abs((int)ReadDWordLE(File));
682  *Height = abs((int)ReadDWordLE(File));
683  NumPlanes = (unsigned)ReadWordLE(File);
684  BitsPerPixel = (unsigned)ReadWordLE(File);
685  Compression = (unsigned)ReadDWordLE(File);
686  fseek(File, 12, SEEK_CUR);
687  NumColors = (unsigned)ReadDWordLE(File);
688  fseek(File, 4, SEEK_CUR);
689  RedMask = ReadDWordLE(File);
690  GreenMask = ReadDWordLE(File);
691  BlueMask = ReadDWordLE(File);
692  AlphaMask = ReadDWordLE(File);
693  }
694 
695  /* Check for problems or unsupported compression modes */
696  if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
697  {
698  ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
699  goto Catch;
700  }
701 
702  if(feof(File) || NumPlanes != 1 || Compression > 3)
703  goto Catch;
704 
705  /* Allocate the image data */
706  if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)*((long int)*Width)*((long int)*Height))))
707  goto Catch;
708 
709  /* Read palette */
710  if(BitsPerPixel <= 8)
711  {
712  fseek(File, 14 + InfoSize, SEEK_SET);
713 
714  if(!NumColors)
715  NumColors = 1 << BitsPerPixel;
716 
717  if(!(Palette = (uint32_t *)Malloc(sizeof(uint32_t)*256)))
718  goto Catch;
719 
720  for(i = 0, PalettePtr = (uint8_t *)Palette; i < NumColors; i++)
721  {
722  PalettePtr[3] = 255; /* Set alpha */
723  PalettePtr[2] = getc(File); /* Read blue component */
724  PalettePtr[1] = getc(File); /* Read green component */
725  PalettePtr[0] = getc(File); /* Read red component */
726  PalettePtr += 4;
727 
728  if(!Os2Bmp)
729  getc(File); /* Skip extra byte (for non-OS/2 bitmaps) */
730  }
731 
732  for(; i < 256; i++) /* Fill the rest of the palette with the first color */
733  Palette[i] = Palette[0];
734  }
735 
736  if(fseek(File, ImageDataOffset, SEEK_SET) || feof(File))
737  {
738  ErrorMessage("File error.\n");
739  goto Catch;
740  }
741 
742  /*** Read the bitmap image data ***/
743  switch(Compression)
744  {
745  case 0: /* Uncompressed data */
746  switch(BitsPerPixel)
747  {
748  case 1: /* Read 1-bit uncompressed indexed data */
749  Success = ReadBmp1Bit(*Image, *Width, *Height, File, Palette);
750  break;
751  case 4: /* Read 4-bit uncompressed indexed data */
752  Success = ReadBmp4Bit(*Image, *Width, *Height, File, Palette);
753  break;
754  case 8: /* Read 8-bit uncompressed indexed data */
755  Success = ReadBmp8Bit(*Image, *Width, *Height, File, Palette);
756  break;
757  case 24: /* Read 24-bit BGR image data */
758  Success = ReadBmp24Bit(*Image, *Width, *Height, File);
759  break;
760  case 16: /* Read 16-bit data */
761  Success = ReadBmp16Bit(*Image, *Width, *Height, File,
762  0x001F << 10, 0x001F << 5, 0x0001F, 0);
763  break;
764  case 32: /* Read 32-bit BGRA image data */
765  Success = ReadBmp32Bit(*Image, *Width, *Height, File,
766  0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
767  break;
768  }
769  break;
770  case 1: /* 8-bit RLE */
771  if(BitsPerPixel == 8)
772  Success = ReadBmp8BitRle(*Image, *Width, *Height, File, Palette);
773  break;
774  case 2: /* 4-bit RLE */
775  if(BitsPerPixel == 4)
776  Success = ReadBmp4BitRle(*Image, *Width, *Height, File, Palette);
777  break;
778  case 3: /* Bitfields data */
779  switch(BitsPerPixel)
780  {
781  case 16: /* Read 16-bit bitfields data */
782  Success = ReadBmp16Bit(*Image, *Width, *Height, File,
783  RedMask, GreenMask, BlueMask, AlphaMask);
784  break;
785  case 32: /* Read 32-bit bitfields data */
786  Success = ReadBmp32Bit(*Image, *Width, *Height, File,
787  RedMask, GreenMask, BlueMask, AlphaMask);
788  break;
789  }
790  break;
791  }
792 
793  if(!Success)
794  ErrorMessage("Error reading BMP data.\n");
795 
796 Catch: /* There was a problem, clean up and exit */
797  if(Palette)
798  Free(Palette);
799 
800  if(!Success && *Image)
801  Free(*Image);
802 
803  return Success;
804 }
805 
806 
828 static int WriteBmp(const uint32_t *Image, int Width, int Height, FILE *File)
829 {
830  const uint8_t *ImagePtr = (uint8_t *)Image;
831  uint32_t *Palette = NULL;
832  uint32_t Pixel;
833  long int ImageSize;
834  int UsePalette, NumColors, UseColor, UseAlpha;
835  int x, y, i, RowPadding, Success = 0;
836 
837 
838  if(!Image)
839  return 0;
840 
841  Palette = GetImagePalette(&NumColors, &UseColor, &UseAlpha,
842  Image, Width, Height);
843 
844  /* Decide whether to use 8-bit palette or 24-bit RGB format */
845  if(Palette && 2*NumColors < Width*Height)
846  UsePalette = 1;
847  else
848  UsePalette = NumColors = 0;
849 
850  /* Tell File to use buffering */
851  setvbuf(File, 0, _IOFBF, FILE_BUFFER_CAPACITY);
852 
853  if(UsePalette)
854  {
855  RowPadding = (-Width)&3;
856  ImageSize = (Width + RowPadding)*((long int)Height);
857  }
858  else
859  {
860  RowPadding = (-3*Width)&3;
861  ImageSize = (3*Width + RowPadding)*((long int)Height);
862  }
863 
864  /*** Write the header ***/
865 
866  /* Write the BMP header */
867  putc(0x42, File); /* Magic numbers */
868  putc(0x4D, File);
869 
870  /* Filesize */
871  WriteDWordLE(54 + 4*NumColors + ImageSize, File);
872 
873  WriteDWordLE(0, File); /* Reserved fields */
874  WriteDWordLE(54 + 4*NumColors, File); /* Image data offset */
875 
876  /* Write the infoheader */
877  WriteDWordLE(40, File); /* Infoheader size */
878  WriteDWordLE(Width, File); /* Image width */
879  WriteDWordLE(Height, File); /* Image height */
880  WriteWordLE(1, File); /* Number of colorplanes */
881  WriteWordLE((UsePalette) ? 8:24, File); /* Bits per pixel */
882  WriteDWordLE(0, File); /* Compression method (none) */
883  WriteDWordLE(ImageSize, File); /* Image size */
884  WriteDWordLE(2835, File); /* HResolution (2835=72dpi) */
885  WriteDWordLE(2835, File); /* VResolution */
886 
887  /* Number of colors */
888  WriteDWordLE((!UsePalette || NumColors == 256) ? 0:NumColors, File);
889 
890  WriteDWordLE(0, File); /* Important colors */
891 
892  if(ferror(File))
893  {
894  ErrorMessage("Error during write to file.\n");
895  goto Catch;
896  }
897 
898  if(UsePalette)
899  { /* Write the Palette */
900  for(i = 0; i < NumColors; i++)
901  {
902  Pixel = Palette[i];
903  putc(((uint8_t *)&Pixel)[2], File); /* Blue */
904  putc(((uint8_t *)&Pixel)[1], File); /* Green */
905  putc(((uint8_t *)&Pixel)[0], File); /* Red */
906  putc(0, File); /* Unused */
907  }
908  }
909 
910  /* Write the image data */
911  Width <<= 2;
912  ImagePtr += ((long int)Width)*((long int)Height - 1);
913 
914  for(y = Height; y; y--, ImagePtr -= Width)
915  {
916  if(UsePalette)
917  { /* 8-bit palette image data */
918  for(x = 0; x < Width; x += 4)
919  {
920  Pixel = *((uint32_t *)(ImagePtr + x));
921 
922  for(i = 0; i < NumColors; i++)
923  if(Pixel == Palette[i])
924  break;
925 
926  putc(i, File);
927  }
928  }
929  else
930  { /* 24-bit RGB image data */
931  for(x = 0; x < Width; x += 4)
932  {
933  putc(ImagePtr[x+2], File); /* Write blue component */
934  putc(ImagePtr[x+1], File); /* Write green component */
935  putc(ImagePtr[x+0], File); /* Write red component */
936  }
937  }
938 
939  for(x = RowPadding; x; x--) /* Write row padding */
940  putc(0, File);
941  }
942 
943  if(ferror(File))
944  {
945  ErrorMessage("Error during write to file.\n");
946  goto Catch;
947  }
948 
949  Success = 1;
950 Catch:
951  if(Palette)
952  Free(Palette);
953  return Success;
954 }
955 
956 
957 #ifdef USE_LIBJPEG
958 
964 typedef struct{
965  struct jpeg_error_mgr pub;
966  jmp_buf jmpbuf;
967 } hooked_jerr;
968 
969 
971 METHODDEF(void) JerrExit(j_common_ptr cinfo)
972 {
973  hooked_jerr *Jerr = (hooked_jerr *) cinfo->err;
974  (*cinfo->err->output_message)(cinfo);
975  longjmp(Jerr->jmpbuf, 1);
976 }
977 
978 
992 static int ReadJpeg(uint32_t **Image, int *Width, int *Height, FILE *File)
993 {
994  struct jpeg_decompress_struct cinfo;
995  hooked_jerr Jerr;
996  JSAMPARRAY Buffer;
997  uint8_t *ImagePtr;
998  unsigned i, RowSize;
999 
1000  *Image = 0;
1001  *Width = *Height = 0;
1002  cinfo.err = jpeg_std_error(&Jerr.pub);
1003  Jerr.pub.error_exit = JerrExit;
1004 
1005  if(setjmp(Jerr.jmpbuf))
1006  goto Catch; /* If this code is reached, libjpeg has signaled an error. */
1007 
1008  jpeg_create_decompress(&cinfo);
1009  jpeg_stdio_src(&cinfo, File);
1010  jpeg_read_header(&cinfo, 1);
1011  cinfo.out_color_space = JCS_RGB; /* Ask for RGB image data */
1012  jpeg_start_decompress(&cinfo);
1013  *Width = (int)cinfo.output_width;
1014  *Height = (int)cinfo.output_height;
1015 
1016  if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
1017  {
1018  ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
1019  jpeg_abort_decompress(&cinfo);
1020  goto Catch;
1021  }
1022 
1023  /* Allocate image memory */
1024  if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)
1025  *((size_t)*Width)*((size_t)*Height))))
1026  {
1027  jpeg_abort_decompress(&cinfo);
1028  goto Catch;
1029  }
1030 
1031  /* Allocate a one-row-high array that will go away when done */
1032  RowSize = cinfo.output_width * cinfo.output_components;
1033  Buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo,
1034  JPOOL_IMAGE, RowSize, 1);
1035  ImagePtr = (uint8_t *)*Image;
1036 
1037  while(cinfo.output_scanline < cinfo.output_height)
1038  for(jpeg_read_scanlines(&cinfo, Buffer, 1), i = 0; i < RowSize; i += 3)
1039  {
1040  *(ImagePtr++) = Buffer[0][i]; /* Red */
1041  *(ImagePtr++) = Buffer[0][i+1]; /* Green */
1042  *(ImagePtr++) = Buffer[0][i+2]; /* Blue */
1043  *(ImagePtr++) = 0xFF;
1044  }
1045 
1046  jpeg_finish_decompress(&cinfo);
1047  jpeg_destroy_decompress(&cinfo);
1048  return 1;
1049 
1050 Catch:
1051  if(*Image)
1052  Free(*Image);
1053 
1054  *Width = *Height = 0;
1055  jpeg_destroy_decompress(&cinfo);
1056  return 0;
1057 }
1058 
1059 
1078 static int WriteJpeg(const uint32_t *Image, int Width, int Height,
1079  FILE *File, int Quality)
1080 {
1081  struct jpeg_compress_struct cinfo;
1082  hooked_jerr Jerr;
1083  uint8_t *Buffer = 0, *ImagePtr;
1084  unsigned i, RowSize;
1085 
1086 
1087  if(!Image)
1088  return 0;
1089 
1090  cinfo.err = jpeg_std_error(&Jerr.pub);
1091  Jerr.pub.error_exit = JerrExit;
1092 
1093  if(setjmp(Jerr.jmpbuf))
1094  goto Catch; /* If this code is reached, libjpeg has signaled an error. */
1095 
1096  jpeg_create_compress(&cinfo);
1097  jpeg_stdio_dest(&cinfo, File);
1098  cinfo.image_width = Width;
1099  cinfo.image_height = Height;
1100  cinfo.input_components = 3;
1101  cinfo.in_color_space = JCS_RGB;
1102  jpeg_set_defaults(&cinfo);
1103  jpeg_set_quality(&cinfo, (Quality < 100) ? Quality : 100, 1);
1104  jpeg_start_compress(&cinfo, 1);
1105 
1106  RowSize = 3*Width;
1107  ImagePtr = (uint8_t *)Image;
1108 
1109  if(!(Buffer = (uint8_t *)Malloc(RowSize)))
1110  goto Catch;
1111 
1112  while(cinfo.next_scanline < cinfo.image_height)
1113  {
1114  for(i = 0; i < RowSize; i += 3)
1115  {
1116  Buffer[i] = ImagePtr[0]; /* Red */
1117  Buffer[i+1] = ImagePtr[1]; /* Green */
1118  Buffer[i+2] = ImagePtr[2]; /* Blue */
1119  ImagePtr += 4;
1120  }
1121 
1122  jpeg_write_scanlines(&cinfo, &Buffer, 1);
1123  }
1124 
1125  if(Buffer)
1126  Free(Buffer);
1127 
1128  jpeg_finish_compress(&cinfo);
1129  jpeg_destroy_compress(&cinfo);
1130  return 1;
1131 Catch:
1132  if(Buffer)
1133  Free(Buffer);
1134 
1135  jpeg_destroy_compress(&cinfo);
1136  return 0;
1137 }
1138 #endif /* USE_LIBJPEG */
1139 
1140 
1141 #ifdef USE_LIBPNG
1142 
1155 static int ReadPng(uint32_t **Image, int *Width, int *Height, FILE *File)
1156 {
1157  png_bytep *RowPointers;
1158  png_byte Header[8];
1159  png_structp Png;
1160  png_infop Info;
1161  png_uint_32 PngWidth, PngHeight;
1162  int BitDepth, ColorType, InterlaceType;
1163  unsigned Row;
1164 
1165  *Image = 0;
1166  *Width = *Height = 0;
1167 
1168  /* Check that file is a PNG file */
1169  if(fread(Header, 1, 8, File) != 8 || png_sig_cmp(Header, 0, 8))
1170  return 0;
1171 
1172  /* Read the info header */
1173  if(!(Png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))
1174  || !(Info = png_create_info_struct(Png)))
1175  {
1176  if(Png)
1177  png_destroy_read_struct(&Png, (png_infopp)NULL, (png_infopp)NULL);
1178 
1179  return 0;
1180  }
1181 
1182  if(setjmp(png_jmpbuf(Png)))
1183  goto Catch; /* If this code is reached, libpng has signaled an error. */
1184 
1185  png_init_io(Png, File);
1186  png_set_sig_bytes(Png, 8);
1187  png_set_user_limits(Png, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
1188  png_read_info(Png, Info);
1189  png_get_IHDR(Png, Info, &PngWidth, &PngHeight, &BitDepth, &ColorType,
1190  &InterlaceType, (int*)NULL, (int*)NULL);
1191  *Width = (int)PngWidth;
1192  *Height = (int)PngHeight;
1193 
1194  /* Tell libpng to convert everything to 32-bit RGBA */
1195  if(ColorType == PNG_COLOR_TYPE_PALETTE)
1196  png_set_palette_to_rgb(Png);
1197  if(ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
1198  png_set_expand_gray_1_2_4_to_8(Png);
1199  if(ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
1200  png_set_gray_to_rgb(Png);
1201  if(png_get_valid(Png, Info, PNG_INFO_tRNS))
1202  png_set_tRNS_to_alpha(Png);
1203 
1204  png_set_strip_16(Png);
1205  png_set_filler(Png, 0xFF, PNG_FILLER_AFTER);
1206 
1207  png_set_interlace_handling(Png);
1208  png_read_update_info(Png, Info);
1209 
1210  /* Allocate image memory and row pointers */
1211  if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)
1212  *((size_t)*Width)*((size_t)*Height)))
1213  || !(RowPointers = (png_bytep *)Malloc(sizeof(png_bytep)
1214  *PngHeight)))
1215  goto Catch;
1216 
1217  for(Row = 0; Row < PngHeight; Row++)
1218  RowPointers[Row] = (png_bytep)(*Image + PngWidth*Row);
1219 
1220  /* Read the image data */
1221  png_read_image(Png, RowPointers);
1222  Free(RowPointers);
1223  png_destroy_read_struct(&Png, &Info, (png_infopp)NULL);
1224  return 1;
1225 
1226 Catch:
1227  if(*Image)
1228  Free(*Image);
1229 
1230  *Width = *Height = 0;
1231  png_destroy_read_struct(&Png, &Info, (png_infopp)NULL);
1232  return 0;
1233 }
1234 
1235 
1256 static int WritePng(const uint32_t *Image, int Width, int Height, FILE *File)
1257 {
1258  const uint32_t *ImagePtr;
1259  uint32_t *Palette = NULL;
1260  uint8_t *RowBuffer;
1261  png_structp Png;
1262  png_infop Info;
1263  png_color PngPalette[256];
1264  png_byte PngTrans[256];
1265  uint32_t Pixel;
1266  int PngColorType, NumColors, UseColor, UseAlpha;
1267  int x, y, i, Success = 0;
1268 
1269 
1270  if(!Image)
1271  return 0;
1272 
1273  if(!(RowBuffer = (uint8_t *)Malloc(4*Width)))
1274  return 0;
1275 
1276  if(!(Png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1277  NULL, NULL, NULL))
1278  || !(Info = png_create_info_struct(Png)))
1279  {
1280  if(Png)
1281  png_destroy_write_struct(&Png, (png_infopp)NULL);
1282 
1283  Free(RowBuffer);
1284  return 0;
1285  }
1286 
1287  if(setjmp(png_jmpbuf(Png)))
1288  { /* If this code is reached, libpng has signaled an error. */
1289  goto Catch;
1290  }
1291 
1292  /* Configure PNG output */
1293  png_init_io(Png, File);
1294  png_set_compression_level(Png, Z_BEST_COMPRESSION);
1295 
1296  Palette = GetImagePalette(&NumColors, &UseColor, &UseAlpha,
1297  Image, Width, Height);
1298 
1299  /* The PNG image is written according to the analysis of GetImagePalette */
1300  if(Palette && UseColor)
1301  PngColorType = PNG_COLOR_TYPE_PALETTE;
1302  else if(UseAlpha)
1303  PngColorType = PNG_COLOR_TYPE_RGB_ALPHA;
1304  else if(UseColor)
1305  PngColorType = PNG_COLOR_TYPE_RGB;
1306  else
1307  PngColorType = PNG_COLOR_TYPE_GRAY;
1308 
1309  png_set_IHDR(Png, Info, Width, Height, 8, PngColorType,
1310  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
1311 
1312  if(PngColorType == PNG_COLOR_TYPE_PALETTE)
1313  {
1314  for(i = 0; i < NumColors; i++)
1315  {
1316  Pixel = Palette[i];
1317  PngPalette[i].red = ((uint8_t *)&Pixel)[0];
1318  PngPalette[i].green = ((uint8_t *)&Pixel)[1];
1319  PngPalette[i].blue = ((uint8_t *)&Pixel)[2];
1320  PngTrans[i] = ((uint8_t *)&Pixel)[3];
1321  }
1322 
1323  png_set_PLTE(Png, Info, PngPalette, NumColors);
1324 
1325  if(UseAlpha)
1326  png_set_tRNS(Png, Info, PngTrans, NumColors, NULL);
1327  }
1328 
1329  png_write_info(Png, Info);
1330 
1331  for(y = 0, ImagePtr = Image; y < Height; y++, ImagePtr += Width)
1332  {
1333  switch(PngColorType)
1334  {
1335  case PNG_COLOR_TYPE_RGB_ALPHA:
1336  png_write_row(Png, (png_bytep)ImagePtr);
1337  break;
1338  case PNG_COLOR_TYPE_RGB:
1339  for(x = 0; x < Width; x++)
1340  {
1341  Pixel = ImagePtr[x];
1342  RowBuffer[3*x + 0] = ((uint8_t *)&Pixel)[0];
1343  RowBuffer[3*x + 1] = ((uint8_t *)&Pixel)[1];
1344  RowBuffer[3*x + 2] = ((uint8_t *)&Pixel)[2];
1345  }
1346 
1347  png_write_row(Png, (png_bytep)RowBuffer);
1348  break;
1349  case PNG_COLOR_TYPE_GRAY:
1350  for(x = 0; x < Width; x++)
1351  {
1352  Pixel = ImagePtr[x];
1353  RowBuffer[x] = ((uint8_t *)&Pixel)[0];
1354  }
1355 
1356  png_write_row(Png, (png_bytep)RowBuffer);
1357  break;
1358  case PNG_COLOR_TYPE_PALETTE:
1359  for(x = 0; x < Width; x++)
1360  {
1361  Pixel = ImagePtr[x];
1362 
1363  for(i = 0; i < NumColors; i++)
1364  if(Pixel == Palette[i])
1365  break;
1366 
1367  RowBuffer[x] = i;
1368  }
1369 
1370  png_write_row(Png, (png_bytep)RowBuffer);
1371  break;
1372  }
1373  }
1374 
1375  png_write_end(Png, Info);
1376  Success = 1;
1377 Catch:
1378  if(Palette)
1379  Free(Palette);
1380  png_destroy_write_struct(&Png, &Info);
1381  Free(RowBuffer);
1382  return Success;
1383 }
1384 #endif /* USE_LIBPNG */
1385 
1386 
1387 #ifdef USE_LIBTIFF
1388 
1401 static int ReadTiff(uint32_t **Image, int *Width, int *Height,
1402  const char *FileName, unsigned Directory)
1403 {
1404  TIFF *Tiff;
1405  uint32 ImageWidth, ImageHeight;
1406 
1407  *Image = 0;
1408  *Width = *Height = 0;
1409 
1410  if(!(Tiff = TIFFOpen(FileName, "r")))
1411  {
1412  ErrorMessage("TIFFOpen failed to open file.\n");
1413  return 0;
1414  }
1415 
1416  TIFFSetDirectory(Tiff, Directory);
1417  TIFFGetField(Tiff, TIFFTAG_IMAGEWIDTH, &ImageWidth);
1418  TIFFGetField(Tiff, TIFFTAG_IMAGELENGTH, &ImageHeight);
1419  *Width = (int)ImageWidth;
1420  *Height = (int)ImageHeight;
1421 
1422  if(*Width > MAX_IMAGE_SIZE || *Height > MAX_IMAGE_SIZE)
1423  {
1424  ErrorMessage("Image dimensions exceed MAX_IMAGE_SIZE.\n");
1425  goto Catch;
1426  }
1427 
1428  if(!(*Image = (uint32_t *)Malloc(sizeof(uint32_t)*ImageWidth*ImageHeight)))
1429  goto Catch;
1430 
1431  if(!TIFFReadRGBAImageOriented(Tiff, ImageWidth, ImageHeight,
1432  (uint32 *)*Image, ORIENTATION_TOPLEFT, 1))
1433  goto Catch;
1434 
1435  TIFFClose(Tiff);
1436  return 1;
1437 
1438 Catch:
1439  if(*Image)
1440  Free(*Image);
1441 
1442  *Width = *Height = 0;
1443  TIFFClose(Tiff);
1444  return 0;
1445 }
1446 
1447 
1461 static int WriteTiff(const uint32_t *Image, int Width, int Height,
1462  const char *FileName)
1463 {
1464  TIFF *Tiff;
1465  uint16 Alpha = EXTRASAMPLE_ASSOCALPHA;
1466 
1467  if(!Image)
1468  return 0;
1469 
1470  if(!(Tiff = TIFFOpen(FileName, "w")))
1471  {
1472  ErrorMessage("TIFFOpen failed to open file.\n");
1473  return 0;
1474  }
1475 
1476  if(TIFFSetField(Tiff, TIFFTAG_IMAGEWIDTH, Width) != 1
1477  || TIFFSetField(Tiff, TIFFTAG_IMAGELENGTH, Height) != 1
1478  || TIFFSetField(Tiff, TIFFTAG_SAMPLESPERPIXEL, 4) != 1
1479  || TIFFSetField(Tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) != 1
1480  || TIFFSetField(Tiff, TIFFTAG_EXTRASAMPLES, 1, &Alpha) != 1
1481  || TIFFSetField(Tiff, TIFFTAG_BITSPERSAMPLE, 8) != 1
1482  || TIFFSetField(Tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT) != 1
1483  || TIFFSetField(Tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) != 1
1484  /* Compression can be COMPRESSION_NONE, COMPRESSION_DEFLATE,
1485  COMPRESSION_LZW, or COMPRESSION_JPEG */
1486  || TIFFSetField(Tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW) != 1)
1487  {
1488  ErrorMessage("TIFFSetField failed.\n");
1489  TIFFClose(Tiff);
1490  return 0;
1491  }
1492 
1493  if(TIFFWriteEncodedStrip(Tiff, 0, (tdata_t)Image,
1494  4*((size_t)Width)*((size_t)Height)) < 0)
1495  {
1496  ErrorMessage("Error writing data to file.\n");
1497  TIFFClose(Tiff);
1498  return 0;
1499  }
1500 
1501  TIFFClose(Tiff);
1502  return 1;
1503 }
1504 #endif /* USE_LIBTIFF */
1505 
1506 
1508 static void *ConvertToFormat(uint32_t *Src, int Width, int Height,
1509  unsigned Format)
1510 {
1511  const int NumPixels = Width*Height;
1512  const int NumChannels = (Format & IMAGEIO_GRAYSCALE) ?
1513  1 : ((Format & IMAGEIO_STRIP_ALPHA) ? 3 : 4);
1514  const int ChannelStride = (Format & IMAGEIO_PLANAR) ? NumPixels : 1;
1515  const int ChannelStride2 = 2*ChannelStride;
1516  const int ChannelStride3 = 3*ChannelStride;
1517  double *DestD;
1518  float *DestF;
1519  uint8_t *DestU8;
1520  uint32_t Pixel;
1521  int Order[4] = {0, 1, 2, 3};
1522  int i, x, y, PixelStride, RowStride;
1523 
1524 
1525  PixelStride = (Format & IMAGEIO_PLANAR) ? 1 : NumChannels;
1526 
1527  if(Format & IMAGEIO_COLUMNMAJOR)
1528  {
1529  RowStride = PixelStride;
1530  PixelStride *= Height;
1531  }
1532  else
1533  RowStride = Width*PixelStride;
1534 
1535  if(Format & IMAGEIO_BGRFLIP)
1536  {
1537  Order[0] = 2;
1538  Order[2] = 0;
1539  }
1540 
1541  if((Format & IMAGEIO_AFLIP) && !(Format & IMAGEIO_STRIP_ALPHA))
1542  {
1543  Order[3] = Order[2];
1544  Order[2] = Order[1];
1545  Order[1] = Order[0];
1546  Order[0] = 3;
1547  }
1548 
1549  switch(Format & (IMAGEIO_U8 | IMAGEIO_SINGLE | IMAGEIO_DOUBLE))
1550  {
1551  case IMAGEIO_U8: /* Destination type is uint8_t */
1552  if(!(DestU8 = (uint8_t *)Malloc(sizeof(uint8_t)*NumChannels*NumPixels)))
1553  return NULL;
1554 
1555  switch(NumChannels)
1556  {
1557  case 1: /* Convert RGBA U8 to grayscale U8 */
1558  for(y = 0; y < Height; y++, Src += Width)
1559  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1560  {
1561  Pixel = Src[x];
1562  DestU8[i] = (uint8_t)(0.299f*((uint8_t *)&Pixel)[0]
1563  + 0.587f*((uint8_t *)&Pixel)[1]
1564  + 0.114f*((uint8_t *)&Pixel)[2] + 0.5f);
1565  }
1566  break;
1567  case 3: /* Convert RGBA U8 to RGB (or BGR) U8 */
1568  for(y = 0; y < Height; y++, Src += Width)
1569  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1570  {
1571  Pixel = Src[x];
1572  DestU8[i] = ((uint8_t *)&Pixel)[Order[0]];
1573  DestU8[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]];
1574  DestU8[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]];
1575  }
1576  break;
1577  case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) U8 */
1578  for(y = 0; y < Height; y++, Src += Width)
1579  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1580  {
1581  Pixel = Src[x];
1582  DestU8[i] = ((uint8_t *)&Pixel)[Order[0]];
1583  DestU8[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]];
1584  DestU8[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]];
1585  DestU8[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]];
1586  }
1587  break;
1588  }
1589  return DestU8;
1590  case IMAGEIO_SINGLE: /* Destination type is float */
1591  if(!(DestF = (float *)Malloc(sizeof(float)*NumChannels*NumPixels)))
1592  return NULL;
1593 
1594  switch(NumChannels)
1595  {
1596  case 1: /* Convert RGBA U8 to grayscale float */
1597  for(y = 0; y < Height; y++, Src += Width)
1598  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1599  {
1600  Pixel = Src[x];
1601  DestF[i] = 1.172549019607843070675535e-3f*((uint8_t *)&Pixel)[0]
1602  + 2.301960784313725357840079e-3f*((uint8_t *)&Pixel)[1]
1603  + 4.470588235294117808150007e-4f*((uint8_t *)&Pixel)[2];
1604  }
1605  break;
1606  case 3: /* Convert RGBA U8 to RGB (or BGR) float */
1607  for(y = 0; y < Height; y++, Src += Width)
1608  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1609  {
1610  Pixel = Src[x];
1611  DestF[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0f;
1612  DestF[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0f;
1613  DestF[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0f;
1614  }
1615  break;
1616  case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) float */
1617  for(y = 0; y < Height; y++, Src += Width)
1618  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1619  {
1620  Pixel = Src[x];
1621  DestF[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0f;
1622  DestF[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0f;
1623  DestF[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0f;
1624  DestF[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]]/255.0f;
1625  }
1626  break;
1627  }
1628  return DestF;
1629  case IMAGEIO_DOUBLE: /* Destination type is double */
1630  if(!(DestD = (double *)Malloc(sizeof(double)*NumChannels*NumPixels)))
1631  return NULL;
1632 
1633  switch(NumChannels)
1634  {
1635  case 1: /* Convert RGBA U8 to grayscale double */
1636  for(y = 0; y < Height; y++, Src += Width)
1637  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1638  {
1639  Pixel = Src[x];
1640  DestD[i] = 1.172549019607843070675535e-3*((uint8_t *)&Pixel)[0]
1641  + 2.301960784313725357840079e-3*((uint8_t *)&Pixel)[1]
1642  + 4.470588235294117808150007e-4*((uint8_t *)&Pixel)[2];
1643  }
1644  break;
1645  case 3: /* Convert RGBA U8 to RGB (or BGR) double */
1646  for(y = 0; y < Height; y++, Src += Width)
1647  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1648  {
1649  Pixel = Src[x];
1650  DestD[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0;
1651  DestD[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0;
1652  DestD[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0;
1653  }
1654  break;
1655  case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) double */
1656  for(y = 0; y < Height; y++, Src += Width)
1657  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1658  {
1659  Pixel = Src[x];
1660  DestD[i] = ((uint8_t *)&Pixel)[Order[0]]/255.0;
1661  DestD[i + ChannelStride] = ((uint8_t *)&Pixel)[Order[1]]/255.0;
1662  DestD[i + ChannelStride2] = ((uint8_t *)&Pixel)[Order[2]]/255.0;
1663  DestD[i + ChannelStride3] = ((uint8_t *)&Pixel)[Order[3]]/255.0;
1664  }
1665  break;
1666  }
1667  return DestD;
1668  default:
1669  return NULL;
1670  }
1671 }
1672 
1673 
1675 static uint32_t *ConvertFromFormat(void *Src, int Width, int Height,
1676  unsigned Format)
1677 {
1678  const int NumPixels = Width*Height;
1679  const int NumChannels = (Format & IMAGEIO_GRAYSCALE) ?
1680  1 : ((Format & IMAGEIO_STRIP_ALPHA) ? 3 : 4);
1681  const int ChannelStride = (Format & IMAGEIO_PLANAR) ? NumPixels : 1;
1682  const int ChannelStride2 = 2*ChannelStride;
1683  const int ChannelStride3 = 3*ChannelStride;
1684  double *SrcD = (double *)Src;
1685  float *SrcF = (float *)Src;
1686  uint8_t *SrcU8 = (uint8_t *)Src;
1687  uint8_t *Dest, *DestPtr;
1688  int Order[4] = {0, 1, 2, 3};
1689  int i, x, y, PixelStride, RowStride;
1690 
1691 
1692  if(!(Dest = (uint8_t *)Malloc(sizeof(uint32_t)*NumPixels)))
1693  return NULL;
1694 
1695  DestPtr = Dest;
1696  PixelStride = (Format & IMAGEIO_PLANAR) ? 1 : NumChannels;
1697 
1698  if(Format & IMAGEIO_COLUMNMAJOR)
1699  {
1700  RowStride = PixelStride;
1701  PixelStride *= Height;
1702  }
1703  else
1704  RowStride = Width*PixelStride;
1705 
1706  if(Format & IMAGEIO_BGRFLIP)
1707  {
1708  Order[0] = 2;
1709  Order[2] = 0;
1710  }
1711 
1712  if((Format & IMAGEIO_AFLIP) && !(Format & IMAGEIO_STRIP_ALPHA))
1713  {
1714  Order[3] = Order[2];
1715  Order[2] = Order[1];
1716  Order[1] = Order[0];
1717  Order[0] = 3;
1718  }
1719 
1720  switch(Format & (IMAGEIO_U8 | IMAGEIO_SINGLE | IMAGEIO_DOUBLE))
1721  {
1722  case IMAGEIO_U8: /* Source type is uint8_t */
1723  switch(NumChannels)
1724  {
1725  case 1: /* Convert grayscale U8 to RGBA U8 */
1726  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1727  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1728  {
1729  DestPtr[4*x] =
1730  DestPtr[4*x + 1] =
1731  DestPtr[4*x + 2] = SrcU8[i];
1732  DestPtr[4*x + 3] = 255;
1733  }
1734  break;
1735  case 3: /* Convert RGB (or BGR) U8 to RGBA U8 */
1736  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1737  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1738  {
1739  DestPtr[4*x + Order[0]] = SrcU8[i];
1740  DestPtr[4*x + Order[1]] = SrcU8[i + ChannelStride];
1741  DestPtr[4*x + Order[2]] = SrcU8[i + ChannelStride2];
1742  DestPtr[4*x + 3] = 255;
1743  }
1744  break;
1745  case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) U8 */
1746  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1747  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1748  {
1749  DestPtr[4*x + Order[0]] = SrcU8[i];
1750  DestPtr[4*x + Order[1]] = SrcU8[i + ChannelStride];
1751  DestPtr[4*x + Order[2]] = SrcU8[i + ChannelStride2];
1752  DestPtr[4*x + Order[3]] = SrcU8[i + ChannelStride3];
1753  }
1754  break;
1755  }
1756  break;
1757  case IMAGEIO_SINGLE: /* Source type is float */
1758  switch(NumChannels)
1759  {
1760  case 1: /* Convert grayscale float to RGBA U8 */
1761  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1762  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1763  {
1764  DestPtr[4*x] =
1765  DestPtr[4*x + 1] =
1766  DestPtr[4*x + 2] = ROUNDCLAMPF(SrcF[i]);
1767  DestPtr[4*x + 3] = 255;
1768  }
1769  break;
1770  case 3: /* Convert RGBA U8 to RGB (or BGR) float */
1771  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1772  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1773  {
1774  DestPtr[4*x + Order[0]] = ROUNDCLAMPF(SrcF[i]);
1775  DestPtr[4*x + Order[1]] = ROUNDCLAMPF(SrcF[i + ChannelStride]);
1776  DestPtr[4*x + Order[2]] = ROUNDCLAMPF(SrcF[i + ChannelStride2]);
1777  DestPtr[4*x + 3] = 255;
1778  }
1779  break;
1780  case 4: /* Convert RGBA U8 to RGBA (or BGRA, ARGB, or ABGR) float */
1781  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1782  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1783  {
1784  DestPtr[4*x + Order[0]] = ROUNDCLAMPF(SrcF[i]);
1785  DestPtr[4*x + Order[1]] = ROUNDCLAMPF(SrcF[i + ChannelStride]);
1786  DestPtr[4*x + Order[2]] = ROUNDCLAMPF(SrcF[i + ChannelStride2]);
1787  DestPtr[4*x + Order[3]] = ROUNDCLAMPF(SrcF[i + ChannelStride3]);
1788  }
1789  break;
1790  }
1791  break;
1792  case IMAGEIO_DOUBLE: /* Source type is double */
1793  switch(NumChannels)
1794  {
1795  case 1: /* Convert grayscale double to RGBA U8 */
1796  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1797  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1798  {
1799  DestPtr[4*x] =
1800  DestPtr[4*x + 1] =
1801  DestPtr[4*x + 2] = ROUNDCLAMP(SrcD[i]);
1802  DestPtr[4*x + 3] = 255;
1803  }
1804  break;
1805  case 3: /* Convert RGB (or BGR) double to RGBA U8 */
1806  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1807  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1808  {
1809  DestPtr[4*x + Order[0]] = ROUNDCLAMP(SrcD[i]);
1810  DestPtr[4*x + Order[1]] = ROUNDCLAMP(SrcD[i + ChannelStride]);
1811  DestPtr[4*x + Order[2]] = ROUNDCLAMP(SrcD[i + ChannelStride2]);
1812  DestPtr[4*x + 3] = 255;;
1813  }
1814  break;
1815  case 4: /* Convert RGBA (or BGRA, ARGB, or ABGR) double to RGBA U8 */
1816  for(y = 0; y < Height; y++, DestPtr += 4*Width)
1817  for(x = 0, i = RowStride*y; x < Width; x++, i += PixelStride)
1818  {
1819  DestPtr[4*x + Order[0]] = ROUNDCLAMP(SrcD[i]);
1820  DestPtr[4*x + Order[1]] = ROUNDCLAMP(SrcD[i + ChannelStride]);
1821  DestPtr[4*x + Order[2]] = ROUNDCLAMP(SrcD[i + ChannelStride2]);
1822  DestPtr[4*x + Order[3]] = ROUNDCLAMP(SrcD[i + ChannelStride3]);
1823  }
1824  break;
1825  }
1826  break;
1827  default:
1828  return NULL;
1829  }
1830 
1831  return (uint32_t *)Dest;
1832 }
1833 
1834 
1844 int IdentifyImageType(char *Type, const char *FileName)
1845 {
1846  FILE *File;
1847  uint32_t Magic;
1848 
1849 
1850  Type[0] = '\0';
1851 
1852  if(!(File = fopen(FileName, "rb")))
1853  return 0;
1854 
1855  /* Determine the file format by reading the first 4 bytes */
1856  Magic = ((uint32_t)getc(File));
1857  Magic |= ((uint32_t)getc(File)) << 8;
1858  Magic |= ((uint32_t)getc(File)) << 16;
1859  Magic |= ((uint32_t)getc(File)) << 24;
1860 
1861  /* Test for errors */
1862  if(ferror(File))
1863  {
1864  fclose(File);
1865  return 0;
1866  }
1867 
1868  fclose(File);
1869 
1870  if((Magic & 0x0000FFFFL) == 0x00004D42L) /* BMP */
1871  strcpy(Type, "BMP");
1872  else if((Magic & 0x00FFFFFFL) == 0x00FFD8FFL) /* JPEG/JFIF */
1873  strcpy(Type, "JPEG");
1874  else if(Magic == 0x474E5089L) /* PNG */
1875  strcpy(Type, "PNG");
1876  else if(Magic == 0x002A4949L || Magic == 0x2A004D4DL) /* TIFF */
1877  strcpy(Type, "TIFF");
1878  else if(Magic == 0x38464947L) /* GIF */
1879  strcpy(Type, "GIF");
1880  else if(Magic == 0x474E4D8AL) /* MNG */
1881  strcpy(Type, "MNG");
1882  else if((Magic & 0xF0FF00FFL) == 0x0001000AL /* PCX */
1883  && ((Magic >> 8) & 0xFF) < 6)
1884  strcpy(Type, "PCX");
1885  else
1886  return 0;
1887 
1888  return 1;
1889 }
1890 
1891 
1973 void *ReadImage(int *Width, int *Height,
1974  const char *FileName, unsigned Format)
1975 {
1976  void *Image = NULL;
1977  uint32_t *ImageU8 = NULL;
1978  FILE *File;
1979  char Type[8];
1980 
1981 
1982  IdentifyImageType(Type, FileName);
1983 
1984  if(!(File = fopen(FileName, "rb")))
1985  {
1986  ErrorMessage("Unable to open file \"%s\".\n", FileName);
1987  return 0;
1988  }
1989 
1990  if(!strcmp(Type, "BMP"))
1991  {
1992  if(!ReadBmp(&ImageU8, Width, Height, File))
1993  ErrorMessage("Failed to read \"%s\".\n", FileName);
1994  }
1995  else if(!strcmp(Type, "JPEG"))
1996  {
1997 #ifdef USE_LIBJPEG
1998  if(!(ReadJpeg(&ImageU8, Width, Height, File)))
1999  ErrorMessage("Failed to read \"%s\".\n", FileName);
2000 #else
2001  ErrorMessage("File \"%s\" is a JPEG image.\n"
2002  "Compile with USE_LIBJPEG to enable JPEG reading.\n",
2003  FileName);
2004 #endif
2005  }
2006  else if(!strcmp(Type, "PNG"))
2007  {
2008 #ifdef USE_LIBPNG
2009  if(!(ReadPng(&ImageU8, Width, Height, File)))
2010  ErrorMessage("Failed to read \"%s\".\n", FileName);
2011 #else
2012  ErrorMessage("File \"%s\" is a PNG image.\n"
2013  "Compile with USE_LIBPNG to enable PNG reading.\n",
2014  FileName);
2015 #endif
2016  }
2017  else if(!strcmp(Type, "TIFF"))
2018  {
2019 #ifdef USE_LIBTIFF
2020  fclose(File);
2021 
2022  if(!(ReadTiff(&ImageU8, Width, Height, FileName, 0)))
2023  ErrorMessage("Failed to read \"%s\".\n", FileName);
2024 
2025  File = NULL;
2026 #else
2027  ErrorMessage("File \"%s\" is a TIFF image.\n"
2028  "Compile with USE_LIBTIFF to enable TIFF reading.\n",
2029  FileName);
2030 #endif
2031  }
2032  else
2033  {
2034  /* File format is unsupported. */
2035  if(Type[0])
2036  ErrorMessage("File \"%s\" is a %s image.", FileName, Type);
2037  else
2038  ErrorMessage("File \"%s\" is an unrecognized format.", FileName);
2039  fprintf(stderr, "\nSorry, only " READIMAGE_FORMATS_SUPPORTED " reading is supported.\n");
2040  }
2041 
2042  if(File)
2043  fclose(File);
2044 
2045  if(ImageU8 && Format)
2046  {
2047  Image = ConvertToFormat(ImageU8, *Width, *Height, Format);
2048  Free(ImageU8);
2049  }
2050  else
2051  Image = ImageU8;
2052 
2053  return Image;
2054 }
2055 
2056 
2076 int WriteImage(void *Image, int Width, int Height,
2077  const char *FileName, unsigned Format, int Quality)
2078 {
2079  FILE *File;
2080  uint32_t *ImageU8;
2081  enum {BMP_FORMAT, JPEG_FORMAT, PNG_FORMAT, TIFF_FORMAT} FileFormat;
2082  int Success = 0;
2083 
2084  if(!Image || Width <= 0 || Height <= 0)
2085  {
2086  ErrorMessage("Null image.\n");
2087  ErrorMessage("Failed to write \"%s\".\n", FileName);
2088  return 0;
2089  }
2090 
2091  if(StringEndsWith(FileName, ".bmp"))
2092  FileFormat = BMP_FORMAT;
2093  else if(StringEndsWith(FileName, ".jpg")
2094  || StringEndsWith(FileName, ".jpeg"))
2095  {
2096  FileFormat = JPEG_FORMAT;
2097 #ifndef USE_LIBJPEG
2098  ErrorMessage("Failed to write \"%s\".\n", FileName);
2099  ErrorMessage("Compile with USE_LIBJPEG to enable JPEG writing.\n");
2100  return 0;
2101 #endif
2102  }
2103  else if(StringEndsWith(FileName, ".png"))
2104  {
2105  FileFormat = PNG_FORMAT;
2106 #ifndef USE_LIBPNG
2107  ErrorMessage("Failed to write \"%s\".\n", FileName);
2108  ErrorMessage("Compile with USE_LIBPNG to enable PNG writing.\n");
2109  return 0;
2110 #endif
2111  }
2112  else if(StringEndsWith(FileName, ".tif")
2113  || StringEndsWith(FileName, ".tiff"))
2114  {
2115  FileFormat = TIFF_FORMAT;
2116 #ifndef USE_LIBTIFF
2117  ErrorMessage("Failed to write \"%s\".\n", FileName);
2118  ErrorMessage("Compile with USE_LIBTIFF to enable TIFF writing.\n");
2119  return 0;
2120 #endif
2121  }
2122  else
2123  {
2124  ErrorMessage("Failed to write \"%s\".\n", FileName);
2125 
2126  if(StringEndsWith(FileName, ".gif"))
2127  ErrorMessage("GIF is not supported. ");
2128  else if(StringEndsWith(FileName, ".mng"))
2129  ErrorMessage("MNG is not supported. ");
2130  else if(StringEndsWith(FileName, ".pcx"))
2131  ErrorMessage("PCX is not supported. ");
2132  else
2133  ErrorMessage("Unable to determine format from extension.\n");
2134 
2135  ErrorMessage("Sorry, only " WRITEIMAGE_FORMATS_SUPPORTED " writing is supported.\n");
2136  return 0;
2137  }
2138 
2139  if(!(File = fopen(FileName, "wb")))
2140  {
2141  ErrorMessage("Unable to write to file \"%s\".\n", FileName);
2142  return 0;
2143  }
2144 
2145  if(!(ImageU8 = ConvertFromFormat(Image, Width, Height, Format)))
2146  return 0;
2147 
2148  switch(FileFormat)
2149  {
2150  case BMP_FORMAT:
2151  Success = WriteBmp(ImageU8, Width, Height, File);
2152  break;
2153  case JPEG_FORMAT:
2154 #ifdef USE_LIBJPEG
2155  Success = WriteJpeg(ImageU8, Width, Height, File, Quality);
2156 #else
2157  /* Dummy operation to avoid unused variable warning if compiled without
2158  libjpeg. Note that execution returns above if Format == JPEG_FORMAT
2159  and USE_LIBJPEG is undefined. */
2160  Success = Quality;
2161 #endif
2162  break;
2163  case PNG_FORMAT:
2164 #ifdef USE_LIBPNG
2165  Success = WritePng(ImageU8, Width, Height, File);
2166 #endif
2167  break;
2168  case TIFF_FORMAT:
2169 #ifdef USE_LIBTIFF
2170  fclose(File);
2171  Success = WriteTiff(ImageU8, Width, Height, FileName);
2172  File = 0;
2173 #endif
2174  break;
2175  }
2176 
2177  if(!Success)
2178  ErrorMessage("Failed to write \"%s\".\n", FileName);
2179 
2180  Free(ImageU8);
2181 
2182  if(File)
2183  fclose(File);
2184 
2185  return Success;
2186 }