@@ -2462,11 +2462,63 @@ PNG_CHUNK_FDAT* PNG_CHUNK_FDAT::generate() {
24622462
24632463
24642464
2465- std::string compress_data (std::string data, int level) {
2465+ int ZEXPORT compress3 (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level, int windowBits)
2466+ {
2467+ z_stream stream;
2468+ int err;
2469+ const uInt max = (uInt)-1 ;
2470+ uLong left;
2471+
2472+ left = *destLen;
2473+ *destLen = 0 ;
2474+
2475+ stream.zalloc = (alloc_func)0 ;
2476+ stream.zfree = (free_func)0 ;
2477+ stream.opaque = (voidpf)0 ;
2478+
2479+ err = deflateInit2 (&stream, level, Z_DEFLATED, windowBits, 8 , Z_DEFAULT_STRATEGY);
2480+ if (err != Z_OK) return err;
2481+
2482+ stream.next_out = dest;
2483+ stream.avail_out = 0 ;
2484+ stream.next_in = (z_const Bytef *)source;
2485+ stream.avail_in = 0 ;
2486+
2487+ do {
2488+ if (stream.avail_out == 0 ) {
2489+ stream.avail_out = left > (uLong)max ? max : (uInt)left;
2490+ left -= stream.avail_out ;
2491+ }
2492+ if (stream.avail_in == 0 ) {
2493+ stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
2494+ sourceLen -= stream.avail_in ;
2495+ }
2496+ err = deflate (&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
2497+ } while (err == Z_OK);
2498+
2499+ *destLen = stream.total_out ;
2500+ deflateEnd (&stream);
2501+ return err == Z_STREAM_END ? Z_OK : err;
2502+ }
2503+
2504+
2505+
2506+ std::string compress_data (std::string data, int level, int windowBits) {
24662507 unsigned long data_len = data.size ();
2467- unsigned long comp_len = compressBound (data_len);
2508+ unsigned long comp_len = 2 * compressBound (data_len);
24682509 unsigned char * compressed = (unsigned char *) malloc (comp_len);
2469- compress2 (compressed, &comp_len, (const Bytef*) data.c_str (), data_len, level);
2510+ compress3 (compressed, &comp_len, (const Bytef*) data.c_str (), data_len, level, windowBits);
2511+ if (windowBits == 8 && compressed[0 ] == 0x18 ) {
2512+ compressed[0 ] = 0x08 ;
2513+ if (compressed[1 ] == 0x19 )
2514+ compressed[1 ] = 0x1d ;
2515+ if (compressed[1 ] == 0x57 )
2516+ compressed[1 ] = 0x5b ;
2517+ if (compressed[1 ] == 0x95 )
2518+ compressed[1 ] = 0x99 ;
2519+ if (compressed[1 ] == 0xd3 )
2520+ compressed[1 ] = 0xd7 ;
2521+ }
24702522 std::string compressed_str ((char *) compressed, comp_len);
24712523 free (compressed);
24722524 return compressed_str;
@@ -2541,19 +2593,30 @@ std::string generate_data(uint32 width, uint32 height, PNG_COLOR_SPACE_TYPE colo
25412593 }
25422594 }
25432595
2596+ int windowBits = 15 ;
25442597 if (!file_acc.generate ) {
25452598 assert_cond (data_len == data.length (), " wrong length for uncompressed IDAT data" );
25462599 file_acc.parse = NULL ;
25472600 std::string compressed ((char *)&file_acc.file_buffer [file_acc.file_pos ], ::g->length ());
2548- for (int l = 0 ; l < 10 ; ++l)
2549- if (compress_data (data, l) == compressed) {
2601+ int cinfo = (unsigned ) compressed[0 ] >> 4 ;
2602+ if (0 <= cinfo && cinfo <= 7 )
2603+ windowBits = cinfo + 8 ;
2604+ for (int l = 0 ; l < 10 ; ++l) {
2605+ std::string candidate = compress_data (data, l, windowBits);
2606+ if (candidate == compressed) {
25502607 file_acc.parse = [l](unsigned char * file_buf) -> long long { return l + 1 ; };
25512608 break ;
25522609 }
2610+ }
25532611 assert_cond (!!file_acc.parse , " failed to find working compression level" );
25542612 }
25552613 int level = file_acc.rand_int (11 , file_acc.parse ) - 1 ;
2556- return compress_data (data, level);
2614+ file_acc.parse = NULL ;
2615+ if (!file_acc.generate ) {
2616+ file_acc.parse = [windowBits](unsigned char * file_buf) -> long long { return windowBits - 8 ; };
2617+ }
2618+ windowBits = file_acc.rand_int (8 , file_acc.parse ) + 8 ;
2619+ return compress_data (data, level, windowBits);
25572620}
25582621
25592622
0 commit comments