git ssb

1+

cel / pngspark



Commit 0b29f5c16c806103ae9326149404b382ab3b7cfd

Get something working using LuPng

Charles Lehner committed on 2/10/2015, 12:30:38 AM
Parent: 7d1b2f8dab921f01fb353d94728ca41743b71b63

Files changed

Makefilechanged
main.cchanged
pngspark.cchanged
pngspark.hchanged
lupng.cadded
lupng.hadded
MakefileView
@@ -3,13 +3,18 @@
33 BIN = pngspark
44 PREFIX ?= /usr/local
55
66 CFLAGS = -Wall -Wextra -Werror -O2 -std=c99 -pedantic
7 +LDFLAGS = -lz
78
89 all: $(BIN)
910
10-pngspark: pngspark.o main.o
11 +lupng.o: lupng.c
12 + $(CC) -c -o $@ $^ -Werror -std=c99 -DLUPNG_USE_ZLIB
1113
14 +pngspark: pngspark.o main.o lupng.o
15 + $(CC) -o $@ $^ $(LDFLAGS)
16 +
1217 install: $(BIN)
1318 cp -f $(BIN) $(PREFIX)/bin/$(BIN)
1419
1520 uninstall:
main.cView
@@ -15,41 +15,37 @@
1515 };
1616
1717 int main(int argc, char *argv[])
1818 {
19- if (isatty(fileno(stdin)) && (argc < 2 ||
20- !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
21- return 1;
22- }
23-
2419 struct pngspark ps;
2520 const char *color = "#000000";
2621 const char *filename = "pngspark.png";
2722 int height = 10;
2823
2924 for (int i = 1; i < argc; i++) {
30- char c = argv[i][1];
31- if(argv[i][0] != '-' || argv[i][2])
32- c = -1;
33- switch(c) {
25 + if (argv[i][0] != '-') continue;
26 + if (argv[i][1] == '-') {
27 + if (strcmp("help", argv[i]+2)) {
28 + errx(1, "Usage: %s [--help] [-h height] "
29 + "[-o output.png] [-c color]", argv[0]);
30 + }
31 + } else if (!argv[i][2]) switch (argv[i][1]) {
3432 case 'c':
3533 if (++i < argc) color = argv[i];
3634 break;
37- case 'f':
35 + case 'o':
3836 if (++i < argc) filename = argv[i];
3937 break;
4038 case 'h':
4139 if (++i < argc) height = atoi(argv[i]);
4240 break;
43- default:
44- fprintf(stderr, "Usage: %s [-h|--help] VALUE,...\n", argv[0]);
4541 }
4642 }
4743
48- int fd = open(filename, O_CREAT | O_RDWR, 0644);
49- if (!fd) err(1, "unable to open file %s", filename);
44 + FILE *file = fopen(filename, "w");
45 + if (!file) err(1, "unable to open file %s", filename);
5046
51- if (pngspark_init(&ps, fd, height, color) < 0)
47 + if (pngspark_init(&ps, height, color) < 0)
5248 return 1;
5349
5450 char c;
5551 char buffer[32];
@@ -67,9 +63,15 @@
6763 if (pngspark_append(&ps, value) < 0)
6864 return 1;
6965 } while (c != EOF);
7066
67 + if (pngspark_write(&ps, file) < 0)
68 + return 1;
69 +
7170 if (pngspark_end(&ps) < 0)
7271 return 1;
7372
73 + if (fclose(file) < 0)
74 + err(1, "close %s", filename);
75 +
7476 return 0;
7577 }
pngspark.cView
@@ -1,23 +1,87 @@
1 +#include <stdlib.h>
2 +#include <string.h>
3 +#include <stdio.h>
4 +#include <unistd.h>
5 +
6 +#include "lupng.h"
17 #include "pngspark.h"
28
3-int pngspark_init(struct pngspark *ps, int fd, int height, const char *color)
9 +static const size_t initial_size = 8;
10 +
11 +uint8_t parse_color(const char *color)
412 {
5- ps->fd = fd;
13 + return !strcmp("black", color) ? 0x00 : 0x99;
14 +}
15 +
16 +int pngspark_init(struct pngspark *ps, size_t height, const char *color)
17 +{
18 + ps->size = initial_size;
19 + ps->num_values = 0;
20 + ps->values = malloc(initial_size * sizeof(double));
21 + if (!ps->values) return 1;
22 + ps->color = parse_color(color);
623 ps->height = height;
7- (void)color;
24 + ps->max_value = 0;
825 return 0;
926 }
1027
1128 int pngspark_append(struct pngspark *ps, double value)
1229 {
13- (void)ps;
14- (void)value;
30 + size_t i = ps->num_values++;
31 + if (i >= ps->size) {
32 + ps->values = realloc(ps->values, sizeof(double) * (ps->size <<= 1));
33 + if (!ps->values) return 1;
34 + }
35 + ps->values[i] = value;
36 + if (value > ps->max_value)
37 + ps->max_value = value;
1538 return 0;
1639 }
1740
41 +int pngspark_draw(struct pngspark *ps, uint8_t *data, size_t width,
42 + size_t height)
43 +{
44 + double *values = ps->values;
45 + uint8_t color = ps->color;
46 + for (size_t x = 0; x < width; x++) {
47 + size_t value = values[x] * height;
48 + data[x] = value;
49 + for (size_t y = 0; y < height; y++)
50 + data[x * width + y] = 0x9f;
51 + /*
52 + printf("write value: %zu, i: %zu\n", value, 1 * width + x);
53 + for (size_t y = value+1; y < height; y++)
54 + data[y * width + x] = color;
55 + */
56 + (void)value;
57 + (void)color;
58 + (void)data;
59 + }
60 + return 0;
61 +}
62 +
63 +static size_t write_fd(const void *ptr, size_t size, size_t count,
64 + void *userPtr)
65 +{
66 + return fwrite(ptr, size, count, (FILE *)userPtr);
67 +}
68 +
69 +int pngspark_write(struct pngspark *ps, FILE *file)
70 +{
71 + LuImage *img = luImageCreate(ps->num_values, ps->max_value+1, 1, 8);
72 + if (!img) return 1;
73 + printf("size: %zu\n", img->dataSize);
74 +
75 + int ret = pngspark_draw(ps, img->data, ps->num_values, ps->max_value);
76 + if (!ret)
77 + ret = luPngWrite(write_fd, file, img);
78 + luImageRelease(img);
79 + return ret;
80 +}
81 +
1882 int pngspark_end(struct pngspark *ps)
1983 {
20- (void)ps;
84 + free(ps->values);
2185 return 0;
2286 }
2387
pngspark.hView
@@ -1,13 +1,20 @@
11 #ifndef __PNGSPARK_H
22 #define __PNGSPARK_H
33
4 +#include <stdint.h>
5 +
46 struct pngspark {
5- int fd;
6- int height;
7 + size_t num_values;
8 + size_t size;
9 + size_t max_value;
10 + size_t height;
11 + uint8_t color;
12 + double *values;
713 };
814
9-int pngspark_init(struct pngspark *, int, int, const char *);
15 +int pngspark_init(struct pngspark *, size_t, const char *);
1016 int pngspark_append(struct pngspark *, double);
17 +int pngspark_write(struct pngspark *, FILE *);
1118 int pngspark_end(struct pngspark *);
1219
1320 #endif /* __PNGSPARK_H */
lupng.cView
@@ -1,0 +1,1077 @@
1 +/*
2 + * The MIT License (MIT)
3 + *
4 + * Copyright (c) 2014 Jan Solanti
5 + *
6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
7 + * of this software and associated documentation files (the "Software"), to deal
8 + * in the Software without restriction, including without limitation the rights
9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 + * copies of the Software, and to permit persons to whom the Software is
11 + * furnished to do so, subject to the following conditions:
12 + *
13 + * The above copyright notice and this permission notice shall be included in all
14 + * copies or substantial portions of the Software.
15 + *
16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 + * SOFTWARE.
23 + */
24 +
25 +#include <stdio.h>
26 +#include <stdlib.h>
27 +#include <string.h>
28 +
29 +#ifndef LUPNG_USE_ZLIB
30 +#include <miniz.h>
31 +#else
32 +#include <zlib.h>
33 +#endif
34 +
35 +#include "lupng.h"
36 +
37 +#define PNG_NONE 0
38 +#define PNG_IHDR 0x01
39 +#define PNG_PLTE 0x02
40 +#define PNG_IDAT 0x04
41 +#define PNG_IEND 0x08
42 +
43 +#define PNG_GRAYSCALE 0
44 +#define PNG_TRUECOLOR 2
45 +/* 24bpp RGB palette */
46 +#define PNG_PALETTED 3
47 +#define PNG_GRAYSCALE_ALPHA 4
48 +#define PNG_TRUECOLOR_ALPHA 6
49 +
50 +#define PNG_FILTER_NONE 0
51 +#define PNG_FILTER_SUB 1
52 +#define PNG_FILTER_UP 2
53 +#define PNG_FILTER_AVERAGE 3
54 +#define PNG_FILTER_PAETH 4
55 +
56 +#define PNG_SIG_SIZE 8
57 +
58 +#define PNG_DONE 1
59 +#define PNG_OK 0
60 +#define PNG_ERROR -1
61 +
62 +#define BUF_SIZE 8192
63 +#define MAX(x, y) (x > y ? x : y)
64 +
65 +
66 +
67 +/********************************************************
68 + * CRC computation as per PNG spec
69 + ********************************************************/
70 +
71 +/* Precomputed table of CRCs of all 8-bit messages
72 + using the polynomial from the PNG spec, 0xEDB88320L. */
73 +static const uint32_t crcTable[] =
74 +{
75 + 0x0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x76DC419, 0x706AF48F,
76 + 0xE963A535, 0x9E6495A3, 0xEDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
77 + 0x9B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
78 + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
79 + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
80 + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
81 + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
82 + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
83 + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
84 + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
85 + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x1DB7106,
86 + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x6B6B51F, 0x9FBFE4A5, 0xE8B8D433,
87 + 0x7807C9A2, 0xF00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x86D3D2D,
88 + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
89 + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
90 + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
91 + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
92 + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
93 + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
94 + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
95 + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
96 + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x3B6E20C, 0x74B1D29A,
97 + 0xEAD54739, 0x9DD277AF, 0x4DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
98 + 0xD6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0xA00AE27, 0x7D079EB1,
99 + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
100 + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
101 + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
102 + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
103 + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
104 + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
105 + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
106 + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
107 + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x26D930A, 0x9C0906A9, 0xEB0E363F,
108 + 0x72076785, 0x5005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0xCB61B38,
109 + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21, 0x86D3D2D4, 0xF1D4E242,
110 + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
111 + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
112 + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
113 + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
114 + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
115 + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
116 + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
117 + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
118 +};
119 +
120 +/* Update a running CRC with the bytes buf[0..len-1]--the CRC
121 + should be initialized to all 1's, and the transmitted value
122 + is the 1's complement of the final running CRC (see the
123 + crc() routine below)). */
124 +static uint32_t updateCrc(uint32_t crc, unsigned char *buf,
125 + int len)
126 +{
127 + unsigned long c = crc;
128 + int n;
129 +
130 + for (n = 0; n < len; n++)
131 + c = crcTable[(c ^ buf[n]) & 0xFF] ^ (c >> 8);
132 +
133 + return c;
134 +}
135 +
136 +/* Return the CRC of the bytes buf[0..len-1]. */
137 +static uint32_t crc(unsigned char *buf, int len)
138 +{
139 + return updateCrc(0xFFFFFFFFL, buf, len) ^ 0xFFFFFFFFL;
140 +}
141 +
142 +
143 +
144 +/********************************************************
145 + * Helper structs
146 + ********************************************************/
147 +
148 +typedef struct
149 +{
150 + uint32_t length;
151 + uint8_t *type;
152 + uint8_t *data;
153 + uint32_t crc;
154 +} PngChunk;
155 +
156 +typedef struct {
157 + void *userPtr;
158 + PngReadProc readProc;
159 + PngWriteProc writeProc;
160 + int8_t chunksFound;
161 +
162 + /* IHDR info */
163 + uint32_t width;
164 + uint32_t height;
165 + uint8_t depth;
166 + uint8_t colorType;
167 + uint8_t channels;
168 + uint8_t compression;
169 + uint8_t filter;
170 + uint8_t interlace;
171 +
172 + /* PLTE info */
173 + uint32_t paletteItems;
174 + uint8_t *palette;
175 +
176 + /* fields used for (de)compression & (de-)filtering */
177 + z_stream stream;
178 + size_t scanlineBytes;
179 + int32_t currentCol;
180 + int32_t currentRow;
181 + uint32_t currentElem;
182 + size_t currentByte;
183 + int bytesPerPixel;
184 + uint8_t *currentScanline;
185 + uint8_t *previousScanline;
186 + uint8_t currentFilter;
187 + uint8_t interlacePass;
188 + size_t compressedBytes;
189 +
190 + /* used for constructing 16 bit deep pixels */
191 + int tmpCount;
192 + uint8_t tmpBytes[2];
193 +
194 + /* the output image */
195 + LuImage *img;
196 +} PngInfoStruct;
197 +
198 +/* PNG header: */
199 +static const uint8_t PNG_SIG[] =
200 +/* P N G \r \n SUB \n */
201 +{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
202 +
203 +static const int startingRow[] = { 0, 0, 0, 4, 0, 2, 0, 1 };
204 +static const int startingCol[] = { 0, 0, 4, 0, 2, 0, 1, 0 };
205 +static const int rowIncrement[] = { 1, 8, 8, 8, 4, 4, 2, 2 };
206 +static const int colIncrement[] = { 1, 8, 8, 4, 4, 2, 2, 1 };
207 +
208 +
209 +
210 +/********************************************************
211 + * Helper functions
212 + ********************************************************/
213 +
214 +static inline void releaseChunk(PngChunk *chunk)
215 +{
216 + /* Only release chunk->type since chunk->data points to the same memory. */
217 + free((void *)chunk->type);
218 + free((void *)chunk);
219 +}
220 +
221 +static inline uint32_t swap32(uint32_t n)
222 +{
223 + union {
224 + unsigned char np[4];
225 + uint32_t i;
226 + } u;
227 + u.i = n;
228 +
229 + return ((uint32_t)u.np[0] << 24) |
230 + ((uint32_t)u.np[1] << 16) |
231 + ((uint32_t)u.np[2] << 8) |
232 + (uint32_t)u.np[3];
233 +}
234 +
235 +static inline uint16_t swap16(uint16_t n)
236 +{
237 + union {
238 + unsigned char np[2];
239 + uint16_t i;
240 + } u;
241 + u.i = n;
242 +
243 + return ((uint16_t)u.np[0] << 8) | (uint16_t)u.np[1];
244 +}
245 +
246 +static int bytesEqual(const uint8_t *a, const uint8_t *b, size_t count)
247 +{
248 + size_t i;
249 + for (i = 0; i < count; ++i)
250 + {
251 + if (*(a+i) != *(b+i))
252 + return 0;
253 + }
254 +
255 + return 1;
256 +}
257 +
258 +
259 +
260 +/********************************************************
261 + * Png filter functions
262 + ********************************************************/
263 +static inline int absi(int val)
264 +{
265 + return val > 0 ? val : -val;
266 +}
267 +
268 +static inline uint8_t raw(PngInfoStruct *info, int32_t col)
269 +{
270 + if (col < 0)
271 + return 0;
272 + return info->currentScanline[col];
273 +}
274 +
275 +static inline uint8_t prior(PngInfoStruct *info, int32_t col)
276 +{
277 + if (info->currentRow <= startingRow[info->interlacePass] || col < 0)
278 + return 0;
279 + return info->previousScanline[col];
280 +}
281 +
282 +static inline uint8_t paethPredictor(uint8_t a, uint8_t b, uint8_t c)
283 +{
284 + unsigned int A = a, B = b, C = c;
285 + int p = (int)A + (int)B - (int)C;
286 + int pa = absi(p - (int)A);
287 + int pb = absi(p - (int)B);
288 + int pc = absi(p - (int)C);
289 +
290 + if (pa <= pb && pa <= pc)
291 + return a;
292 + if (pb <= pc)
293 + return b;
294 + return c;
295 +}
296 +
297 +static inline uint8_t deSub(PngInfoStruct *info, uint8_t filtered)
298 +{
299 + return filtered + raw(info, info->currentByte-info->bytesPerPixel);
300 +}
301 +
302 +static inline uint8_t deUp(PngInfoStruct *info, uint8_t filtered)
303 +{
304 + return filtered + prior(info, info->currentByte);
305 +}
306 +
307 +static inline uint8_t deAverage(PngInfoStruct *info, uint8_t filtered)
308 +{
309 + uint16_t avg = (uint16_t)(raw(info, info->currentByte-info->bytesPerPixel)
310 + + prior(info, info->currentByte));
311 + avg >>= 1;
312 + return filtered + avg;
313 +}
314 +
315 +static inline uint8_t dePaeth(PngInfoStruct *info, uint8_t filtered)
316 +{
317 + return filtered + paethPredictor(
318 + raw(info, info->currentByte-info->bytesPerPixel),
319 + prior(info, info->currentByte),
320 + prior(info, info->currentByte-info->bytesPerPixel));
321 +}
322 +
323 +static inline uint8_t none(PngInfoStruct *info)
324 +{
325 + return raw(info, info->currentByte);
326 +}
327 +
328 +static inline uint8_t sub(PngInfoStruct *info)
329 +{
330 + return raw(info, info->currentByte) - raw(info, info->currentByte-info->bytesPerPixel);
331 +}
332 +
333 +static inline uint8_t up(PngInfoStruct *info)
334 +{
335 + return raw(info, info->currentByte) - prior(info, info->currentByte);
336 +}
337 +
338 +static inline uint8_t average(PngInfoStruct *info)
339 +{
340 + uint16_t avg = (uint16_t)(raw(info, info->currentByte-info->bytesPerPixel)
341 + + prior(info, info->currentByte));
342 + avg >>= 1;
343 + return raw(info, info->currentByte) - avg;
344 +}
345 +
346 +static inline uint8_t paeth(PngInfoStruct *info)
347 +{
348 + return raw(info, info->currentByte) - paethPredictor(
349 + raw(info, info->currentByte-info->bytesPerPixel),
350 + prior(info, info->currentByte),
351 + prior(info, info->currentByte-info->bytesPerPixel));
352 +}
353 +
354 +
355 +
356 +/********************************************************
357 + * Actual implementation
358 + ********************************************************/
359 +static inline int parseIhdr(PngInfoStruct *info, PngChunk *chunk)
360 +{
361 + if (info->chunksFound)
362 + {
363 + printf("PNG: malformed PNG file!\n");
364 + return PNG_ERROR;
365 + }
366 +
367 + info->chunksFound |= PNG_IHDR;
368 + info->width = swap32(*(uint32_t *)chunk->data);
369 + info->height = swap32(*((uint32_t *)chunk->data + 1));
370 + info->depth = *(chunk->data + 8);
371 + info->colorType = *(chunk->data + 9);
372 + info->compression = *(chunk->data + 10);
373 + info->filter = *(chunk->data + 11);
374 + info->interlace = *(chunk->data + 12);
375 +
376 + switch (info->colorType)
377 + {
378 + case PNG_GRAYSCALE:
379 + info->channels = 1;
380 + break;
381 + case PNG_TRUECOLOR:
382 + info->channels = 3;
383 + break;
384 + case PNG_PALETTED:
385 + info->channels = 3;
386 + break;
387 + case PNG_GRAYSCALE_ALPHA:
388 + info->channels = 2;
389 + break;
390 + case PNG_TRUECOLOR_ALPHA:
391 + info->channels = 4;
392 + break;
393 + default:
394 + printf("PNG: illegal color type: %i\n",
395 + (unsigned int)info->colorType);
396 + return PNG_ERROR;
397 + break;
398 + }
399 +
400 + if ((info->colorType != PNG_GRAYSCALE && info->colorType != PNG_PALETTED &&
401 + info->depth < 8) ||
402 + (info->colorType == PNG_PALETTED && info->depth == 16) ||
403 + info->depth > 16)
404 + {
405 + printf("PNG: illegal bit depth for color type\n");
406 + return PNG_ERROR;
407 + }
408 +
409 + if (info->compression)
410 + {
411 + printf("PNG: unknown compression method: %i\n",
412 + (unsigned int)info->compression);
413 + return PNG_ERROR;
414 + }
415 +
416 + if (info->filter)
417 + {
418 + printf("PNG: unknown filter scheme: %i\n",
419 + (unsigned int)info->filter);
420 + return PNG_ERROR;
421 + }
422 +
423 + memset(&(info->stream), 0, sizeof(info->stream));
424 + if(inflateInit(&(info->stream)) != Z_OK)
425 + {
426 + printf("PNG: inflateInit failed!\n");
427 + return PNG_ERROR;
428 + }
429 + info->img = luImageCreate(info->width, info->height,
430 + info->channels, info->depth < 16 ? 8 : 16);
431 + info->scanlineBytes = MAX((info->width * info->channels * info->depth) >> 3, 1);
432 + info->currentScanline = (uint8_t *)malloc(info->scanlineBytes);
433 + info->previousScanline = (uint8_t *)malloc(info->scanlineBytes);
434 + info->currentCol = -1;
435 + info->interlacePass = info->interlace ? 1 : 0;
436 + info->bytesPerPixel = MAX((info->channels * info->depth) >> 3, 1);
437 + if (!info->img || !info->currentScanline || !info->previousScanline)
438 + {
439 + printf("PNG: memory allocation failed!\n");
440 + return PNG_ERROR;
441 + }
442 +
443 + return PNG_OK;
444 +}
445 +
446 +static inline int parsePlte(PngInfoStruct *info, PngChunk *chunk)
447 +{
448 + if (info->chunksFound & PNG_IDAT || !(info->chunksFound & PNG_IHDR))
449 + {
450 + printf("PNG: malformed PNG file!\n");
451 + return PNG_ERROR;
452 + }
453 +
454 + info->chunksFound |= PNG_PLTE;
455 +
456 + if (chunk->length % 3 != 0)
457 + {
458 + printf("PNG: invalid palette size!\n");
459 + return PNG_ERROR;
460 + }
461 +
462 + info->paletteItems = chunk->length/3;
463 + info->palette = (uint8_t *)malloc(chunk->length);
464 + if (!info->palette)
465 + {
466 + printf("PNG: memory allocation failed!\n");
467 + return PNG_ERROR;
468 + }
469 + memcpy(info->palette, chunk->data, chunk->length);
470 +
471 + return PNG_OK;
472 +}
473 +
474 +static inline void stretchBits(uint8_t inByte, uint8_t outBytes[8], int depth)
475 +{
476 + int i;
477 + switch (depth) {
478 + case 1:
479 + for (i = 0; i < 8; ++i)
480 + outBytes[i] = (inByte >> (7-i)) & 0x01;
481 + break;
482 +
483 + case 2:
484 + outBytes[0] = (inByte >> 6) & 0x03;
485 + outBytes[1] = (inByte >> 4) & 0x03;
486 + outBytes[2] = (inByte >> 2) & 0x03;
487 + outBytes[3] = inByte & 0x03;
488 + break;
489 +
490 + case 4:
491 + outBytes[0] = (inByte >> 4) & 0x0F;
492 + outBytes[1] = inByte & 0x0F;
493 + break;
494 +
495 + default:
496 + break;
497 + }
498 +}
499 +
500 +/* returns: 1 if at end of scanline, 0 otherwise */
501 +static inline int insertByte(PngInfoStruct *info, uint8_t byte)
502 +{
503 + int advance = 0;
504 + const uint8_t scale[] = {0x00, 0xFF, 0x55, 0x00, 0x11, 0x00, 0x00, 0x00};
505 +
506 + /* for paletted images currentElem will always be 0 */
507 + size_t idx = info->currentRow * info->width * info->channels
508 + + info->currentCol * info->channels
509 + + info->currentElem;
510 +
511 + if (info->colorType != PNG_PALETTED)
512 + {
513 + if (info->depth == 8)
514 + info->img->data[idx] = byte;
515 +
516 + else if (info->depth < 8)
517 + info->img->data[idx] = byte * scale[info->depth];
518 +
519 + else /* depth == 16 */
520 + {
521 + info->tmpBytes[info->tmpCount] = byte;
522 + if (info->tmpCount) /* just inserted 2nd byte */
523 + {
524 + uint16_t val = *(uint16_t *)info->tmpBytes;
525 + val = swap16(val);
526 + info->tmpCount = 0;
527 +
528 + ((uint16_t *)(info->img->data))[idx] = val;
529 + }
530 + else
531 + {
532 + ++info->tmpCount;
533 + return 0;
534 + }
535 + }
536 +
537 + ++info->currentElem;
538 + if (info->currentElem >= info->channels)
539 + {
540 + advance = 1;
541 + info->currentElem = 0;
542 + }
543 + }
544 + else
545 + {
546 + /* The spec limits palette size to 256 entries */
547 + if (byte < info->paletteItems)
548 + {
549 + info->img->data[idx ] = info->palette[3*byte ];
550 + info->img->data[idx+1] = info->palette[3*byte+1];
551 + info->img->data[idx+2] = info->palette[3*byte+2];
552 + }
553 + else
554 + {
555 + printf("PNG: invalid palette index encountered!\n");
556 + }
557 + advance = 1;
558 + }
559 +
560 + if (advance)
561 + {
562 + /* advance to next pixel */
563 + info->currentCol += colIncrement[info->interlacePass];
564 +
565 + if (info->currentCol >= info->width)
566 + {
567 + uint8_t *tmp = info->currentScanline;
568 + info->currentScanline = info->previousScanline;
569 + info->previousScanline = tmp;
570 +
571 + info->currentCol = -1;
572 + info->currentByte = 0;
573 +
574 + info->currentRow += rowIncrement[info->interlacePass];
575 + if (info->currentRow >= info->height && info->interlace)
576 + {
577 + ++info->interlacePass;
578 + while (startingCol[info->interlacePass] >= info->width ||
579 + startingRow[info->interlacePass] >= info->height)
580 + ++info->interlacePass;
581 + info->currentRow = startingRow[info->interlacePass];
582 + }
583 + return 1;
584 + }
585 + }
586 +
587 + return 0;
588 +}
589 +
590 +static inline int parseIdat(PngInfoStruct *info, PngChunk *chunk)
591 +{
592 + unsigned char filtered[BUF_SIZE];
593 + int status = Z_OK;
594 +
595 + if (!(info->chunksFound & PNG_IHDR))
596 + {
597 + printf("PNG: malformed PNG file!\n");
598 + return PNG_ERROR;
599 + }
600 +
601 + if (info->colorType == PNG_PALETTED && !(info->chunksFound & PNG_PLTE))
602 + {
603 + printf("PNG: palette required but missing!\n");
604 + return PNG_ERROR;
605 + }
606 +
607 + info->chunksFound |= PNG_IDAT;
608 + info->stream.next_in = (unsigned char *)chunk->data;
609 + info->stream.avail_in = chunk->length;
610 + do
611 + {
612 + info->stream.next_out = filtered;
613 + info->stream.avail_out = BUF_SIZE;
614 + status = inflate(&(info->stream), Z_NO_FLUSH);
615 + size_t decompressed = BUF_SIZE - info->stream.avail_out;
616 + size_t i;
617 +
618 + if (status != Z_OK &&
619 + status != Z_STREAM_END &&
620 + status != Z_BUF_ERROR &&
621 + status != Z_NEED_DICT)
622 + {
623 + printf("PNG: inflate error!\n");
624 + return PNG_ERROR;
625 + }
626 +
627 + for (i = 0; i < decompressed; ++i)
628 + {
629 + if (info->currentCol < 0)
630 + {
631 + info->currentCol = startingCol[info->interlacePass];
632 + info->currentFilter = filtered[i];
633 + }
634 + else
635 + {
636 + uint8_t rawByte = 0;
637 + uint8_t fullBytes[8] = {0};
638 + switch (info->currentFilter)
639 + {
640 + case PNG_FILTER_NONE:
641 + rawByte = filtered[i];
642 + break;
643 + case PNG_FILTER_SUB:
644 + rawByte = deSub(info, filtered[i]);
645 + break;
646 + case PNG_FILTER_UP:
647 + rawByte = deUp(info, filtered[i]);
648 + break;
649 + case PNG_FILTER_AVERAGE:
650 + rawByte = deAverage(info, filtered[i]);
651 + break;
652 + case PNG_FILTER_PAETH:
653 + rawByte = dePaeth(info, filtered[i]);
654 + break;
655 + default:
656 + break;
657 + }
658 +
659 + info->currentScanline[info->currentByte] = rawByte;
660 + ++info->currentByte;
661 +
662 + if (info->depth < 8)
663 + {
664 + int j;
665 + stretchBits(rawByte, fullBytes, info->depth);
666 + for (j = 0; j < 8/info->depth; ++j)
667 + if(insertByte(info, fullBytes[j]))
668 + break;
669 + }
670 + else
671 + insertByte(info, rawByte);
672 + }
673 + }
674 + } while ((info->stream.avail_in > 0 || info->stream.avail_out == 0));
675 +
676 + return PNG_OK;
677 +}
678 +
679 +static inline PngChunk *readChunk(PngInfoStruct *info)
680 +{
681 + PngChunk *chunk = (PngChunk *)malloc(sizeof(PngChunk));
682 + size_t read = 0;
683 + if (!chunk)
684 + {
685 + printf("PNG: memory allocation failed!\n");
686 + return 0;
687 + }
688 +
689 + info->readProc((void *)&chunk->length, 4, 1, info->userPtr);
690 + chunk->length = swap32(chunk->length);
691 + chunk->type = (uint8_t *)malloc(chunk->length + 4);
692 + chunk->data = chunk->type + 4;
693 +
694 + info->readProc((void *)chunk->type, 1, chunk->length + 4, info->userPtr);
695 + read = info->readProc((void *)&chunk->crc, 4, 1, info->userPtr);
696 + chunk->crc = swap32(chunk->crc);
697 +
698 + if (read != 1)
699 + {
700 + printf("PNG: read error\n");
701 + releaseChunk(chunk);
702 + return 0;
703 + }
704 +
705 + if (crc(chunk->type, chunk->length+4) != chunk->crc)
706 + {
707 + printf("PNG: CRC mismatch in \'%.4s\'\n", (char *)chunk->type);
708 + releaseChunk(chunk);
709 + return 0;
710 + }
711 +
712 + return chunk;
713 +}
714 +
715 +static inline int handleChunk(PngInfoStruct *info, PngChunk *chunk)
716 +{
717 + /* critical chunk */
718 + if (!(chunk->type[0] & 0x20))
719 + {
720 + if (bytesEqual(chunk->type, (const uint8_t *)"IHDR", 4))
721 + return parseIhdr(info, chunk);
722 + if (bytesEqual(chunk->type, (const uint8_t *)"PLTE", 4))
723 + return parsePlte(info, chunk);
724 + if (bytesEqual(chunk->type, (const uint8_t *)"IDAT", 4))
725 + return parseIdat(info, chunk);
726 + if (bytesEqual(chunk->type, (const uint8_t *)"IEND", 4))
727 + {
728 + info->chunksFound |= PNG_IEND;
729 + if (!(info->chunksFound & PNG_IDAT))
730 + {
731 + printf("PNG: no IDAT chunk found\n");
732 + return PNG_ERROR;
733 + }
734 + return PNG_DONE;
735 + }
736 + }
737 + /* ignore ancillary chunks for now */
738 +
739 + return PNG_OK;
740 +}
741 +
742 +LuImage *luPngRead(PngReadProc readProc, void *userPtr)
743 +{
744 + PngInfoStruct info =
745 + {
746 + userPtr,
747 + readProc,
748 + 0,
749 + PNG_NONE
750 + };
751 + uint8_t signature[PNG_SIG_SIZE];
752 + int status = PNG_ERROR;
753 +
754 + info.readProc((void *)signature, 1, PNG_SIG_SIZE, userPtr);
755 + if (bytesEqual(signature, PNG_SIG, PNG_SIG_SIZE))
756 + {
757 + PngChunk *chunk;
758 + while ((chunk = readChunk(&info)))
759 + {
760 + status = handleChunk(&info, chunk);
761 + releaseChunk(chunk);
762 +
763 + if (status != PNG_OK)
764 + break;
765 + }
766 + }
767 + else
768 + printf("PNG: invalid header\n");
769 +
770 + if (info.currentScanline)
771 + free((void *)info.currentScanline);
772 + if (info.previousScanline)
773 + free((void *)info.previousScanline);
774 + if (info.palette)
775 + free((void *)info.palette);
776 + inflateEnd(&info.stream);
777 +
778 + if (status == PNG_DONE)
779 + return info.img;
780 + else
781 + if (info.img)
782 + luImageRelease(info.img);
783 +
784 + return 0;
785 +}
786 +
787 +static inline int writeIhdr(PngInfoStruct *info)
788 +{
789 + static uint8_t buf[17];
790 + static const uint8_t colorType[] = {
791 + PNG_GRAYSCALE,
792 + PNG_GRAYSCALE_ALPHA,
793 + PNG_TRUECOLOR,
794 + PNG_TRUECOLOR_ALPHA
795 + };
796 + size_t written = 0;
797 + PngChunk c;
798 +
799 + if (info->img->channels > 4)
800 + {
801 + printf("PNG: too many channels in image\n");
802 + return PNG_ERROR;
803 + }
804 +
805 + c.length = swap32(13);
806 + c.type = buf; // 4 (type) + 4 + 4 + 5x1
807 + c.data = c.type + 4;
808 +
809 + memcpy((void *)c.type, (void *)"IHDR", 4);
810 + *(uint32_t *)(c.data) = swap32((uint32_t)info->img->width);
811 + *(uint32_t *)(c.data + 4) = swap32((uint32_t)info->img->height);
812 + *(c.data + 8) = info->img->depth;
813 + *(c.data + 9) = colorType[info->img->channels-1];
814 + *(c.data + 10) = 0; // compression method
815 + *(c.data + 11) = 0; // filter method
816 + *(c.data + 12) = 0; // interlace method: none
817 +
818 + c.crc = swap32(crc(c.type, 17));
819 +
820 + written += info->writeProc((void *)&c.length, 4, 1, info->userPtr) * 4;
821 + written += info->writeProc((void *)c.type, 1, 4, info->userPtr);
822 + written += info->writeProc((void *)c.data, 1, 13, info->userPtr);
823 + written += info->writeProc((void *)&c.crc, 4, 1, info->userPtr) * 4;
824 +
825 + if (written != 25)
826 + {
827 + printf("PNG: write error\n");
828 + return PNG_ERROR;
829 + }
830 +
831 + return PNG_OK;
832 +}
833 +
834 +static inline int writeIdat(PngInfoStruct *info, uint8_t *buf, size_t buflen)
835 +{
836 + size_t written = 0;
837 + PngChunk c;
838 +
839 + c.length = swap32(buflen-4);
840 + c.crc = swap32(crc(buf, buflen));
841 +
842 + written += info->writeProc((void *)&c.length, 4, 1, info->userPtr) * 4;
843 + written += info->writeProc((void *)buf, 1, buflen, info->userPtr);
844 + written += info->writeProc((void *)&c.crc, 4, 1, info->userPtr) * 4;
845 +
846 + if (written != buflen+8)
847 + {
848 + printf("PNG: write error\n");
849 + return PNG_ERROR;
850 + }
851 +
852 + return PNG_OK;
853 +}
854 +
855 +static inline void advanceBytep(PngInfoStruct *info, int is16bit)
856 +{
857 + if (is16bit)
858 + {
859 + if (info->currentByte%2)
860 + --info->currentByte;
861 + else
862 + info->currentByte+=3;
863 + }
864 + else
865 + ++info->currentByte;
866 +}
867 +
868 +static inline size_t filterScanline(PngInfoStruct *info,
869 + uint8_t(*f)(PngInfoStruct *info),
870 + uint8_t filter,
871 + uint8_t *filterCandidate,
872 + int is16bit)
873 +{
874 + size_t curSum = 0;
875 + filterCandidate[0] = filter;
876 + size_t fc;
877 + for (info->currentByte = is16bit ? 1 : 0, fc = 1;
878 + info->currentByte < info->scanlineBytes; ++fc, advanceBytep(info, is16bit) )
879 + {
880 + uint8_t val = f(info);
881 + filterCandidate[fc] = val;
882 + curSum += val;
883 + }
884 +
885 + return curSum;
886 +}
887 +
888 +/*
889 + * Processes the input image and calls writeIdat for every BUF_SIZE compressed
890 + * bytes.
891 + */
892 +static inline int processPixels(PngInfoStruct *info)
893 +{
894 + uint8_t idatBuf[BUF_SIZE+4] = {'I', 'D', 'A', 'T'};
895 + uint8_t *compressed = idatBuf+4;
896 + uint8_t *filterCandidate = (uint8_t *)malloc(info->scanlineBytes+1);
897 + uint8_t *bestCandidate = (uint8_t *)malloc(info->scanlineBytes+1);
898 + size_t minSum = (size_t)-1, curSum = 0;
899 + int status = Z_OK;
900 + int is16bit = info->img->depth == 16;
901 +
902 + if (!filterCandidate || !bestCandidate)
903 + {
904 + printf("PNG: memory allocation failed!\n");
905 + }
906 +
907 + memset(&(info->stream), 0, sizeof(info->stream));
908 + if(deflateInit(&(info->stream), Z_DEFAULT_COMPRESSION) != Z_OK)
909 + {
910 + printf("PNG: deflateInit failed!\n");
911 + free(filterCandidate);
912 + free(bestCandidate);
913 + return PNG_ERROR;
914 + }
915 +
916 + info->stream.avail_out = BUF_SIZE;
917 + info->stream.next_out = compressed;
918 +
919 + for (info->currentRow = 0; info->currentRow < info->img->height;
920 + ++info->currentRow)
921 + {
922 + int flush = (info->currentRow < info->img->height-1) ?
923 + Z_NO_FLUSH : Z_FINISH;
924 + minSum = (size_t)-1;
925 +
926 + /*
927 + * 1st time it doesn't matter, the filters never look at the previous
928 + * scanline when processing row 0. And next time it'll be valid.
929 + */
930 + info->previousScanline = info->currentScanline;
931 + info->currentScanline = info->img->data + (info->currentRow*info->scanlineBytes);
932 +
933 + /*
934 + * Try to choose the best filter for each scanline.
935 + * Breaks in case of overflow, but hey it's just a heuristic.
936 + */
937 + for (info->currentFilter = PNG_FILTER_NONE; info->currentFilter <= PNG_FILTER_PAETH; ++info->currentFilter)
938 + {
939 +
940 + switch (info->currentFilter)
941 + {
942 + case PNG_FILTER_NONE:
943 + curSum = filterScanline(info, none, PNG_FILTER_NONE, filterCandidate, is16bit);
944 + break;
945 +
946 + case PNG_FILTER_SUB:
947 + curSum = filterScanline(info, sub, PNG_FILTER_SUB, filterCandidate, is16bit);
948 + break;
949 +
950 + case PNG_FILTER_UP:
951 + curSum = filterScanline(info, up, PNG_FILTER_UP, filterCandidate, is16bit);
952 + break;
953 +
954 + case PNG_FILTER_AVERAGE:
955 + curSum = filterScanline(info, average, PNG_FILTER_AVERAGE, filterCandidate, is16bit);
956 + break;
957 +
958 + case PNG_FILTER_PAETH:
959 + curSum = filterScanline(info, paeth, PNG_FILTER_PAETH, filterCandidate, is16bit);
960 + break;
961 +
962 + default:
963 + break;
964 + }
965 +
966 + if (curSum < minSum || !info->currentFilter)
967 + {
968 + uint8_t *tmp = bestCandidate;
969 + bestCandidate = filterCandidate;
970 + filterCandidate = tmp;
971 + minSum = curSum;
972 + }
973 + }
974 +
975 + info->stream.avail_in = info->scanlineBytes+1;
976 + info->stream.next_in = bestCandidate;
977 +
978 + // compress bestCandidate
979 + do
980 + {
981 + status = deflate(&info->stream, flush);
982 +
983 + if (info->stream.avail_out < BUF_SIZE)
984 + {
985 + writeIdat(info, idatBuf, BUF_SIZE-info->stream.avail_out+4);
986 + info->stream.next_out = compressed;
987 + info->stream.avail_out = BUF_SIZE;
988 + }
989 + } while ((flush == Z_FINISH && status != Z_STREAM_END)
990 + || (flush == Z_NO_FLUSH && info->stream.avail_in));
991 + // TODO: fix loop conditions, apparently data gets truncated
992 + }
993 +
994 + return PNG_OK;
995 +}
996 +
997 +static inline int writeIend(PngInfoStruct *info)
998 +{
999 + PngChunk c = { 0, (uint8_t *)"IEND", 0, 0 };
1000 + size_t written = 0;
1001 + c.crc = swap32(crc(c.type, 4));
1002 +
1003 + written += info->writeProc((void *)&c.length, 4, 1, info->userPtr) * 4;
1004 + written += info->writeProc((void *)c.type, 1, 4, info->userPtr);
1005 + written += info->writeProc((void *)&c.crc, 4, 1, info->userPtr) * 4;
1006 +
1007 + if (written != 12)
1008 + {
1009 + printf("PNG: write error\n");
1010 + return PNG_ERROR;
1011 + }
1012 +
1013 + return PNG_OK;
1014 +}
1015 +
1016 +int luPngWrite(PngWriteProc writeProc, void *userPtr, LuImage *img)
1017 +{
1018 + PngInfoStruct info = {
1019 + userPtr,
1020 + 0,
1021 + writeProc,
1022 + PNG_NONE
1023 + };
1024 +
1025 + info.img = img;
1026 + info.bytesPerPixel = (info.img->channels * info.img->depth) >> 3;
1027 +
1028 + if (writeProc((void *)PNG_SIG, 1, PNG_SIG_SIZE, userPtr) != PNG_SIG_SIZE)
1029 + {
1030 + printf("PNG: write error\n");
1031 + return PNG_ERROR;
1032 + }
1033 +
1034 + if (writeIhdr(&info) != PNG_OK)
1035 + return PNG_ERROR;
1036 +
1037 + info.scanlineBytes = (img->depth >> 3) * img->channels * img->width;
1038 + if (processPixels(&info) != PNG_OK)
1039 + {
1040 + deflateEnd(&(info.stream));
1041 + return PNG_ERROR;
1042 + }
1043 +
1044 + deflateEnd(&(info.stream));
1045 + return writeIend(&info);
1046 +}
1047 +
1048 +
1049 +void luImageRelease(LuImage *img)
1050 +{
1051 + free((void *)img->data);
1052 + free((void *)img);
1053 +}
1054 +
1055 +LuImage *luImageCreate(size_t width, size_t height, uint8_t channels, uint8_t depth)
1056 +{
1057 + LuImage *img;
1058 +
1059 + if (depth != 8 && depth != 16)
1060 + {
1061 + printf("Image: only bit depths 8 and 16 are supported!\n");
1062 + return 0;
1063 + }
1064 +
1065 + img = (LuImage *)malloc(sizeof(LuImage));
1066 + if (!img)
1067 + return 0;
1068 +
1069 + img->width = width;
1070 + img->height = height;
1071 + img->channels = channels;
1072 + img->depth = depth;
1073 + img->dataSize = (size_t)((depth >> 3) * width * height * channels);
1074 + img->data = (uint8_t *)malloc(img->dataSize);
1075 +
1076 + return img;
1077 +}
lupng.hView
@@ -1,0 +1,78 @@
1 +/*
2 + * The MIT License (MIT)
3 + *
4 + * Copyright (c) 2014 Jan Solanti
5 + *
6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
7 + * of this software and associated documentation files (the "Software"), to deal
8 + * in the Software without restriction, including without limitation the rights
9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 + * copies of the Software, and to permit persons to whom the Software is
11 + * furnished to do so, subject to the following conditions:
12 + *
13 + * The above copyright notice and this permission notice shall be included in all
14 + * copies or substantial portions of the Software.
15 + *
16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 + * SOFTWARE.
23 + */
24 +
25 +#ifdef __cplusplus
26 +extern "C" {
27 +#endif
28 +
29 +#pragma once
30 +#include <stdint.h>
31 +
32 +typedef struct {
33 + int32_t width;
34 + int32_t height;
35 + uint8_t channels;
36 + uint8_t depth; // must be 8 or 16
37 + size_t dataSize;
38 + uint8_t *data;
39 +} LuImage;
40 +
41 +typedef size_t (*PngReadProc)(void *outPtr, size_t size, size_t count, void *userPtr);
42 +typedef size_t (*PngWriteProc)(const void *inPtr, size_t size, size_t count, void *userPtr);
43 +
44 +/**
45 + * Creates a new Image object with the specified attributes.
46 + * The data store of the Image is allocated but its contents are undefined.
47 + * Only 8 and 16 bits deep images with 1-4 channels are supported.
48 + */
49 +LuImage *luImageCreate(size_t width, size_t height, uint8_t channels, uint8_t depth);
50 +
51 +/**
52 + * Releases the memory associated with the given Image object.
53 + */
54 +void luImageRelease(LuImage *img);
55 +
56 +/**
57 + * Decodes a PNG image with the provided read function into a LuImage struct
58 + *
59 + * @param readProc a function pointer to a user-defined function to use for
60 + * reading the PNG data.
61 + * @param userPtr an opaque pointer provided as an argument to readProc
62 + */
63 +LuImage *luPngRead(PngReadProc readProc, void *userPtr);
64 +
65 +/**
66 + * Encodes a LuImage struct to PNG and writes it out using a user-defined write
67 + * function.
68 + *
69 + * @param writeProc a function pointer to a user-defined function that will be
70 + * used for writing the final PNG data.
71 + * @param userPtr an opaque pointer provided as an argument to writeProc
72 + * @param img the LuImage to encode
73 + */
74 +int luPngWrite(PngWriteProc writeProc, void *userPtr, LuImage *img);
75 +
76 +#ifdef __cplusplus
77 +}
78 +#endif

Built with git-ssb-web