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 #if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \
     30     defined (PNG_iCCP_SUPPORTED)
     31 
     32 
     33 static int verbose = 1;
     34 static png_byte no_profile[] = "no profile";
     35 
     36 static png_bytep
     37 extract(FILE *fp, png_uint_32 *proflen)
     38 {
     39    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
     40    png_infop info_ptr = NULL;
     41    png_bytep result = NULL;
     42 
     43    /* Initialize for error or no profile: */
     44    *proflen = 0;
     45 
     46    if (png_ptr == NULL)
     47    {
     48       fprintf(stderr, "iccfrompng: version library mismatch?\n");
     49       return 0;
     50    }
     51 
     52    if (setjmp(png_jmpbuf(png_ptr)))
     53    {
     54       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     55       return 0;
     56    }
     57 
     58    png_init_io(png_ptr, fp);
     59 
     60    info_ptr = png_create_info_struct(png_ptr);
     61    if (info_ptr == NULL)
     62       png_error(png_ptr, "OOM allocating info structure");
     63 
     64    png_read_info(png_ptr, info_ptr);
     65 
     66    {
     67       png_charp name;
     68       int compression_type;
     69       png_bytep profile;
     70 
     71       if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
     72          proflen) & PNG_INFO_iCCP)
     73       {
     74          result = malloc(*proflen);
     75          if (result != NULL)
     76             memcpy(result, profile, *proflen);
     77 
     78          else
     79             png_error(png_ptr, "OOM allocating profile buffer");
     80       }
     81 
     82       else
     83 	result = no_profile;
     84    }
     85 
     86    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     87    return result;
     88 }
     89 
     90 static int
     91 extract_one_file(const char *filename)
     92 {
     93    int result = 0;
     94    FILE *fp = fopen(filename, "rb");
     95 
     96    if (fp != NULL)
     97    {
     98       png_uint_32 proflen = 0;
     99       png_bytep profile = extract(fp, &proflen);
    100 
    101       if (profile != NULL && profile != no_profile)
    102       {
    103          size_t len;
    104          char *output;
    105 
    106          {
    107             const char *ep = strrchr(filename, '.');
    108 
    109             if (ep != NULL)
    110                len = ep-filename;
    111 
    112             else
    113                len = strlen(filename);
    114          }
    115 
    116          output = malloc(len + 5);
    117          if (output != NULL)
    118          {
    119             FILE *of;
    120 
    121             memcpy(output, filename, len);
    122             strcpy(output+len, ".icc");
    123 
    124             of = fopen(output, "wb");
    125             if (of != NULL)
    126             {
    127                if (fwrite(profile, proflen, 1, of) == 1 &&
    128                   fflush(of) == 0 &&
    129                   fclose(of) == 0)
    130                {
    131                   if (verbose)
    132                      printf("%s -> %s\n", filename, output);
    133                   /* Success return */
    134                   result = 1;
    135                }
    136 
    137                else
    138                {
    139                   fprintf(stderr, "%s: error writing profile\n", output);
    140                   if (remove(output))
    141                      fprintf(stderr, "%s: could not remove file\n", output);
    142                }
    143             }
    144 
    145             else
    146                fprintf(stderr, "%s: failed to open output file\n", output);
    147 
    148             free(output);
    149          }
    150 
    151          else
    152             fprintf(stderr, "%s: OOM allocating string!\n", filename);
    153 
    154          free(profile);
    155       }
    156 
    157       else if (verbose && profile == no_profile)
    158 	printf("%s has no profile\n", filename);
    159    }
    160 
    161    else
    162       fprintf(stderr, "%s: could not open file\n", filename);
    163 
    164    return result;
    165 }
    166 
    167 int
    168 main(int argc, char **argv)
    169 {
    170    int i;
    171    int extracted = 0;
    172 
    173    for (i=1; i<argc; ++i)
    174    {
    175       if (strcmp(argv[i], "-q") == 0)
    176          verbose = 0;
    177 
    178       else if (extract_one_file(argv[i]))
    179          extracted = 1;
    180    }
    181 
    182    /* Exit code is true if any extract succeeds */
    183    return extracted == 0;
    184 }
    185 #endif /* READ && STDIO && iCCP */
    186