§ Как устроен формат

Этот формат переводится как Portable Pixel Map и настолько прост, что даже BMP кажется сложным.
Первые строки в файле PPM пишутся так:
P6
# Здесь может быть комментарий
640 400
255
  • Здесь P6 означает "магическое число формата". После P6 ставится символ \n переноса строки. Тут может быть не только P6, но и P3. Этот формат можно посмотреть тут.
  • Комментариев может быть сколько угодно, они начинаются с #
  • Сразу после комментария идет размер по ширине и высоте
  • 255 означает что далее идет RGB последовательность
После числа 255 идет также \n и сразу же после этого записан цвет в формате RGB, то есть, первым байтом идет компонента R, потом G, и потом B. И так повторяется для каждого пикселя.

§ Код для записи файла

В data находятся числа в формате int, причем blue-компонента находится в младшем байте. Альфа-канал не записывается.
int write_ppm(const char* filename, int width, int height, int data[]) {

    FILE* fp = fopen(filename, "wb");

    char buf[256];

    if (fp) {

        sprintf(buf, "P6\n# G++ HELLO WORLD\n%d %d\n255\n", width, height);
        fputs(buf, fp);

        for (int y = 0; y < height; y++)
        for (int x = 0; x < width;  x++) {

            int cl = data[y*width+x];

            buf[0] = cl>>16;
            buf[1] = cl>>8;
            buf[2] = cl;

            fwrite(buf, 1, 3, fp);
        }

        fclose(fp);
    }
}
Тестовый код для записи в файл
int main(int argc, char* argv[]) {

    int data[640*480];

    for (int y = 0; y < 480; y++)
    for (int x = 0; x < 640; x++) {
        data[640*y + x] = x*y;
    }

    write_ppm("file.ppm", 640, 480, data);

    return 0;
}

§ Код для чтения из PPM

Чтение из файла, создание новой области памяти и заполнить значениями RGB.
unsigned char* loadppm(const char* fn) {

    char buf[512];
    unsigned char* pixels;

    FILE* fp = fopen(name, "rb");
    if (fp) {

        fgets(buf, 512, fp);
        do { fgets(buf, 512, fp); } while (buf[0] == '#');

        // Попробовать распарсить данные W x H
        sscanf(buf, "%d %d", &width, &height);

        // Другой формат. Дочитать
        if (width && !height) { fgets(buf, 512, fp); sscanf(buf, "%d", &height); }

        // Прочесть число 255
        fgets(buf, 512, fp);

        // Выделить память
        pixels = (unsigned char*) malloc(3 * width * height);
        fread(pixels, 3, width * height, fp);
        fclose(fp);
    }

    return pixels;
}