annotate png.c @ 1532:b505083dcd87

Added png screenshot support
author Michael Pavone <pavone@retrodev.com>
date Sat, 24 Mar 2018 19:40:51 -0700
parents
children 0ec89dadb36d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1532
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
1 #include <stdint.h>
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
2 #include <stdlib.h>
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
3 #include <stdio.h>
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
4 #include "zlib/zlib.h"
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
5
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
6 static const char png_magic[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
7 static const char ihdr[] = {'I', 'H', 'D', 'R'};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
8 static const char plte[] = {'P', 'L', 'T', 'E'};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
9 static const char idat[] = {'I', 'D', 'A', 'T'};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
10 static const char iend[] = {'I', 'E', 'N', 'D'};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
11
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
12 enum {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
13 COLOR_TRUE = 2,
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
14 COLOR_INDEXED
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
15 };
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
16
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
17 static void write_chunk(FILE *f, const char*id, uint8_t *buffer, uint32_t size)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
18 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
19 uint8_t tmp[4] = {size >> 24, size >> 16, size >> 8, size};
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
20 uint8_t warn = 0;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
21 warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f));
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
22 warn = warn || (4 != fwrite(id, 1, 4, f));
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
23 if (size) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
24 warn = warn || (size != fwrite(buffer, 1, size, f));
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
25 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
26
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
27 uint32_t crc = crc32(0, NULL, 0);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
28 crc = crc32(crc, id, 4);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
29 if (size) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
30 crc = crc32(crc, buffer, size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
31 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
32 tmp[0] = crc >> 24;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
33 tmp[1] = crc >> 16;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
34 tmp[2] = crc >> 8;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
35 tmp[3] = crc;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
36 warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f));
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
37 if (warn) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
38 fprintf(stderr, "Failure during write of %c%c%c%c chunk\n", id[0], id[1], id[2], id[3]);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
39 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
40 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
41
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
42 static void write_header(FILE *f, uint32_t width, uint32_t height, uint8_t color_type)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
43 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
44 uint8_t chunk[13] = {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
45 width >> 24, width >> 16, width >> 8, width,
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
46 height >> 24, height >> 16, height >> 8, height,
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
47 8, color_type, 0, 0, 0
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
48 };
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
49 if (sizeof(png_magic) != fwrite(png_magic, 1, sizeof(png_magic), f)) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
50 fputs("Error writing PNG magic\n", stderr);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
51 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
52 write_chunk(f, ihdr, chunk, sizeof(chunk));
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
53 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
54
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
55 void save_png24(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
56 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
57 uint32_t idat_size = (1 + width*3) * height;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
58 uint8_t *idat_buffer = malloc(idat_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
59 uint32_t *pixel = buffer;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
60 uint8_t *cur = idat_buffer;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
61 for (uint32_t y = 0; y < height; y++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
62 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
63 //save filter type
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
64 *(cur++) = 0;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
65 uint32_t *start = pixel;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
66 for (uint32_t x = 0; x < width; x++, pixel++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
67 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
68 uint32_t value = *pixel;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
69 *(cur++) = value >> 16;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
70 *(cur++) = value >> 8;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
71 *(cur++) = value;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
72 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
73 pixel = start + pitch / sizeof(uint32_t);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
74 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
75 write_header(f, width, height, COLOR_TRUE);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
76 uLongf compress_buffer_size = idat_size + 5 * (idat_size/16383 + 1) + 3;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
77 uint8_t *compressed = malloc(compress_buffer_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
78 compress(compressed, &compress_buffer_size, idat_buffer, idat_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
79 free(idat_buffer);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
80 write_chunk(f, idat, compressed, compress_buffer_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
81 write_chunk(f, iend, NULL, 0);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
82 free(compressed);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
83 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
84
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
85 void save_png(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
86 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
87 uint32_t palette[256];
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
88 uint8_t pal_buffer[256*3];
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
89 uint32_t num_pal = 0;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
90 uint32_t index_size = (1 + width) * height;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
91 uint8_t *index_buffer = malloc(index_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
92 uint8_t *cur = index_buffer;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
93 uint32_t *pixel = buffer;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
94 for (uint32_t y = 0; y < height; y++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
95 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
96 //save filter type
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
97 *(cur++) = 0;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
98 uint32_t *start = pixel;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
99 for (uint32_t x = 0; x < width; x++, pixel++, cur++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
100 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
101 uint32_t value = (*pixel) & 0xFFFFFF;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
102 uint32_t i;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
103 for (i = 0; i < num_pal; i++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
104 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
105 if (palette[i] == value) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
106 break;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
107 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
108 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
109 if (i == num_pal) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
110 if (num_pal == 256) {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
111 free(index_buffer);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
112 save_png24(f, buffer, width, height, pitch);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
113 return;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
114 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
115 palette[i] = value;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
116 num_pal++;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
117 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
118 *cur = i;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
119 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
120 pixel = start + pitch / sizeof(uint32_t);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
121 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
122 write_header(f, width, height, COLOR_INDEXED);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
123 cur = pal_buffer;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
124 for (uint32_t i = 0; i < num_pal; i++)
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
125 {
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
126 *(cur++) = palette[i] >> 16;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
127 *(cur++) = palette[i] >> 8;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
128 *(cur++) = palette[i];
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
129 }
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
130 write_chunk(f, plte, pal_buffer, num_pal * 3);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
131 uLongf compress_buffer_size = index_size + 5 * (index_size/16383 + 1) + 3;
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
132 uint8_t *compressed = malloc(compress_buffer_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
133 compress(compressed, &compress_buffer_size, index_buffer, index_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
134 free(index_buffer);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
135 write_chunk(f, idat, compressed, compress_buffer_size);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
136 write_chunk(f, iend, NULL, 0);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
137 free(compressed);
b505083dcd87 Added png screenshot support
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
138 }