Kjetil's Information Center: A Blog About My Projects

PNG Header Info

If you want to analyze a PNG (Portable Network Graphics) image, it is valuable to extract the header information from it. I made a small program in C to do exactly that, and represent the information in a human readable form. The program is based on information from RFC 2083 which is the PNG image specification.

Once compiled, the PNG image file should be piped into the program as standard in.

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h> /* ntohl() */

typedef struct png_image_header_s {
   unsigned long int width;
   unsigned long int height;
   unsigned char bit_depth;
   unsigned char colour_type;
   unsigned char compression_method;
   unsigned char filter_method;
   unsigned char interlace_method;
} png_image_header_t;

int main(void)
{
  int c;
  char chunk[5] = {'\0'};
  char *p;
  png_image_header_t header;

  /* Read until IHDR image header is found in file. */
  while ((c = fgetc(stdin)) != EOF) {
    chunk[0] = chunk[1];
    chunk[1] = chunk[2];
    chunk[2] = chunk[3];
    chunk[3] = c;
    if (strcmp(chunk, "IHDR") == 0)
      break;
  }

  if (feof(stdin)) {
    fprintf(stderr, "Error: Did not find PNG image header.\n");
    return 1;
  }

  fread(&header, sizeof(png_image_header_t), 1, stdin);
  if (feof(stdin)) {
    fprintf(stderr, "Error: PNG image header too short.\n");
    return 1;
  }

  /* Convert from network byte order. */
  header.width = ntohl(header.width);
  header.height = ntohl(header.height);

  printf("Width             : %lu\n", header.width);
  printf("Height            : %lu\n", header.height);
  printf("Bit depth         : %d\n", header.bit_depth);
  switch (header.colour_type) {
  case 0:
    p = "Greyscale";
    break;
  case 2:
    p = "Truecolour";
    break;
  case 3:
    p = "Indexed-colour";
    break;
  case 4:
    p = "Greyscale with alpha";
    break;
  case 6:
    p = "Truecolour with alpha";
    break;
  default:
    p = "Unknown";
    break;
  }
  printf("Colour type       : %d (%s)\n", header.colour_type, p);
  printf("Compression method: %d (%s)\n", header.compression_method, 
    (header.compression_method == 0) ? "Deflate" : "Unknown");
  printf("Filter method     : %d (%s)\n", header.filter_method,
    (header.filter_method == 0) ? "Adaptive" : "Unknown");
  switch (header.interlace_method) {
  case 0:
    p = "No interlace";
    break;
  case 1:
    p = "Adam7 interlace";
    break;
  default:
    p = "Unknown";
    break;
  }
  printf("Interlace method  : %d (%s)\n", header.interlace_method, p);

  return 0;
}
          


Topic: Scripts and Code, by Kjetil @ 09/03-2008, Article Link