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 }