Skip to main content TerryFunggg Blog

PPM Image Parse

PPM image parser

References: https://netpbm.sourceforge.net/doc/ppm.html

Example format

code snippet start

P3
# feep.ppm
4 4
15
 0  0  0    0  0  0    0  0  0   15  0 15
 0  0  0    0 15  7    0  0  0    0  0  0
 0  0  0    0  0  0    0 15  7    0  0  0
15  0 15    0  0  0    0  0  0    0  0  0

code snippet end

P3 is identifier it can be P3 or P6. Just like version Number

4 4 is the image width and height

15 is the maximum color depth for each RGB. For morden PC, it should be 255 now.

Other below are the RGB value split by space

code snippet start

 0  0  0    0  0  0    0  0  0   15  0 15

code snippet end

For example there have a four pixel, first three all the zero means all the black. Last is 15 0 15 -> Red is 15, Green is 0 and Blue is 15.

We can use GIMP to export the jpg and png normal image into ppm format.

Use xxd to check the binary:

code snippet start

> ~/ $ xxd bafff.ppm | head
00000000: 5036 0a23 2043 7265 6174 6564 2062 7920  P6.# Created by
00000010: 4749 4d50 2076 6572 7369 6f6e 2033 2e30  GIMP version 3.0
00000020: 2e36 2050 4e4d 2070 6c75 672d 696e 0a32  .6 PNM plug-in.2
00000030: 3132 2032 3337 0a32 3535 0a26 2626 2626  12 237.255.&&&&&
00000040: 2626 2626 2626 2626 2626 2626 2626 2626  &&&&&&&&&&&&&&&&
00000050: 2626 2627 2727 2727 2727 2727 2727 2727  &&&'''''''''''''
00000060: 2727 2727 2727 2727 2727 2728 2828 2929  '''''''''''((())
00000070: 2929 2929 2929 292a 2a2a 2a2a 2a2b 2b2b  )))))))******+++
00000080: 2b2b 2b28 2828 2929 2929 2929 2929 292a  +++((()))))))))*
00000090: 2a2a 2a2a 2a2b 2b2b 2b2b 2b2b 2b2b 2b2b  *****+++++++++++

code snippet end

Simple ppm parser using SDL:

c code snippet start

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
#include <string.h>

int main(void) {
  FILE *in = stdin;
  char *pt = malloc(1024);
  char identifier[1024];

  int width = 0;
  int height = 0;
  int depth = 0;

  fgets(pt, 1024, in);
  sscanf(pt, "%s\n", identifier);
  // Lazy format check
  if (!(strcmp(identifier, "P3") == 0 || strcmp(identifier, "P6") == 0)) {
    printf("The ppm image format is not valid.\n");
	return 0;
  }

  printf("Magic Number: %s\n", identifier);  
  
  // Skip the comment line
  fgets(pt, 1024, in);
  // Get the height and width
  fgets(pt, 1024, in);
  sscanf(pt, "%d %d\n", &width, &height);  

  fgets(pt, 1024, in);
  sscanf(pt, "%d\n", &depth);  
  free(pt);

  // INFO
  printf("Color depth: %d\n", depth);
  printf("Image Heigh: %d\n", height);
  printf("Image Width: %d\n", width);  

  
  SDL_Window *window = SDL_CreateWindow("ppm Image viewer", SDL_WINDOWPOS_CENTERED,
                                         SDL_WINDOWPOS_CENTERED, width, height, 0);

  SDL_Surface *surface = SDL_GetWindowSurface(window);
  
  SDL_FillRect(surface, NULL, 0xFF0000FF);

  Uint32 color = 0;

  SDL_Rect pixel = (SDL_Rect) { 0, 0, 1, 1};

  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      Uint8 r, g, b;	  
	  r = (char) getchar();
	  g = (char) getchar();
      b = (char) getchar();
	  color = SDL_MapRGB(surface->format, r, g, b);	  
	  pixel.x = x;
	  pixel.y = y;
	  SDL_FillRect(surface, &pixel, color);
    }
  }


  SDL_UpdateWindowSurface(window);

  int is_running = 1;

  while (is_running) {
    SDL_Event event;
    SDL_PollEvent(&event);
	switch (event.type) {
        case SDL_QUIT:
          is_running = 0;
          break;
        case SDL_KEYDOWN:
          if (event.key.keysym.sym == SDLK_ESCAPE) {
            is_running = 0;
            SDL_DestroyWindow(window);
			SDL_Quit();
          }
		  break;
	}
  }
  

  return 0;
}

c code snippet end