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

Этот формат переводится как 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-компонента находится в младшем байте. Альфа-канал не записывается.
1int write_ppm(const char* filename, int width, int height, int data[]) {
2
3    FILE* fp = fopen(filename, "wb");
4
5    char buf[256];
6
7    if (fp) {
8
9        sprintf(buf, "P6\n# G++ HELLO WORLD\n%d %d\n255\n", width, height);
10        fputs(buf, fp);
11
12        for (int y = 0; y < height; y++)
13        for (int x = 0; x < width;  x++) {
14
15            int cl = data[y*width+x];
16
17            buf[0] = cl>>16;
18            buf[1] = cl>>8;
19            buf[2] = cl;
20
21            fwrite(buf, 1, 3, fp);
22        }
23
24        fclose(fp);
25    }
26}
Тестовый код для записи в файл
1int main(int argc, char* argv[]) {
2
3    int data[640*480];
4
5    for (int y = 0; y < 480; y++)
6    for (int x = 0; x < 640; x++) {
7        data[640*y + x] = x*y;
8    }
9
10    write_ppm("file.ppm", 640, 480, data);
11
12    return 0;
13}

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

Чтение из файла, создание новой области памяти с Uint значениями RGB.
1unsigned int* load_ppm(const char* fn) {
2
3    char s[256];
4    unsigned char m[3];
5    int w = 0, h = 0;
6
7    FILE* fp = fopen(fn, "rb");
8    if (fp) {
9
10        fgets(s, 256, fp);
11        if (s[0] == 'P' && s[1] == '6') {
12
13            // Игнорировать комментарии
14            do { fgets(s, 256, fp); } while (s[0] == '#');
15            sscanf(s, "%d %d", &w, &h);
16            fgets(s, 256, fp); // Должен быть 255
17
18            // Загрузка текстуры в память
19            unsigned int* tmp = (unsigned int*)malloc(w * h * sizeof(unsigned int));
20
21            for (int i = 0; i < h; i++)
22            for (int j = 0; j < w; j++) {
23
24                fread(m, 1, 3, fp);
25                tmp[i*w + j] = m[0] + m[1]*256 + m[2]*65536;
26            }
27
28            fclose(fp);
29            return tmp;
30
31        } else {
32
33            fclose(fp);
34            printf("Error with signature %s\n", fn); exit(2);
35        }
36
37    } else {
38        printf("Texture %s not found\n", fn);
39        exit(1);
40    }
41
42    return NULL;
43}