Home | History | Annotate | Download | only in examples
      1 /*- iccfrompng
      2  *
      3  * COPYRIGHT: Written by John Cunningham Bowler, 2011.
      4  * To the extent possible under law, the author has waived all copyright and
      5  * related or neighboring rights to this work.  This work is published from:
      6  * United States.
      7  *
      8  * Extract any icc profiles found in the given PNG files.  This is a simple
      9  * example of a program that extracts information from the header of a PNG file
     10  * without processing the image.  Notice that some header information may occur
     11  * after the image data. Textual data and comments are an example; the approach
     12  * in this file won't work reliably for such data because it only looks for the
     13  * information in the section of the file that preceeds the image data.
     14  *
     15  * Compile and link against libpng and zlib, plus anything else required on the
     16  * system you use.
     17  *
     18  * To use supply a list of PNG files containing iCCP chunks, the chunks will be
     19  * extracted to a similarly named file with the extension replaced by 'icc',
     20  * which will be overwritten without warning.
     21  */
     22 #include <stdlib.h>
     23 #include <setjmp.h>
     24 #include <string.h>
     25 #include <stdio.h>
     26 
     27 #include <png.h>
     28 
     29 static int verbose = 1;
     30 static png_byte no_profile[] = "no profile";
     31 
     32 static png_bytep
     33 extract(FILE *fp, png_uint_32 *proflen)
     34 {
     35    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
     36    png_infop info_ptr = NULL;
     37    png_bytep result = NULL;
     38 
     39    /* Initialize for error or no profile: */
     40    *proflen = 0;
     41 
     42    if (png_ptr == NULL)
     43    {
     44       fprintf(stderr, "iccfrompng: version library mismatch?\n");
     45       return 0;
     46    }
     47 
     48    if (setjmp(png_jmpbuf(png_ptr)))
     49    {
     50       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     51       return 0;
     52    }
     53 
     54    png_init_io(png_ptr, fp);
     55 
     56    info_ptr = png_create_info_struct(png_ptr);
     57    if (info_ptr == NULL)
     58       png_error(png_ptr, "OOM allocating info structure");
     59 
     60    png_read_info(png_ptr, info_ptr);
     61 
     62    {
     63       png_charp name;
     64       int compression_type;
     65       png_bytep profile;
     66 
     67       if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
     68          proflen) & PNG_INFO_iCCP)
     69       {
     70          result = malloc(*proflen);
     71          if (result != NULL)
     72             memcpy(result, profile, *proflen);
     73 
     74          else
     75             png_error(png_ptr, "OOM allocating profile buffer");
     76       }
     77 
     78       else
     79 	result = no_profile;
     80    }
     81 
     82    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     83    return result;
     84 }
     85 
     86 static int
     87 extract_one_file(const char *filename)
     88 {
     89    int result = 0;
     90    FILE *fp = fopen(filename, "rb");
     91 
     92    if (fp != NULL)
     93    {
     94       png_uint_32 proflen = 0;
     95       png_bytep profile = extract(fp, &proflen);
     96 
     97       if (profile != NULL && profile != no_profile)
     98       {
     99          size_t len;
    100          char *output;
    101 
    102          {
    103             const char *ep = strrchr(filename, '.');
    104 
    105             if (ep != NULL)
    106                len = ep-filename;
    107 
    108             else
    109                len = strlen(filename);
    110          }
    111 
    112          output = malloc(len + 5);
    113          if (output != NULL)
    114          {
    115             FILE *of;
    116 
    117             memcpy(output, filename, len);
    118             strcpy(output+len, ".icc");
    119 
    120             of = fopen(output, "wb");
    121             if (of != NULL)
    122             {
    123                if (fwrite(profile, proflen, 1, of) == 1 &&
    124                   fflush(of) == 0 &&
    125                   fclose(of) == 0)
    126                {
    127                   if (verbose)
    128                      printf("%s -> %s\n", filename, output);
    129                   /* Success return */
    130                   result = 1;
    131                }
    132 
    133                else
    134                {
    135                   fprintf(stderr, "%s: error writing profile\n", output);
    136                   if (remove(output))
    137                      fprintf(stderr, "%s: could not remove file\n", output);
    138                }
    139             }
    140 
    141             else
    142                fprintf(stderr, "%s: failed to open output file\n", output);
    143 
    144             free(output);
    145          }
    146 
    147          else
    148             fprintf(stderr, "%s: OOM allocating string!\n", filename);
    149 
    150          free(profile);
    151       }
    152 
    153       else if (verbose && profile == no_profile)
    154 	printf("%s has no profile\n", filename);
    155    }
    156 
    157    else
    158       fprintf(stderr, "%s: could not open file\n", filename);
    159 
    160    return result;
    161 }
    162 
    163 int
    164 main(int argc, char **argv)
    165 {
    166    int i;
    167    int extracted = 0;
    168 
    169    for (i=1; i<argc; ++i)
    170    {
    171       if (strcmp(argv[i], "-q") == 0)
    172          verbose = 0;
    173 
    174       else if (extract_one_file(argv[i]))
    175          extracted = 1;
    176    }
    177 
    178    /* Exit code is true if any extract succeeds */
    179    return extracted == 0;
    180 }
    181