root/morphix/trunk/cloop/advancecomp-1.9_create_compressed_fs/pngex.cc

Revision 2, 10.8 kB (checked in by nextime, 2 years ago)

Initial import, branching from morphix svn

Line 
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 <cassert>
29
30 #include <iostream>
31 #include <iomanip>
32
33 using namespace std;
34
35 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) {
36         data_ptr fil_ptr;
37         unsigned fil_size;
38         unsigned fil_scanline;
39         data_ptr z_ptr;
40         unsigned z_size;
41         unsigned i;
42         unsigned char* p0;
43
44         fil_scanline = dx * img_pixel + 1;
45         fil_size = dy * fil_scanline;
46         z_size = oversize_zlib(fil_size);
47
48         fil_ptr = data_alloc(fil_size);
49         z_ptr = data_alloc(z_size);
50
51         p0 = fil_ptr;
52
53         for(i=0;i<dy;++i) {
54                 const unsigned char* p1 = &img_ptr[x * img_pixel + (i+y) * img_scanline];
55                 *p0++ = 0;
56                 memcpy(p0, p1, dx * img_pixel);
57                 p0 += dx * img_pixel;
58         }
59
60         assert(p0 == fil_ptr + fil_size);
61
62         if (!compress_zlib(level, z_ptr, z_size, fil_ptr, fil_size)) {
63                 throw error() << "Failed compression";
64         }
65
66         out_ptr = z_ptr;
67         out_size = z_size;
68 }
69
70 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) {
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
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) {
109         unsigned i;
110         unsigned char* dst_ptr;
111         unsigned dst_size;
112
113         dst_ptr = data_alloc(pal_size * 2);
114         dst_size = 0;
115
116         dst_ptr[dst_size++] = 0; /* replacement */
117
118         i = 0;
119         while (i<pal_size) {
120                 unsigned j;
121
122                 while (i < pal_size && prev_ptr[i] == pal_ptr[i] && prev_ptr[i+1] == pal_ptr[i+1] && prev_ptr[i+2] == pal_ptr[i+2])
123                         i += 3;
124
125                 if (i == pal_size)
126                         break;
127
128                 j = i;
129
130                 while (j < pal_size && (prev_ptr[j] != pal_ptr[j] || prev_ptr[j+1] != pal_ptr[j+1] || prev_ptr[j+2] != pal_ptr[j+2]))
131                         j += 3;
132
133                 dst_ptr[dst_size++] = i / 3; /* first index */
134                 dst_ptr[dst_size++] = (j / 3) - 1; /* last index */
135
136                 while (i < j) {
137                         dst_ptr[dst_size++] = pal_ptr[i++];
138                         dst_ptr[dst_size++] = pal_ptr[i++];
139                         dst_ptr[dst_size++] = pal_ptr[i++];
140                 }
141         }
142
143         if (dst_size == 1) {
144                 out_ptr = 0;
145                 out_size = 0;
146                 free(dst_ptr);
147         } else {
148                 out_ptr = dst_ptr;
149                 out_size = dst_size;
150         }
151 }
152
153 void png_print_chunk(unsigned type, unsigned char* data, unsigned size) {
154         char tag[5];
155         unsigned i;
156
157         be_uint32_write(tag, type);
158         tag[4] = 0;
159
160         cout << tag << setw(8) << size;
161
162         switch (type) {
163                 case MNG_CN_MHDR :
164                         cout << " width:" << be_uint32_read(data+0) << " height:" << be_uint32_read(data+4) << " frequency:" << be_uint32_read(data+8) << " simplicity:" << be_uint32_read(data+24);
165                 break;
166                 case MNG_CN_DHDR :
167                         cout << " id:" << be_uint16_read(data+0);
168                         switch (data[2]) {
169                                 case 0 : cout << " img:unspecified"; break;
170                                 case 1 : cout << " img:png"; break;
171                                 case 2 : cout << " img:jng"; break;
172                                 default: cout << " img:?"; break;
173                         }
174                         switch (data[3]) {
175                                 case 0 : cout << " delta:entire_replacement"; break;
176                                 case 1 : cout << " delta:block_addition"; break;
177                                 case 2 : cout << " delta:block_alpha_addition"; break;
178                                 case 3 : cout << " delta:block_color_addition"; break;
179                                 case 4 : cout << " delta:block_replacement"; break;
180                                 case 5 : cout << " delta:block_alpha_replacement"; break;
181                                 case 6 : cout << " delta:block_color_replacement"; break;
182                                 case 7 : cout << " delta:no_change"; break;
183                                 default: cout << " delta:?"; break;
184                         }
185                         if (size >= 12) {
186                                 cout << " width:" << be_uint32_read(data + 4) << " height:" << be_uint32_read(data + 8);
187                         }
188                         if (size >= 20) {
189                                 cout << " x:" << (int)be_uint32_read(data + 12) << " y:" << (int)be_uint32_read(data + 16);
190                         }
191                 break;
192                 case MNG_CN_FRAM :
193                         if (size >= 1) {
194                                 cout << " mode:" << (unsigned)data[0];
195                         }
196                         if (size > 1) {
197                                 i = 1;
198                                 while (i < size && data[i]!=0)
199                                         ++i;
200                                 cout << " len:" << i-1;
201
202                                 if (size >= i+2) {
203                                         cout << " delay_mode:" << (unsigned)data[i+1];
204                                 }
205
206                                 if (size >= i+3) {
207                                         cout << " timeout:" << (unsigned)data[i+2];
208                                 }
209
210                                 if (size >= i+4) {
211                                         cout << " clip:" << (unsigned)data[i+3];
212                                 }
213
214                                 if (size >= i+5) {
215                                         cout << " syncid:" << (unsigned)data[i+4];
216                                 }
217
218                                 if (size >= i+9) {
219                                         cout << " tick:" << be_uint32_read(data+i+5);
220                                 }
221
222                                 if (size >= i+13) {
223                                         cout << " timeout:" << be_uint32_read(data+i+9);
224                                 }
225
226                                 if (size >= i+14) {
227                                         cout << " dt:" << (unsigned)data[i+10];
228                                 }
229
230                                 if (size >= i+15) {
231                                         cout << " ...";
232                                 }
233                         }
234                         break;
235                 case MNG_CN_DEFI :
236                         cout << " id:" << be_uint16_read(data+0);
237                         if (size >= 3) {
238                                 switch (data[2]) {
239                                         case 0 : cout << " visible:yes"; break;
240                                         case 1 : cout << " visible:no"; break;
241                                         default : cout << " visible:?"; break;
242                                 }
243                         }
244                         if (size >= 4) {
245                                 switch (data[3]) {
246                                         case 0 : cout << " concrete:abstract"; break;
247                                         case 1 : cout << " concrete:concrete"; break;
248                                         default : cout << " concrete:?"; break;
249                                 }
250                         }
251                         if (size >= 12) {
252                                 cout << " x:" << (int)be_uint32_read(data + 4) << " y:" << (int)be_uint32_read(data + 8);
253                         }
254                         if (size >= 28) {
255                                 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);
256                         }
257                 break;
258                 case MNG_CN_MOVE :
259                         cout << " id_from:" << be_uint16_read(data+0) << " id_to:" << be_uint16_read(data+2);
260                         switch (data[4]) {
261                                 case 0 : cout << " type:replace"; break;
262                                 case 1 : cout << " type:add"; break;
263                                 default : cout << " type:?"; break;
264                         }
265                         cout << " x:" << (int)be_uint32_read(data + 5) << " y:" << (int)be_uint32_read(data + 9);
266                         break;
267                 case MNG_CN_PPLT :
268                         switch (data[0]) {
269                                 case 0 : cout << " type:replacement_rgb"; break;
270                                 case 1 : cout << " type:delta_rgb"; break;
271                                 case 2 : cout << " type:replacement_alpha"; break;
272                                 case 3 : cout << " type:delta_alpha"; break;
273                                 case 4 : cout << " type:replacement_rgba"; break;
274                                 case 5 : cout << " type:delta_rgba"; break;
275                                 default : cout << " type:?"; break;
276                         }
277                         i = 1;
278                         while (i<size) {
279                                 unsigned ssize;
280                                 cout << " " << (unsigned)data[i] << ":" << (unsigned)data[i+1];
281                                 if (data[0] == 0 || data[1] == 1)
282                                         ssize = 3;
283                                 else if (data[0] == 2 || data[1] == 3)
284                                         ssize = 1;
285                                 else
286                                         ssize = 4;
287                                 i += 2 + (data[i+1] - data[i] + 1) * ssize;
288                         }
289                         break;
290                 case PNG_CN_IHDR :
291                         cout << " width:" << be_uint32_read(data) << " height:" << be_uint32_read(data + 4);
292                         cout << " depth:" << (unsigned)data[8];
293                         cout << " color_type:" << (unsigned)data[9];
294                         cout << " compression:" << (unsigned)data[10];
295                         cout << " filter:" << (unsigned)data[11];
296                         cout << " interlace:" << (unsigned)data[12];
297                 break;
298         }
299
300         cout << endl;
301 }
302
303 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) {
304         unsigned char ihdr[13];
305         data_ptr z_ptr;
306         unsigned z_size;
307
308         if (png_write_signature(f, 0) != 0) {
309                 throw error_png();
310         }
311
312         be_uint32_write(ihdr + 0, pix_width);
313         be_uint32_write(ihdr + 4, pix_height);
314         ihdr[8] = 8; /* bit depth */
315         if (pix_pixel == 1)
316                 ihdr[9] = 3; /* color type */
317         else if (pix_pixel == 3)
318                 ihdr[9] = 2; /* color type */
319         else if (pix_pixel == 4)
320                 ihdr[9] = 6; /* color type */
321         else
322                 throw error() << "Invalid format";
323
324         ihdr[10] = 0; /* compression */
325         ihdr[11] = 0; /* filter */
326         ihdr[12] = 0; /* interlace */
327
328         if (png_write_chunk(f, PNG_CN_IHDR, ihdr, sizeof(ihdr), 0) != 0) {
329                 throw error_png();
330         }
331
332         if (pal_size) {
333                 if (png_write_chunk(f, PNG_CN_PLTE, pal_ptr, pal_size, 0) != 0) {
334                         throw error_png();
335                 }
336         }
337
338         if (rns_size) {
339                 if (png_write_chunk(f, PNG_CN_tRNS, rns_ptr, rns_size, 0) != 0) {
340                         throw error_png();
341                 }
342         }
343
344         png_compress(level, z_ptr, z_size, pix_ptr, pix_scanline, pix_pixel, 0, 0, pix_width, pix_height);
345
346         if (png_write_chunk(f, PNG_CN_IDAT, z_ptr, z_size, 0) != 0) {
347                 throw error_png();
348         }
349
350         if (png_write_chunk(f, PNG_CN_IEND, 0, 0, 0) != 0) {
351                 throw error_png();
352         }
353 }
354
355 void png_convert_4(
356         unsigned pix_width, unsigned pix_height, unsigned pix_pixel, unsigned char* pix_ptr, unsigned pix_scanline,
357         unsigned char* pal_ptr, unsigned pal_size,
358         unsigned char** dst_ptr, unsigned* dst_pixel, unsigned* dst_scanline
359 ) {
360         *dst_pixel = 4;
361         *dst_scanline = 4 * pix_width;
362         *dst_ptr = (unsigned char*)malloc( *dst_scanline * pix_height );
363
364         if (pix_pixel == 3) {
365                 unsigned i,j;
366                 for(i=0;i<pix_height;++i) {
367                         const unsigned char* p0 = pix_ptr + i * pix_scanline;
368                         unsigned char* p1 = *dst_ptr + i * *dst_scanline;
369                         for(j=0;j<pix_width;++j) {
370                                 p1[0] = p0[0];
371                                 p1[1] = p0[1];
372                                 p1[2] = p0[2];
373                                 p1[3] = 0xFF;
374                                 p0 += 3;
375                                 p1 += 4;
376                         }
377                 }
378         } else if (pix_pixel == 1) {
379                 unsigned i,j