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

Revision 2, 17.4 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, 2003 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 "mngex.h"
24
25 #include "lib/mng.h"
26 #include "lib/endianrw.h"
27
28 #include <cassert>
29
30 #include <iostream>
31 #include <iomanip>
32
33 using namespace std;
34
35 static bool mng_write_reduce(adv_mng_write* mng, data_ptr& out_ptr, unsigned& out_scanline, unsigned char* ovr_ptr, unsigned* ovr_used, unsigned char* img_ptr, unsigned img_scanline)
36 {
37         unsigned char col_ptr[256*3];
38         unsigned col_mapped[256];
39         unsigned col_count;
40         unsigned i,j,k;
41         unsigned char* new_ptr;
42         unsigned new_scanline;
43
44         /* build the new palette */
45         col_count = 0;
46         for(i=0;i<mng->height;++i) {
47                 unsigned char* p0 = img_ptr + i * img_scanline;
48                 for(j=0;j<mng->width;++j) {
49                         for(k=0;k<col_count;++k) {
50                                 if (col_ptr[k*3] == p0[0] && col_ptr[k*3+1] == p0[1] && col_ptr[k*3+2] == p0[2])
51                                         break;
52                         }
53                         if (k == col_count) {
54                                 if (col_count == 256)
55                                         return false; /* too many colors */
56                                 col_ptr[col_count*3] = p0[0];
57                                 col_ptr[col_count*3+1] = p0[1];
58                                 col_ptr[col_count*3+2] = p0[2];
59                                 ++col_count;
60                         }
61                         p0 += 3;
62                 }
63         }
64
65         for(i=0;i<256;++i) {
66                 ovr_used[i] = 0;
67                 col_mapped[i] = 0;
68         }
69         memcpy(ovr_ptr, mng->pal_ptr, 256*3);
70
71         /* map colors already present in the old palette */
72         for(i=0;i<col_count;++i) {
73                 for(k=0;k<256;++k) {
74                         if (!ovr_used[k] && ovr_ptr[k*3]==col_ptr[i*3] && ovr_ptr[k*3+1]==col_ptr[i*3+1] && ovr_ptr[k*3+2]==col_ptr[i*3+2])
75                                 break;
76                 }
77                 if (k<256) {
78                         ovr_used[k] = 1;
79                         col_mapped[i] = 1;
80                 }
81         }
82
83         /* map colors not present in the old palette */
84         for(i=0;i<col_count;++i) {
85                 if (!col_mapped[i]) {
86                         /* search the first free space */
87                         for(k=0;k<256;++k)
88                                 if (!ovr_used[k])
89                                         break;
90                         ovr_used[k] = 1;
91                         ovr_ptr[k*3] = col_ptr[i*3];
92                         ovr_ptr[k*3+1] = col_ptr[i*3+1];
93                         ovr_ptr[k*3+2] = col_ptr[i*3+2];
94                 }
95         }
96
97         /* create the new bitmap */
98         new_scanline = mng->width;
99         new_ptr = data_alloc(mng->height * new_scanline);
100         for(i=0;i<mng->height;++i) {
101                 unsigned char* p0 = new_ptr + i*new_scanline;
102                 unsigned char* p1 = img_ptr + i*img_scanline;
103                 for(j=0;j<mng->width;++j) {
104                         for(k=0;;++k)
105                                 if (ovr_ptr[k*3]==p1[0] && ovr_ptr[k*3+1]==p1[1] && ovr_ptr[k*3+2]==p1[2])
106                                         break;
107                         *p0 = k;
108                         ++p0;
109                         p1 += 3;
110                 }
111         }
112
113         out_ptr = new_ptr;
114         out_scanline = new_scanline;
115
116         return true;
117 }
118
119 static void mng_write_expand(adv_mng_write* mng, data_ptr& out_ptr, unsigned& out_scanline, const unsigned char* img_ptr, unsigned img_scanline, unsigned char* pal_ptr)
120 {
121         unsigned char* new_ptr;
122         unsigned new_scanline;
123         unsigned i,j;
124
125         /* create the new bitmap */
126         new_scanline = mng->width * 3;
127         new_ptr = data_alloc(mng->height * new_scanline);
128
129         for(i=0;i<mng->height;++i) {
130                 unsigned char* p0 = new_ptr + i*new_scanline;
131                 const unsigned char* p1 = img_ptr + i*img_scanline;
132                 for(j=0;j<mng->width;++j) {
133                         unsigned k = 3 * *p1;
134                         p0[0] = pal_ptr[k];
135                         p0[1] = pal_ptr[k+1];
136                         p0[2] = pal_ptr[k+2];
137                         p0 += 3;
138                         ++p1;
139                 }
140         }
141
142         out_ptr = new_ptr;
143         out_scanline = new_scanline;
144 }
145
146 void mng_write_header(adv_mng_write* mng, adv_fz* f, unsigned* fc, unsigned width, unsigned height, unsigned frequency, int scroll_x, int scroll_y, unsigned scroll_width, unsigned scroll_height)
147 {
148         unsigned simplicity;
149         unsigned char mhdr[28];
150
151         if (mng_write_signature(f, fc) != 0) {
152                 throw error_png();
153         }
154
155         switch (mng->type) {
156         case mng_vlc :
157                 simplicity = (1 << 0) /* Enable flags */
158                         | (1 << 6); /* Enable flags */
159                 break;
160         case mng_lc :
161                 simplicity = (1 << 0) /* Enable flags */
162                         | (1 << 1) /* Basic features */
163                         | (1 << 6); /* Enable flags */
164                 break;
165         default:
166         case mng_std :
167                 simplicity = (1 << 0) /* Enable flags */
168                         | (1 << 1) /* Basic features */
169                         | (1 << 2) /* Extended features */
170                         | (1 << 5) /* Delta PNG */
171                         | (1 << 6) /* Enable flags */
172                         | (1 << 9); /* Object buffers must be stored */
173                 break;
174         }
175
176         be_uint32_write(mhdr + 0, width); /* width */
177         be_uint32_write(mhdr + 4, height); /* height */
178         be_uint32_write(mhdr + 8, frequency ); /* ticks per second */
179         be_uint32_write(mhdr + 12, 0 ); /* nominal layer count */
180         be_uint32_write(mhdr + 16, 0 ); /* nominal frame count */
181         be_uint32_write(mhdr + 20, 0 ); /* nominal play time */
182         be_uint32_write(mhdr + 24, simplicity); /* simplicity profile */
183
184         if (png_write_chunk(f, MNG_CN_MHDR, mhdr, sizeof(mhdr), fc) != 0) {
185                 throw error_png();
186         }
187
188         mng->first = 1;
189
190         mng->width = width;
191         mng->height = height;
192         mng->pixel = 0;
193         mng->line = 0;
194
195         mng->scroll_x = scroll_x;
196         mng->scroll_y = scroll_y;
197         mng->scroll_width = scroll_width;
198         mng->scroll_height = scroll_height;
199
200         mng->scroll_ptr = 0;
201
202         mng->pal_size = 0;
203
204         mng->tick = 1;
205
206         mng->has_header = 1;
207 }
208
209 static bool row_equal(adv_mng_write* mng, unsigned y, unsigned char* img_ptr, unsigned img_scanline)
210 {
211         unsigned char* p0;
212         unsigned char* p1;
213
214         p0 = mng->current_ptr + y * mng->line;
215         p1 = img_ptr + y * img_scanline;
216
217         return memcmp(p0, p1, mng->width * mng->pixel) == 0;
218 }
219
220 static bool col_equal(adv_mng_write* mng, unsigned x, unsigned char* img_ptr, unsigned img_scanline) {
221         unsigned char* p0;
222         unsigned char* p1;
223         unsigned i;
224
225         p0 = mng->current_ptr + x * mng->pixel;
226         p1 = img_ptr + x * mng->pixel;
227
228         if (mng->pixel == 1) {
229                 for(i=0;i<mng->height;++i) {
230                         if (p0[0] != p1[0])
231                                 return false;
232                         p0 += mng->line;
233                         p1 += img_scanline;
234                 }
235         } else {
236                 for(i=0;i<mng->height;++i) {
237                         if (p0[0] != p1[0] || p0[1] != p1[1] || p0[2] != p1[2])
238                                 return false;
239                         p0 += mng->line;
240                         p1 += img_scanline;
241                 }
242         }
243
244         return true;
245 }
246
247 static void compute_image_range(adv_mng_write* mng, unsigned* out_x, unsigned* out_y, unsigned* out_dx, unsigned* out_dy, unsigned char* img_ptr, unsigned img_scanline)
248 {
249         unsigned x;
250         unsigned dx;
251         unsigned y;
252         unsigned dy;
253
254         x = 0;
255         while (x < mng->width && col_equal(mng, x, img_ptr, img_scanline))
256                 ++x;
257
258         dx = mng->width - x;
259         while (dx > 0 && col_equal(mng, x + dx - 1, img_ptr, img_scanline))
260                 --dx;
261
262         y = 0;
263         while (y < mng->height && row_equal(mng, y, img_ptr, img_scanline))
264                 ++y;
265
266         dy = mng->height - y;
267         while (dy > 0 && row_equal(mng, y + dy - 1, img_ptr, img_scanline))
268                 --dy;
269
270         *out_x = x;
271         *out_y = y;
272         *out_dx = dx;
273         *out_dy = dy;
274 }
275
276 static void mng_write_store(adv_mng_write* mng, unsigned char* img_ptr, unsigned img_scanline, unsigned char* pal_ptr, unsigned pal_size)
277 {
278         unsigned i;
279
280         if (pal_size) {
281                 memcpy(mng->pal_ptr, pal_ptr, pal_size);
282                 memset(mng->pal_ptr + pal_size, 0, 256*3 - pal_size);
283                 if (pal_size > mng->pal_size)
284                         mng->pal_size = pal_size;
285         }
286
287         for(i=0;i<mng->height;++i) {
288                 memcpy( &mng->current_ptr[i * mng->line], &img_ptr[i * img_scanline], mng->width * mng->pixel);
289         }
290 }
291
292 static void mng_write_first(adv_mng_write* mng, adv_fz* f, unsigned* fc)
293 {
294         unsigned char defi[12];
295         unsigned defi_size;
296         unsigned char ihdr[13];
297         data_ptr z_ptr;
298         unsigned z_size;
299
300         if (mng->type == mng_std) {
301                 be_uint16_write(defi + 0, 1); /* object id */
302                 defi[2] = 0; /* visible */
303                 defi[3] = 1; /* concrete */
304                 if (mng->scroll_x!=0 || mng->scroll_y!=0) {
305                         be_uint32_write(defi + 4, - mng->scroll_x);
306                         be_uint32_write(defi + 8, - mng->scroll_y);
307                         defi_size = 12;
308                 } else
309                         defi_size = 4;
310                 if (png_write_chunk(f, MNG_CN_DEFI, defi, defi_size, fc) != 0) {
311                         throw error_png();
312                 }
313         }
314
315         be_uint32_write(ihdr + 0, mng->width + mng->scroll_width);
316         be_uint32_write(ihdr + 4, mng->height + mng->scroll_height);
317         ihdr[8] = 8; /* bit depth */
318         if (mng->pixel == 1)
319                 ihdr[9] = 3; /* color type */
320         else
321                 ihdr[9] = 2; /* color type */
322         ihdr[10] = 0; /* compression */
323         ihdr[11] = 0; /* filter */
324         ihdr[12] = 0; /* interlace */
325
326         if (png_write_chunk(f, PNG_CN_IHDR, ihdr, sizeof(ihdr), fc) != 0) {
327                 throw error_png();
328         }
329
330         if (mng->pal_size) {
331                 if (png_write_chunk(f, PNG_CN_PLTE, mng->pal_ptr, mng->pal_size, fc) != 0) {
332                         throw error_png();
333                 }
334         }
335
336         png_compress(mng->level, z_ptr, z_size, mng->scroll_ptr, mng->line, mng->pixel, 0, 0, mng->width + mng->scroll_width, mng->height + mng->scroll_height);
337
338         if (png_write_chunk(f, PNG_CN_IDAT, z_ptr, z_size, fc) != 0) {
339                 throw error_png();
340         }
341
342         if (png_write_chunk(f, PNG_CN_IEND, 0, 0, fc) != 0) {
343                 throw error_png();
344         }
345 }
346
347 static void mng_write_move(adv_mng_write* mng, adv_fz* f, unsigned* fc, int shift_x, int shift_y)
348 {
349         unsigned char move[13];
350
351         if (shift_x!=0 || shift_y!=0) {
352
353                 be_uint16_write(move + 0, 1); /* id 1 */
354                 be_uint16_write(move + 2, 1); /* id 1 */
355                 move[4] = 1; /* adding */
356                 be_uint32_write(move + 5, - shift_x);
357                 be_uint32_write(move + 9, - shift_y);
358
359                 if (png_write_chunk(f, MNG_CN_MOVE, move, sizeof(move), fc)!=0) {
360                         throw error_png();
361                 }
362         }
363 }
364
365 static void mng_write_delta_image(adv_mng_write* mng, adv_fz* f, unsigned* fc, unsigned char* img_ptr, unsigned img_scanline, unsigned char* pal_ptr, unsigned pal_size)
366 {
367         unsigned x,y,dx,dy;
368         data_ptr pal_d_ptr;
369         unsigned pal_d_size;
370         data_ptr pal_r_ptr;
371         unsigned pal_r_size;
372         data_ptr z_d_ptr;
373         unsigned z_d_size;
374         data_ptr z_r_ptr;
375         unsigned z_r_size;
376         unsigned char dhdr[20];
377         unsigned dhdr_size;
378
379         if (pal_ptr && pal_size) {
380                 png_compress_palette_delta(pal_d_ptr, pal_d_size, pal_ptr, pal_size, mng->pal_ptr);
381
382                 pal_r_ptr = data_dup(pal_ptr, pal_size);
383                 pal_r_size = pal_size;
384         } else {
385                 pal_d_ptr = 0;
386                 pal_d_size = 0;
387                 pal_r_ptr = 0;
388                 pal_r_size = 0;
389         }
390
391         compute_image_range(mng, &x, &y, &dx, &dy, img_ptr, img_scanline);
392
393         if (dx && dy) {
394                 png_compress_delta(mng->level, z_d_ptr, z_d_size, img_ptr, img_scanline, mng->pixel, mng->current_ptr, mng->line, x, y, dx, dy);
395                 png_compress(mng->level, z_r_ptr, z_r_size, img_ptr, img_scanline, mng->pixel, x, y, dx, dy);
396         } else {
397                 z_d_ptr = 0;
398                 z_d_size = 0;
399                 z_r_ptr = 0;
400                 z_r_size = 0;
401         }
402
403         be_uint16_write(dhdr + 0