revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / png_image / loadpng.c
blob04cca2ed5796f9dc4b5afd64e10aacee77115d2f
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "class.h"
28 #include "endian.h"
29 #include <libraries/z.h>
30 #include <proto/exec.h>
31 #include <proto/dos.h>
32 #include <proto/z.h>
33 #include <string.h>
35 #pragma pack(1)
37 #define PNG_SIGNATURE "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
39 typedef struct {
40 ULONG size;
41 ULONG id;
42 } png_chunk_t;
44 #define ID_IHDR MAKE_ID('I','H','D','R')
45 #define ID_PLTE MAKE_ID('P','L','T','E')
46 #define ID_IDAT MAKE_ID('I','D','A','T')
47 #define ID_IEND MAKE_ID('I','E','N','D')
49 typedef struct {
50 ULONG width;
51 ULONG height;
52 UBYTE depth;
53 UBYTE color_type;
54 UBYTE compression;
55 UBYTE filter;
56 UBYTE interlace;
57 } png_ihdr_t;
59 #pragma pack()
61 static inline WORD abs (WORD x) {
62 return x >= 0 ? x : -x;
65 /*static void PrintULONG (ULONG x) {
66 ULONG y;
67 char buffer[9];
68 int i;
69 for (i = 0; i < 8; i++) {
70 y = (x & 0xf0000000UL) >> 28;
71 x <<= 4;
72 if (y <= 9)
73 buffer[i] = y + '0';
74 else if (y <= 15)
75 buffer[i] = y + 'A' - 10;
76 else
77 buffer[i] = '?';
79 buffer[8] = '\n';
80 Write(Output(), buffer, 9);
81 }*/
83 BOOL LoadPNG (struct ClassData *data, const char *filename, LONG index) {
84 BOOL ihdr_found = FALSE;
85 BOOL done = FALSE;
86 BPTR file = 0;
87 UBYTE signature[8];
88 png_chunk_t chunk;
89 png_ihdr_t ihdr;
90 ULONG original_crc/*, crc*/;
91 const LONG pix_size = 4;
92 LONG row_size = 0;
93 ULONG data_size = 0;
94 ULONG png_data_size = 0;
95 ULONG packed_size = 0;
96 UBYTE *packed = NULL;
97 UBYTE *unpacked = NULL;
98 ULONG dest_len, source_len;
99 UBYTE *src, *dst;
100 int filter;
101 int y, x;
102 WORD a, b, c, d;
103 WORD p, pa, pb, pc;
105 file = Open(filename, MODE_OLDFILE);
106 if (!file) {
107 goto error;
110 if (FRead(file, signature, 1, sizeof(signature)) != sizeof(signature)) {
111 goto error;
113 if (memcmp(signature, PNG_SIGNATURE, sizeof(signature))) {
114 goto error;
117 while (!done) {
118 if (FRead(file, &chunk, 1, sizeof(chunk)) != sizeof(chunk)) {
119 goto error;
121 /*crc = CRC32(0, &chunk.id, sizeof(chunk.id));*/
122 wbe32(&chunk.size, chunk.size);
123 switch (chunk.id) {
124 case ID_IHDR:
125 ihdr_found = TRUE;
126 if (chunk.size != sizeof(ihdr)) {
127 goto error;
129 if (FRead(file, &ihdr, 1, chunk.size) != chunk.size) {
130 goto error;
132 if (FRead(file, &original_crc, 1, sizeof(original_crc)) != sizeof(original_crc)) {
133 goto error;
135 /*crc = CRC32(crc, &ihdr, chunk.size);*/
136 /*PrintULONG(crc);
137 PrintULONG(original_crc);*/
138 /*if (crc != original_crc) {
139 goto error;
141 if (index == IMG_NORMAL) {
142 data->width = rbe32(&ihdr.width);
143 data->height = rbe32(&ihdr.height);
144 } else {
145 if (data->width != rbe32(&ihdr.width) || data->height != rbe32(&ihdr.height)) {
146 goto error;
149 if (ihdr.depth != 8 || ihdr.color_type != 6 || ihdr.compression != 0 ||
150 ihdr.filter != 0 || ihdr.interlace != 0)
152 goto error;
154 row_size = data->width * pix_size;
155 data_size = row_size * data->height;
156 data->image[index] = AllocVec(data_size, MEMF_ANY);
157 if (!data->image[index]) {
158 goto error;
160 png_data_size = data_size + data->height;
161 packed_size = 0;
162 packed = AllocVec(png_data_size, MEMF_ANY);
163 unpacked = AllocVec(png_data_size, MEMF_ANY);
164 if (!packed || !unpacked) {
165 goto error;
167 break;
169 case ID_IDAT:
170 if (!ihdr_found) {
171 goto error;
173 if (packed_size + chunk.size > png_data_size) {
174 goto error;
176 if (FRead(file, packed + packed_size, 1, chunk.size) != chunk.size) {
177 goto error;
179 if (FRead(file, &original_crc, 1, sizeof(original_crc)) != sizeof(original_crc)) {
180 goto error;
182 /*crc = CRC32(crc, packed + packed_size, chunk.size);*/
183 /*PrintULONG(crc);
184 PrintULONG(original_crc);*/
185 /*if (crc != original_crc) {
186 goto error;
188 packed_size += chunk.size;
189 break;
191 case ID_IEND:
192 if (!ihdr_found || !packed_size) {
193 goto error;
195 if (chunk.size != 0) {
196 goto error;
198 if (FRead(file, &original_crc, 1, sizeof(original_crc)) != sizeof(original_crc)) {
199 goto error;
201 /*PrintULONG(crc);
202 PrintULONG(original_crc);*/
203 /*if (crc != original_crc) {
204 goto error;
206 dest_len = png_data_size;
207 source_len = packed_size;
208 if (Uncompress(unpacked, &dest_len, packed, source_len) != Z_OK) {
209 goto error;
211 if (dest_len != png_data_size) {
212 goto error;
214 src = unpacked;
215 dst = data->image[index];
216 for (y = 0; y < data->height; y++) {
217 filter = *src++;
218 a = b = c = 0;
219 for (x = 0; x < row_size; x++) {
220 if (x >= pix_size) a = dst[-pix_size];
221 if (y >= 1) b = dst[-row_size];
222 if (y >= 1 && x >= pix_size) c = dst[-pix_size-row_size];
223 d = *src++;
224 switch (filter) {
225 case 0:
226 *dst++ = d;
227 break;
228 case 1:
229 *dst++ = d + a;
230 break;
231 case 2:
232 *dst++ = d + b;
233 break;
234 case 3:
235 *dst++ = d + ((a + b) / 2);
236 break;
237 case 4:
238 p = a + b - c;
239 pa = abs(p-a);
240 pb = abs(p-b);
241 pc = abs(p-c);
242 if (pa <= pb && pa <= pc)
243 *dst++ = d + a;
244 else if (pb <= pc)
245 *dst++ = d + b;
246 else
247 *dst++ = d + c;
248 break;
249 default:
250 goto error;
254 done = TRUE;
255 break;
257 default:
258 if (Seek(file, chunk.size + 4, OFFSET_CURRENT) == -1) {
259 goto error;
261 break;
265 error:
266 FreeVec(packed);
267 FreeVec(unpacked);
268 if (file) Close(file);
269 return done;