diff --git a/png.h b/png.h index 5d69f0fd1..1af4f12bc 100644 --- a/png.h +++ b/png.h @@ -1060,6 +1060,13 @@ PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structp png_ptr)); PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structp png_ptr)); #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16 bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structp png_ptr)); +#endif + #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ PNG_EXPORT(30, void, png_set_bgr, (png_structp png_ptr)); @@ -2271,7 +2278,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); * scripts/symbols.def as well. */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(220); + PNG_EXPORT_LAST_ORDINAL(221); #endif #ifdef __cplusplus diff --git a/pngpriv.h b/pngpriv.h index b6f382e54..57dff38d6 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -286,7 +286,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_QUANTIZE 0x0040 #define PNG_BACKGROUND 0x0080 #define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ #define PNG_16_TO_8 0x0400 #define PNG_RGBA 0x0800 #define PNG_EXPAND 0x1000 @@ -875,6 +875,11 @@ PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, png_bytep row, png_const_color_16p trans_color)); #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED +PNG_EXTERN void png_do_expand_16 PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + /* The following decodes the appropriate chunks, and does error correction, * then calls the appropriate callback for the chunk if it is valid. */ diff --git a/pngrtran.c b/pngrtran.c index 0ab3d8fd5..d3aa72f66 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -137,6 +137,7 @@ png_set_strip_16(png_structp png_ptr) return; png_ptr->transformations |= PNG_16_TO_8; + png_ptr->transformations &= ~PNG_EXPAND_16; } #endif @@ -686,6 +687,25 @@ png_set_tRNS_to_alpha(png_structp png_ptr) } #endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16 bit channels, expand the tRNS chunk too (because otherwise + * it may not work correctly.) + */ +void PNGAPI +png_set_expand_16(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand_16"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->transformations &= ~PNG_16_TO_8; + + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif + #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED void PNGAPI png_set_gray_to_rgb(png_structp png_ptr) @@ -1285,6 +1305,14 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + #ifdef PNG_READ_BACKGROUND_SUPPORTED if (png_ptr->transformations & PNG_BACKGROUND) { @@ -1445,14 +1473,17 @@ png_do_read_transformations(png_structp png_ptr) (png_ptr->transformations & PNG_EXPAND_tRNS)) png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, &(png_ptr->trans_color)); - else + else png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, NULL); } } #endif + /* Delay the 'expand 16' step until later for efficiency - so that the + * intermediate steps work with 8 bit data. */ + #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) && (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA || @@ -1567,6 +1598,16 @@ png_do_read_transformations(png_structp png_ptr) } #endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if (png_ptr->transformations & PNG_EXPAND_16) + png_do_expand_16(&png_ptr->row_info, png_ptr->row_buf + 1); +#endif + #ifdef PNG_READ_INVERT_SUPPORTED if (png_ptr->transformations & PNG_INVERT_MONO) png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); @@ -1594,6 +1635,9 @@ png_do_read_transformations(png_structp png_ptr) #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /*NOTE: this must be in the wrong place - what happens if BGR is set too? + * Need pngvalid to test this combo. + */ /* If gray -> RGB, do so now only if we did not do so above */ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) @@ -4066,6 +4110,37 @@ png_do_expand(png_row_infop row_info, png_bytep row, } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* If the bit depth is 8 and the colour type is not a palette type expand the + * whole row to 16 bits. Has no effect otherwise. + */ +void /* PRIVATE */ +png_do_expand_16(png_row_infop row_info, png_bytep row) +{ + if (row_info->bit_depth == 8 && + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + /* The row have a sequence of bytes containing [0..255] and we need + * to turn it into another row containing [0..65535], to do this we + * calculate: + * + * (input / 255) * 65535 + * + * Which happens to be exactly input * 257 and this can be achieved + * simply by byte replication in place (copying backwards). + */ + png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ + png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ + while (dp > sp) + dp[-2] = dp[-1] = *--sp, dp -= 2; + + row_info->rowbytes *= 2; + row_info->bit_depth = 16; + row_info->pixel_depth = (png_byte)(row_info->channels * 16); + } +} +#endif + #ifdef PNG_READ_QUANTIZE_SUPPORTED void /* PRIVATE */ png_do_quantize(png_row_infop row_info, png_bytep row, diff --git a/pngrutil.c b/pngrutil.c index 4c3cd5381..09b821bca 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -3463,6 +3463,24 @@ png_read_start_row(png_structp png_ptr) } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND_16) + { +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; + } +#endif + #ifdef PNG_READ_FILLER_SUPPORTED if (png_ptr->transformations & (PNG_FILLER)) { diff --git a/pngvalid.c b/pngvalid.c index 417d71b4a..ff78b224b 100644 --- a/pngvalid.c +++ b/pngvalid.c @@ -4465,6 +4465,48 @@ image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this, } IT(expand_gray_1_2_4_to_8, expand); +/* png_set_expand_16 */ +static void +image_transform_png_set_expand_16_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_expand_16(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this, + image_pixel *that, png_structp pp, PNG_CONST transform_display *display) +{ + /* Expect expand_16 to expand everything to 16 bits as a result of also + * causing 'expand' to happen. + */ + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that, &display->this); + + if (that->have_tRNS) + image_pixel_add_alpha(that, &display->this); + + if (that->bit_depth < 16) + that->sample_depth = that->bit_depth = 16; + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_expand_16_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(colour_type) + + this->next = *that; + *that = this; + + /* expand_16 does something unless the bit depth is already 16. */ + return bit_depth < 16; +} + +IT(expand_16, expand_gray_1_2_4_to_8); /* png_set_strip_16 */ static void @@ -4516,7 +4558,7 @@ image_transform_png_set_strip_16_add(image_transform *this, return bit_depth > 8; } -IT(strip_16, expand_gray_1_2_4_to_8); +IT(strip_16, expand_16); /* png_set_strip_alpha */ static void diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index 9fe0d6030..26afef866 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -304,6 +304,7 @@ option READ_TRANSFORMS requires READ = NO_READ_TRANSFORMS READ_TRANSFORMS_NOT_SUPPORTED option READ_EXPAND requires READ_TRANSFORMS +option READ_EXPAND_16 requires READ_TRANSFORMS READ_16BIT enables READ_EXPAND option READ_SHIFT requires READ_TRANSFORMS option READ_PACK requires READ_TRANSFORMS option READ_BGR requires READ_TRANSFORMS diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt index de1c4d363..142e90ec3 100644 --- a/scripts/pnglibconf.h.prebuilt +++ b/scripts/pnglibconf.h.prebuilt @@ -118,7 +118,6 @@ #define PNG_WRITE_tEXt_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_pCAL_SUPPORTED -#define PNG_READ_EXPAND_SUPPORTED #define PNG_WRITE_sPLT_SUPPORTED #define PNG_READ_SWAP_SUPPORTED #define PNG_READ_tIME_SUPPORTED @@ -155,6 +154,7 @@ #define PNG_tRNS_SUPPORTED #define PNG_WRITE_iTXt_SUPPORTED #define PNG_oFFs_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED #define PNG_USER_TRANSFORM_PTR_SUPPORTED #define PNG_hIST_SUPPORTED #define PNG_iCCP_SUPPORTED @@ -164,6 +164,7 @@ #define PNG_pCAL_SUPPORTED #define PNG_CHECK_cHRM_SUPPORTED #define PNG_tIME_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED #define PNG_pHYs_SUPPORTED #define PNG_READ_iTXt_SUPPORTED #define PNG_TEXT_SUPPORTED diff --git a/scripts/symbols.def b/scripts/symbols.def index 493dc9a19..900e480b4 100644 --- a/scripts/symbols.def +++ b/scripts/symbols.def @@ -226,3 +226,4 @@ EXPORTS png_get_current_pass_number @218 png_process_data_pause @219 png_process_data_skip @220 + png_set_expand_16 @221