annotate png.c @ 1546:1a09422b87a5

Get Windows build working again. MegaWiFi code probably needs more work before it will actually work on Windows, but at least it doesn't break the build now
author Michael Pavone <pavone@retrodev.com>
date Mon, 26 Mar 2018 21:25:40 -0700
parents b505083dcd87
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 }