1 /*
2 * This file is part of the AdvanceSCAN project.
3 *
4 * Copyright (C) 2002 Andrea Mazzoleni
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "portable.h"
22
23 #include "lib/endianrw.h"
24 #include "lib/mng.h"
25
26 #include "pngex.h"
27
28 #include <iostream>
29 #include <iomanip>
30
31 using namespace std;
32
png_compress(shrink_t level,data_ptr & out_ptr,unsigned & out_size,const unsigned char * img_ptr,unsigned img_scanline,unsigned img_pixel,unsigned x,unsigned y,unsigned dx,unsigned dy)33 void png_compress(shrink_t level, data_ptr& out_ptr, unsigned& out_size, const unsigned char* img_ptr, unsigned img_scanline, unsigned img_pixel, unsigned x, unsigned y, unsigned dx, unsigned dy)
34 {
35 data_ptr fil_ptr;
36 unsigned fil_size;
37 unsigned fil_scanline;
38 data_ptr z_ptr;
39 unsigned z_size;
40 unsigned i;
41 unsigned char* p0;
42
43 fil_scanline = dx * img_pixel + 1;
44 fil_size = dy * fil_scanline;
45 z_size = oversize_zlib(fil_size);
46
47 fil_ptr = data_alloc(fil_size);
48 z_ptr = data_alloc(z_size);
49
50 p0 = fil_ptr;
51
52 for(i=0;i<dy;++i) {
53 const unsigned char* p1 = &img_ptr[x * img_pixel + (i+y) * img_scanline];
54 *p0++ = 0;
55 memcpy(p0, p1, dx * img_pixel);
56 p0 += dx * img_pixel;
57 }
58
59 assert(p0 == fil_ptr + fil_size);
60
61 if (!compress_zlib(level, z_ptr, z_size, fil_ptr, fil_size)) {
62 throw error() << "Failed compression";
63 }
64
65 out_ptr = z_ptr;
66 out_size = z_size;
67 }
68
png_compress_delta(shrink_t level,data_ptr & out_ptr,unsigned & out_size,const unsigned char * img_ptr,unsigned img_scanline,unsigned img_pixel,const unsigned char * prev_ptr,unsigned prev_scanline,unsigned x,unsigned y,unsigned dx,unsigned dy)69 void png_compress_delta(shrink_t level, data_ptr& out_ptr, unsigned& out_size, const unsigned char* img_ptr, unsigned img_scanline, unsigned img_pixel, const unsigned char* prev_ptr, unsigned prev_scanline, unsigned x, unsigned y, unsigned dx, unsigned dy)
70 {
71 data_ptr fil_ptr;
72 unsigned fil_size;
73 unsigned fil_scanline;
74 data_ptr z_ptr;
75 unsigned z_size;
76 unsigned i;
77 unsigned char* p0;
78
79 fil_scanline = dx * img_pixel + 1;
80 fil_size = dy * fil_scanline;
81 z_size = oversize_zlib(fil_size);
82
83 fil_ptr = data_alloc(fil_size);
84 z_ptr = data_alloc(z_size);
85
86 p0 = fil_ptr;
87
88 for(i=0;i<dy;++i) {
89 unsigned j;
90 const unsigned char* p1 = &img_ptr[x * img_pixel + (i+y) * img_scanline];
91 const unsigned char* p2 = &prev_ptr[x * img_pixel + (i+y) * prev_scanline];
92
93 *p0++ = 0;
94 for(j=0;j<dx*img_pixel;++j)
95 *p0++ = *p1++ - *p2++;
96 }
97
98 assert(p0 == fil_ptr + fil_size);
99
100 if (!compress_zlib(level, z_ptr, z_size, fil_ptr, fil_size)) {
101 throw error() << "Failed compression";
102 }
103
104 out_ptr = z_ptr;
105 out_size = z_size;
106 }
107
png_compress_palette_delta(data_ptr & out_ptr,unsigned & out_size,const unsigned char * pal_ptr,unsigned pal_size,const unsigned char * prev_ptr,unsigned prev_size)108 void png_compress_palette_delta(data_ptr& out_ptr, unsigned& out_size, const unsigned char* pal_ptr, unsigned pal_size, const unsigned char* prev_ptr, unsigned prev_size)
109 {
110 unsigned i;
111 unsigned char* dst_ptr;
112 unsigned dst_size;
113
114 dst_ptr = data_alloc(pal_size * 2);
115 dst_size = 0;
116
117 dst_ptr[dst_size++] = 0; /* replacement */
118
119 i = 0;
120 while (i<pal_size) {
121 unsigned j;
122
123 while (i < pal_size && (i < prev_size && prev_ptr[i] == pal_ptr[i] && prev_ptr[i+1] == pal_ptr[i+1] && prev_ptr[i+2] == pal_ptr[i+2]))
124 i += 3;
125
126 if (i == pal_size)
127 break;
128
129 j = i + 3;
130
131 while (j < pal_size && (j >= prev_size || prev_ptr[j] != pal_ptr[j] || prev_ptr[j+1] != pal_ptr[j+1] || prev_ptr[j+2] != pal_ptr[j+2]))
132 j += 3;
133
134 dst_ptr[dst_size++] = i / 3; /* first index */
135 dst_ptr[dst_size++] = (j / 3) - 1; /* last index */
136
137 while (i < j) {
138 dst_ptr[dst_size++] = pal_ptr[i++];
139 dst_ptr[dst_size++] = pal_ptr[i++];
140 dst_ptr[dst_size++] = pal_ptr[i++];
141 }
142 }
143
144 if (dst_size == 1) {
145 out_ptr = 0;
146 out_size = 0;
147 free(dst_ptr);
148 } else {
149 out_ptr = dst_ptr;
150 out_size = dst_size;
151 }
152 }
153
png_print_chunk(unsigned type,unsigned char * data,unsigned size)154 void png_print_chunk(unsigned type, unsigned char* data, unsigned size)
155 {
156 char tag[5];
157 unsigned i;
158
159 be_uint32_write(tag, type);
160 tag[4] = 0;
161
162 cout << tag << setw(8) << size;
163
164 switch (type) {
165 case ADV_MNG_CN_MHDR :
166 if (size < 28) {
167 cout << " invalid chunk size";
168 break;
169 }
170 cout << " width:" << be_uint32_read(data+0) << " height:" << be_uint32_read(data+4) << " frequency:" << be_uint32_read(data+8);
171 cout << " simplicity:" << be_uint32_read(data+24);
172 cout << "(bit";
173 for(i=0;i<32;++i) {
174 if (be_uint32_read(data+24) & (1 << i)) {
175 cout << "," << i;
176 }
177 }
178 cout << ")";
179 break;
180 case ADV_MNG_CN_DHDR :
181 if (size < 4) {
182 cout << " invalid chunk size";
183 break;
184 }
185 cout << " id:" << be_uint16_read(data+0);
186 switch (data[2]) {
187 case 0 : cout << " img:unspecified"; break;
188 case 1 : cout << " img:png"; break;
189 case 2 : cout << " img:jng"; break;
190 default: cout << " img:?"; break;
191 }
192 switch (data[3]) {
193 case 0 : cout << " delta:entire_replacement"; break;
194 case 1 : cout << " delta:block_addition"; break;
195 case 2 : cout << " delta:block_alpha_addition"; break;
196 case 3 : cout << " delta:block_color_addition"; break;
197 case 4 : cout << " delta:block_replacement"; break;
198 case 5 : cout << " delta:block_alpha_replacement"; break;
199 case 6 : cout << " delta:block_color_replacement"; break;
200 case 7 : cout << " delta:no_change"; break;
201 default: cout << " delta:?"; break;
202 }
203 if (size >= 12) {
204 cout << " width:" << be_uint32_read(data + 4) << " height:" << be_uint32_read(data + 8);
205 }
206 if (size >= 20) {
207 cout << " x:" << (int)be_uint32_read(data + 12) << " y:" << (int)be_uint32_read(data + 16);
208 }
209 break;
210 case ADV_MNG_CN_FRAM :
211 if (size >= 1) {
212 cout << " mode:" << (unsigned)data[0];
213 }
214 if (size > 1) {
215 i = 1;
216 while (i < size && data[i]!=0)
217 ++i;
218 cout << " len:" << i-1;
219
220 if (size >= i+2) {
221 cout << " delay_mode:" << (unsigned)data[i+1];
222 }
223
224 if (size >= i+3) {
225 cout << " timeout:" << (unsigned)data[i+2];
226 }
227
228 if (size >= i+4) {
229 cout << " clip:" << (unsigned)data[i+3];
230 }
231
232 if (size >= i+5) {
233 cout << " syncid:" << (unsigned)data[i+4];
234 }
235
236 if (size >= i+9) {
237 cout << " tick:" << be_uint32_read(data+i+5);
238 }
239
240 if (size >= i+13) {
241 cout << " timeout:" << be_uint32_read(data+i+9);
242 }
243
244 if (size >= i+14) {
245 cout << " dt:" << (unsigned)data[i+10];
246 }
247
248 if (size >= i+15) {
249 cout << " ...";
250 }
251 }
252 break;
253 case ADV_MNG_CN_DEFI :
254 if (size < 2) {
255 cout << " invalid chunk size";
256 break;
257 }
258 cout << " id:" << be_uint16_read(data+0);
259 if (size >= 3) {
260 switch (data[2]) {
261 case 0 : cout << " visible:yes"; break;
262 case 1 : cout << " visible:no"; break;
263 default : cout << " visible:?"; break;
264 }
265 }
266 if (size >= 4) {
267 switch (data[3]) {
268 case 0 : cout << " concrete:abstract"; break;
269 case 1 : cout << " concrete:concrete"; break;
270 default : cout << " concrete:?"; break;
271 }
272 }
273 if (size >= 12) {
274 cout << " x:" << (int)be_uint32_read(data + 4) << " y:" << (int)be_uint32_read(data + 8);
275 }
276 if (size >= 28) {
277 cout << " left:" << be_uint32_read(data + 12) << " right:" << be_uint32_read(data + 16) << " top:" << be_uint32_read(data + 20) << " bottom:" << be_uint32_read(data + 24);
278 }
279 break;
280 case ADV_MNG_CN_MOVE :
281 if (size < 13) {
282 cout << " invalid chunk size";
283 break;
284 }
285 cout << " id_from:" << be_uint16_read(data+0) << " id_to:" << be_uint16_read(data+2);
286 switch (data[4]) {
287 case 0 : cout << " type:replace"; break;
288 case 1 : cout << " type:add"; break;
289 default : cout << " type:?"; break;
290 }
291 cout << " x:" << (int)be_uint32_read(data + 5) << " y:" << (int)be_uint32_read(data + 9);
292 break;
293 case ADV_MNG_CN_PPLT :
294 if (size < 1) {
295 cout << " invalid chunk size";
296 break;
297 }
298 switch (data[0]) {
299 case 0 : cout << " type:replacement_rgb"; break;
300 case 1 : cout << " type:delta_rgb"; break;
301 case 2 : cout << " type:replacement_alpha"; break;
302 case 3 : cout << " type:delta_alpha"; break;
303 case 4 : cout << " type:replacement_rgba"; break;
304 case 5 : cout << " type:delta_rgba"; break;
305 default : cout << " type:?"; break;
306 }
307 i = 1;
308 while (i + 1 < size) {
309 unsigned ssize;
310 cout << " " << (unsigned)data[i] << ":" << (unsigned)data[i+1];
311 if (data[0] == 0 || data[1] == 1)
312 ssize = 3;
313 else if (data[0] == 2 || data[1] == 3)
314 ssize = 1;
315 else
316 ssize = 4;
317 i += 2 + (data[i+1] - data[i] + 1) * ssize;
318 }
319 break;
320 case ADV_PNG_CN_IHDR :
321 if (size < 13) {
322 cout << " invalid chunk size";
323 break;
324 }
325 cout << " width:" << be_uint32_read(data) << " height:" << be_uint32_read(data + 4);
326 cout << " depth:" << (unsigned)data[8];
327 cout << " color_type:" << (unsigned)data[9];
328 cout << " compression:" << (unsigned)data[10];
329 cout << " filter:" << (unsigned)data[11];
330 cout << " interlace:" << (unsigned)data[12];
331 break;
332 }
333
334 cout << endl;
335 }
336
png_write(adv_fz * f,unsigned pix_width,unsigned pix_height,unsigned pix_pixel,unsigned char * pix_ptr,unsigned pix_scanline,unsigned char * pal_ptr,unsigned pal_size,unsigned char * rns_ptr,unsigned rns_size,shrink_t level)337 void png_write(adv_fz* f, unsigned pix_width, unsigned pix_height, unsigned pix_pixel, unsigned char* pix_ptr, unsigned pix_scanline, unsigned char* pal_ptr, unsigned pal_size, unsigned char* rns_ptr, unsigned rns_size, shrink_t level)
338 {
339 unsigned char ihdr[13];
340 data_ptr z_ptr;
341 unsigned z_size;
342
343 if (adv_png_write_signature(f, 0) != 0) {
344 throw_png_error();
345 }
346
347 be_uint32_write(ihdr + 0, pix_width);
348 be_uint32_write(ihdr + 4, pix_height);
349 ihdr[8] = 8; /* bit depth */
350 if (pix_pixel == 1)
351 ihdr[9] = 3; /* color type */
352 else if (pix_pixel == 3)
353 ihdr[9] = 2; /* color type */
354 else if (pix_pixel == 4)
355 ihdr[9] = 6; /* color type */
356 else
357 throw error() << "Invalid format";
358
359 ihdr[10] = 0; /* compression */
360 ihdr[11] = 0; /* filter */
361 ihdr[12] = 0; /* interlace */
362
363 if (adv_png_write_chunk(f, ADV_PNG_CN_IHDR, ihdr, sizeof(ihdr), 0) != 0) {
364 throw_png_error();
365 }
366
367 if (pal_size) {
368 if (adv_png_write_chunk(f, ADV_PNG_CN_PLTE, pal_ptr, pal_size, 0) != 0) {
369 throw_png_error();
370 }
371 }
372
373 if (rns_size) {
374 if (adv_png_write_chunk(f, ADV_PNG_CN_tRNS, rns_ptr, rns_size, 0) != 0) {
375 throw_png_error();
376 }
377 }
378
379 png_compress(level, z_ptr, z_size, pix_ptr, pix_scanline, pix_pixel, 0, 0, pix_width, pix_height);
380
381 if (adv_png_write_chunk(f, ADV_PNG_CN_IDAT, z_ptr, z_size, 0) != 0) {
382 throw_png_error();
383 }
384
385 if (adv_png_write_chunk(f, ADV_PNG_CN_IEND, 0, 0, 0) != 0) {
386 throw_png_error();
387 }
388 }
389
png_convert_4(unsigned pix_width,unsigned pix_height,unsigned pix_pixel,unsigned char * pix_ptr,unsigned pix_scanline,unsigned char * pal_ptr,unsigned pal_size,unsigned char ** dst_ptr,unsigned * dst_pixel,unsigned * dst_scanline)390 void png_convert_4(
391 unsigned pix_width, unsigned pix_height, unsigned pix_pixel, unsigned char* pix_ptr, unsigned pix_scanline,
392 unsigned char* pal_ptr, unsigned pal_size,
393 unsigned char** dst_ptr, unsigned* dst_pixel, unsigned* dst_scanline)
394 {
395 *dst_pixel = 4;
396 *dst_scanline = 4 * pix_width;
397 *dst_ptr = (unsigned char*)malloc(*dst_scanline * pix_height);
398
399 if (pix_pixel == 3) {
400 unsigned i, j;
401 for(i=0;i<pix_height;++i) {
402 const unsigned char* p0 = pix_ptr + i * pix_scanline;
403 unsigned char* p1 = *dst_ptr + i * *dst_scanline;
404 for(j=0;j<pix_width;++j) {
405 p1[0] = p0[0];
406 p1[1] = p0[1];
407 p1[2] = p0[2];
408 p1[3] = 0xFF;
409 p0 += 3;
410 p1 += 4;
411 }
412 }
413 } else if (pix_pixel == 1) {
414 unsigned i, j;
415 for(i=0;i<pix_height;++i) {
416 const unsigned char* p0 = pix_ptr + i * pix_scanline;
417 unsigned char* p1 = *dst_ptr + i * *dst_scanline;
418 for(j=0;j<pix_width;++j) {
419 unsigned char* c = &pal_ptr[p0[0]*3];
420 p1[0] = c[0];
421 p1[1] = c[1];
422 p1[2] = c[2];
423 p1[3] = 0xFF;
424 p0 += 1;
425 p1 += 4;
426 }
427 }
428 } else if (pix_pixel == 4) {
429 unsigned i;
430 for(i=0;i<pix_height;++i) {
431 const unsigned char* p0 = pix_ptr + i * pix_scanline;
432 unsigned char* p1 = *dst_ptr + i * *dst_scanline;
433 memcpy(p1, p0, *dst_scanline);
434 }
435 } else {
436 throw error_unsupported() << "Unsupported format";
437 }
438 }
439
440