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