| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 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; |
|---|
| 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; |
|---|
| 134 |
dst_ptr[dst_size++] = (j / 3) - 1; |
|---|
| 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; |
|---|
| 315 |
if (pix_pixel == 1) |
|---|
| 316 |
ihdr[9] = 3; |
|---|
| 317 |
else if (pix_pixel == 3) |
|---|
| 318 |
ihdr[9] = 2; |
|---|
| 319 |
else if (pix_pixel == 4) |
|---|
| 320 |
ihdr[9] = 6; |
|---|
| 321 |
else |
|---|
| 322 |
throw error() << "Invalid format"; |
|---|
| 323 |
|
|---|
| 324 |
ihdr[10] = 0; |
|---|
| 325 |
ihdr[11] = 0; |
|---|
| 326 |
ihdr[12] = 0; |
|---|
| 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 |
|---|