all repos — mgba @ 6882339f625b97f344c6464915c2038bc453ea3c

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/pngminus/pnm2png.c (view raw)

  1/*
  2 *  pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
  3 *  copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
  4 *
  5 *  version 1.0 - 1999.10.15 - First version.
  6 *
  7 *  Permission to use, copy, modify, and distribute this software and
  8 *  its documentation for any purpose and without fee is hereby granted,
  9 *  provided that the above copyright notice appear in all copies and
 10 *  that both that copyright notice and this permission notice appear in
 11 *  supporting documentation. This software is provided "as is" without
 12 *  express or implied warranty.
 13 */
 14
 15#include <stdio.h>
 16#include <stdlib.h>
 17#ifdef __TURBOC__
 18#include <mem.h>
 19#include <fcntl.h>
 20#endif
 21#include <zlib.h>
 22
 23#ifndef BOOL
 24#define BOOL unsigned char
 25#endif
 26#ifndef TRUE
 27#define TRUE (BOOL) 1
 28#endif
 29#ifndef FALSE
 30#define FALSE (BOOL) 0
 31#endif
 32
 33#define STDIN  0
 34#define STDOUT 1
 35#define STDERR 2
 36
 37/* to make pnm2png verbose so we can find problems (needs to be before png.h) */
 38#ifndef PNG_DEBUG
 39#define PNG_DEBUG 0
 40#endif
 41
 42#include "png.h"
 43
 44/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
 45#ifndef png_jmpbuf
 46#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
 47#endif
 48
 49/* function prototypes */
 50
 51int  main (int argc, char *argv[]);
 52void usage ();
 53BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
 54    BOOL alpha);
 55void get_token(FILE *pnm_file, char *token);
 56png_uint_32 get_data (FILE *pnm_file, int depth);
 57png_uint_32 get_value (FILE *pnm_file, int depth);
 58
 59/*
 60 *  main
 61 */
 62
 63int main(int argc, char *argv[])
 64{
 65  FILE *fp_rd = stdin;
 66  FILE *fp_al = NULL;
 67  FILE *fp_wr = stdout;
 68  BOOL interlace = FALSE;
 69  BOOL alpha = FALSE;
 70  int argi;
 71
 72  for (argi = 1; argi < argc; argi++)
 73  {
 74    if (argv[argi][0] == '-')
 75    {
 76      switch (argv[argi][1])
 77      {
 78        case 'i':
 79          interlace = TRUE;
 80          break;
 81        case 'a':
 82          alpha = TRUE;
 83          argi++;
 84          if ((fp_al = fopen (argv[argi], "rb")) == NULL)
 85          {
 86            fprintf (stderr, "PNM2PNG\n");
 87            fprintf (stderr, "Error:  alpha-channel file %s does not exist\n",
 88               argv[argi]);
 89            exit (1);
 90          }
 91          break;
 92        case 'h':
 93        case '?':
 94          usage();
 95          exit(0);
 96          break;
 97        default:
 98          fprintf (stderr, "PNM2PNG\n");
 99          fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
100          usage();
101          exit(1);
102          break;
103      } /* end switch */
104    }
105    else if (fp_rd == stdin)
106    {
107      if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
108      {
109        fprintf (stderr, "PNM2PNG\n");
110        fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
111        exit (1);
112      }
113    }
114    else if (fp_wr == stdout)
115    {
116      if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
117      {
118        fprintf (stderr, "PNM2PNG\n");
119        fprintf (stderr, "Error:  can not create PNG-file %s\n", argv[argi]);
120        exit (1);
121      }
122    }
123    else
124    {
125      fprintf (stderr, "PNM2PNG\n");
126      fprintf (stderr, "Error:  too many parameters\n");
127      usage();
128      exit (1);
129    }
130  } /* end for */
131
132#ifdef __TURBOC__
133  /* set stdin/stdout to binary, we're reading the PNM always! in binary format */
134  if (fp_rd == stdin)
135  {
136    setmode (STDIN, O_BINARY);
137  }
138  if (fp_wr == stdout)
139  {
140    setmode (STDOUT, O_BINARY);
141  }
142#endif
143
144  /* call the conversion program itself */
145  if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE)
146  {
147    fprintf (stderr, "PNM2PNG\n");
148    fprintf (stderr, "Error:  unsuccessful converting to PNG-image\n");
149    exit (1);
150  }
151
152  /* close input file */
153  fclose (fp_rd);
154  /* close output file */
155  fclose (fp_wr);
156  /* close alpha file */
157  if (alpha)
158    fclose (fp_al);
159
160  return 0;
161}
162
163/*
164 *  usage
165 */
166
167void usage()
168{
169  fprintf (stderr, "PNM2PNG\n");
170  fprintf (stderr, "   by Willem van Schaik, 1999\n");
171#ifdef __TURBOC__
172  fprintf (stderr, "   for Turbo-C and Borland-C compilers\n");
173#else
174  fprintf (stderr, "   for Linux (and Unix) compilers\n");
175#endif
176  fprintf (stderr, "Usage:  pnm2png [options] <file>.<pnm> [<file>.png]\n");
177  fprintf (stderr, "   or:  ... | pnm2png [options]\n");
178  fprintf (stderr, "Options:\n");
179  fprintf (stderr, "   -i[nterlace]   write png-file with interlacing on\n");
180  fprintf (stderr,
181      "   -a[lpha] <file>.pgm read PNG alpha channel as pgm-file\n");
182  fprintf (stderr, "   -h | -?  print this help-information\n");
183}
184
185/*
186 *  pnm2png
187 */
188
189BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
190     BOOL alpha)
191{
192  png_struct    *png_ptr = NULL;
193  png_info      *info_ptr = NULL;
194  png_byte      *png_pixels = NULL;
195  png_byte      **row_pointers = NULL;
196  png_byte      *pix_ptr = NULL;
197  volatile png_uint_32   row_bytes;
198
199  char          type_token[16];
200  char          width_token[16];
201  char          height_token[16];
202  char          maxval_token[16];
203  volatile int           color_type;
204  unsigned long   ul_width=0, ul_alpha_width=0;
205  unsigned long   ul_height=0, ul_alpha_height=0;
206  unsigned long   ul_maxval=0;
207  volatile png_uint_32   width, height;
208  volatile png_uint_32   alpha_width, alpha_height;
209  png_uint_32   maxval;
210  volatile int           bit_depth = 0;
211  int           channels;
212  int           alpha_depth = 0;
213  int           alpha_present;
214  int           row, col;
215  BOOL          raw, alpha_raw = FALSE;
216#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
217  BOOL          packed_bitmap = FALSE;
218#endif
219  png_uint_32   tmp16;
220  int           i;
221
222  /* read header of PNM file */
223
224  get_token(pnm_file, type_token);
225  if (type_token[0] != 'P')
226  {
227    return FALSE;
228  }
229  else if ((type_token[1] == '1') || (type_token[1] == '4'))
230  {
231#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
232    raw = (type_token[1] == '4');
233    color_type = PNG_COLOR_TYPE_GRAY;
234    get_token(pnm_file, width_token);
235    sscanf (width_token, "%lu", &ul_width);
236    width = (png_uint_32) ul_width;
237    get_token(pnm_file, height_token);
238    sscanf (height_token, "%lu", &ul_height);
239    height = (png_uint_32) ul_height;
240    bit_depth = 1;
241    packed_bitmap = TRUE;
242#else
243    fprintf (stderr, "PNM2PNG built without PNG_WRITE_INVERT_SUPPORTED and \n");
244    fprintf (stderr, "PNG_WRITE_PACK_SUPPORTED can't read PBM (P1,P4) files\n");
245#endif
246  }
247  else if ((type_token[1] == '2') || (type_token[1] == '5'))
248  {
249    raw = (type_token[1] == '5');
250    color_type = PNG_COLOR_TYPE_GRAY;
251    get_token(pnm_file, width_token);
252    sscanf (width_token, "%lu", &ul_width);
253    width = (png_uint_32) ul_width;
254    get_token(pnm_file, height_token);
255    sscanf (height_token, "%lu", &ul_height);
256    height = (png_uint_32) ul_height;
257    get_token(pnm_file, maxval_token);
258    sscanf (maxval_token, "%lu", &ul_maxval);
259    maxval = (png_uint_32) ul_maxval;
260
261    if (maxval <= 1)
262      bit_depth = 1;
263    else if (maxval <= 3)
264      bit_depth = 2;
265    else if (maxval <= 15)
266      bit_depth = 4;
267    else if (maxval <= 255)
268      bit_depth = 8;
269    else /* if (maxval <= 65535) */
270      bit_depth = 16;
271  }
272  else if ((type_token[1] == '3') || (type_token[1] == '6'))
273  {
274    raw = (type_token[1] == '6');
275    color_type = PNG_COLOR_TYPE_RGB;
276    get_token(pnm_file, width_token);
277    sscanf (width_token, "%lu", &ul_width);
278    width = (png_uint_32) ul_width;
279    get_token(pnm_file, height_token);
280    sscanf (height_token, "%lu", &ul_height);
281    height = (png_uint_32) ul_height;
282    get_token(pnm_file, maxval_token);
283    sscanf (maxval_token, "%lu", &ul_maxval);
284    maxval = (png_uint_32) ul_maxval;
285    if (maxval <= 1)
286      bit_depth = 1;
287    else if (maxval <= 3)
288      bit_depth = 2;
289    else if (maxval <= 15)
290      bit_depth = 4;
291    else if (maxval <= 255)
292      bit_depth = 8;
293    else /* if (maxval <= 65535) */
294      bit_depth = 16;
295  }
296  else
297  {
298    return FALSE;
299  }
300
301  /* read header of PGM file with alpha channel */
302
303  if (alpha)
304  {
305    if (color_type == PNG_COLOR_TYPE_GRAY)
306      color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
307    if (color_type == PNG_COLOR_TYPE_RGB)
308      color_type = PNG_COLOR_TYPE_RGB_ALPHA;
309
310    get_token(alpha_file, type_token);
311    if (type_token[0] != 'P')
312    {
313      return FALSE;
314    }
315    else if ((type_token[1] == '2') || (type_token[1] == '5'))
316    {
317      alpha_raw = (type_token[1] == '5');
318      get_token(alpha_file, width_token);
319      sscanf (width_token, "%lu", &ul_alpha_width);
320      alpha_width=(png_uint_32) ul_alpha_width;
321      if (alpha_width != width)
322        return FALSE;
323      get_token(alpha_file, height_token);
324      sscanf (height_token, "%lu", &ul_alpha_height);
325      alpha_height = (png_uint_32) ul_alpha_height;
326      if (alpha_height != height)
327        return FALSE;
328      get_token(alpha_file, maxval_token);
329      sscanf (maxval_token, "%lu", &ul_maxval);
330      maxval = (png_uint_32) ul_maxval;
331      if (maxval <= 1)
332        alpha_depth = 1;
333      else if (maxval <= 3)
334        alpha_depth = 2;
335      else if (maxval <= 15)
336        alpha_depth = 4;
337      else if (maxval <= 255)
338        alpha_depth = 8;
339      else /* if (maxval <= 65535) */
340        alpha_depth = 16;
341      if (alpha_depth != bit_depth)
342        return FALSE;
343    }
344    else
345    {
346      return FALSE;
347    }
348  } /* end if alpha */
349
350  /* calculate the number of channels and store alpha-presence */
351  if (color_type == PNG_COLOR_TYPE_GRAY)
352    channels = 1;
353  else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
354    channels = 2;
355  else if (color_type == PNG_COLOR_TYPE_RGB)
356    channels = 3;
357  else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
358    channels = 4;
359  else
360    channels = 0; /* should not happen */
361
362  alpha_present = (channels - 1) % 2;
363
364#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
365  if (packed_bitmap)
366    /* row data is as many bytes as can fit width x channels x bit_depth */
367    row_bytes = (width * channels * bit_depth + 7) / 8;
368  else
369#endif
370    /* row_bytes is the width x number of channels x (bit-depth / 8) */
371    row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
372
373  if ((png_pixels = (png_byte *)
374     malloc (row_bytes * height * sizeof (png_byte))) == NULL)
375    return FALSE;
376
377  /* read data from PNM file */
378  pix_ptr = png_pixels;
379
380  for (row = 0; row < (int) height; row++)
381  {
382#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
383    if (packed_bitmap) {
384      for (i = 0; i < (int) row_bytes; i++)
385        /* png supports this format natively so no conversion is needed */
386        *pix_ptr++ = get_data (pnm_file, 8);
387    } else
388#endif
389    {
390      for (col = 0; col < (int) width; col++)
391      {
392        for (i = 0; i < (channels - alpha_present); i++)
393        {
394          if (raw)
395            *pix_ptr++ = get_data (pnm_file, bit_depth);
396          else
397            if (bit_depth <= 8)
398              *pix_ptr++ = get_value (pnm_file, bit_depth);
399            else
400            {
401              tmp16 = get_value (pnm_file, bit_depth);
402              *pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
403              pix_ptr++;
404              *pix_ptr = (png_byte) (tmp16 & 0xFF);
405              pix_ptr++;
406            }
407        }
408
409        if (alpha) /* read alpha-channel from pgm file */
410        {
411          if (alpha_raw)
412            *pix_ptr++ = get_data (alpha_file, alpha_depth);
413          else
414            if (alpha_depth <= 8)
415              *pix_ptr++ = get_value (alpha_file, bit_depth);
416            else
417            {
418              tmp16 = get_value (alpha_file, bit_depth);
419              *pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
420              *pix_ptr++ = (png_byte) (tmp16 & 0xFF);
421            }
422        } /* if alpha */
423      } /* if packed_bitmap */
424    } /* end for col */
425  } /* end for row */
426
427  /* prepare the standard PNG structures */
428  png_ptr = png_create_write_struct (png_get_libpng_ver(NULL), NULL, NULL,
429      NULL);
430  if (!png_ptr)
431  {
432    return FALSE;
433  }
434  info_ptr = png_create_info_struct (png_ptr);
435  if (!info_ptr)
436  {
437    png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
438    return FALSE;
439  }
440
441#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
442  if (packed_bitmap == TRUE)
443  {
444    png_set_packing (png_ptr);
445    png_set_invert_mono (png_ptr);
446  }
447#endif
448
449  /* setjmp() must be called in every function that calls a PNG-reading libpng function */
450  if (setjmp (png_jmpbuf(png_ptr)))
451  {
452    png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
453    return FALSE;
454  }
455
456  /* initialize the png structure */
457  png_init_io (png_ptr, png_file);
458
459  /* we're going to write more or less the same PNG as the input file */
460  png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
461    (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,
462    PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
463
464  /* write the file header information */
465  png_write_info (png_ptr, info_ptr);
466
467  /* if needed we will allocate memory for an new array of row-pointers */
468  if (row_pointers == (unsigned char**) NULL)
469  {
470    if ((row_pointers = (png_byte **)
471        malloc (height * sizeof (png_bytep))) == NULL)
472    {
473      png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
474      return FALSE;
475    }
476  }
477
478  /* set the individual row_pointers to point at the correct offsets */
479  for (i = 0; i < (int) height; i++)
480    row_pointers[i] = png_pixels + i * row_bytes;
481
482  /* write out the entire image data in one call */
483  png_write_image (png_ptr, row_pointers);
484
485  /* write the additional chunks to the PNG file (not really needed) */
486  png_write_end (png_ptr, info_ptr);
487
488  /* clean up after the write, and free any memory allocated */
489  png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
490
491  if (row_pointers != (unsigned char**) NULL)
492    free (row_pointers);
493  if (png_pixels != (unsigned char*) NULL)
494    free (png_pixels);
495
496  return TRUE;
497} /* end of pnm2png */
498
499/*
500 * get_token() - gets the first string after whitespace
501 */
502
503void get_token(FILE *pnm_file, char *token)
504{
505  int i = 0;
506  int ret;
507
508  /* remove white-space and comment lines */
509  do
510  {
511    ret = fgetc(pnm_file);
512    if (ret == '#') {
513      /* the rest of this line is a comment */
514      do
515      {
516        ret = fgetc(pnm_file);
517      }
518      while ((ret != '\n') && (ret != '\r') && (ret != EOF));
519    }
520    if (ret == EOF) break;
521    token[i] = (unsigned char) ret;
522  }
523  while ((token[i] == '\n') || (token[i] == '\r') || (token[i] == ' '));
524
525  /* read string */
526  do
527  {
528    ret = fgetc(pnm_file);
529    if (ret == EOF) break;
530    i++;
531    token[i] = (unsigned char) ret;
532  }
533  while ((token[i] != '\n') && (token[i] != '\r') && (token[i] != ' '));
534
535  token[i] = '\0';
536
537  return;
538}
539
540/*
541 * get_data() - takes first byte and converts into next pixel value,
542 *        taking as much bits as defined by bit-depth and
543 *        using the bit-depth to fill up a byte (0Ah -> AAh)
544 */
545
546png_uint_32 get_data (FILE *pnm_file, int depth)
547{
548  static int bits_left = 0;
549  static int old_value = 0;
550  static int mask = 0;
551  int i;
552  png_uint_32 ret_value;
553
554  if (mask == 0)
555    for (i = 0; i < depth; i++)
556      mask = (mask >> 1) | 0x80;
557
558  if (bits_left <= 0)
559  {
560    old_value = fgetc (pnm_file);
561    bits_left = 8;
562  }
563
564  ret_value = old_value & mask;
565  for (i = 1; i < (8 / depth); i++)
566    ret_value = ret_value || (ret_value >> depth);
567
568  old_value = (old_value << depth) & 0xFF;
569  bits_left -= depth;
570
571  return ret_value;
572}
573
574/*
575 * get_value() - takes first (numeric) string and converts into number,
576 *         using the bit-depth to fill up a byte (0Ah -> AAh)
577 */
578
579png_uint_32 get_value (FILE *pnm_file, int depth)
580{
581  static png_uint_32 mask = 0;
582  png_byte token[16];
583  unsigned long ul_ret_value;
584  png_uint_32 ret_value;
585  int i = 0;
586
587  if (mask == 0)
588    for (i = 0; i < depth; i++)
589      mask = (mask << 1) | 0x01;
590
591  get_token (pnm_file, (char *) token);
592  sscanf ((const char *) token, "%lu", &ul_ret_value);
593  ret_value = (png_uint_32) ul_ret_value;
594
595  ret_value &= mask;
596
597  if (depth < 8)
598    for (i = 0; i < (8 / depth); i++)
599      ret_value = (ret_value << depth) || ret_value;
600
601  return ret_value;
602}
603
604/* end of source */
605