| |
| /* pngrtran.c - transforms the data in a row for PNG readers |
| * |
| * Last changed in libpng 1.7.0 [(PENDING RELEASE)] |
| * Copyright (c) 1998-2015 Glenn Randers-Pehrson |
| * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) |
| * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) |
| * |
| * This code is released under the libpng license. |
| * For conditions of distribution and use, see the disclaimer |
| * and license in png.h |
| * |
| * This file contains functions optionally called by an application |
| * in order to tell libpng how to handle data when reading a PNG. |
| * Transformations that are used in both reading and writing are |
| * in pngtrans.c. |
| */ |
| |
| #include "pngpriv.h" |
| #define PNG_SRC_FILE PNG_SRC_FILE_pngrtran |
| |
| #ifdef PNG_READ_QUANTIZE_SUPPORTED |
| typedef struct |
| { |
| png_transform tr; |
| png_byte map[256U]; /* Map of palette values */ |
| png_byte lut[1U << /* LUT for RGB values */ |
| (PNG_QUANTIZE_RED_BITS+PNG_QUANTIZE_GREEN_BITS+PNG_QUANTIZE_BLUE_BITS)]; |
| } png_transform_quantize; |
| |
| #define PNG_QUANTIZE_MAP 1U /* map is present and not a 1:1 mapping */ |
| #define PNG_QUANTIZE_LUT 2U /* lut has been built */ |
| |
| static void |
| do_quantize_rgb(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_quantize *tr = png_transform_cast(png_transform_quantize, |
| *transform); |
| unsigned int channels = PNG_TC_CHANNELS(*tc); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - channels/*safety*/; |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| affirm(tc->bit_depth == 8 && (channels == 3 || channels == 4) && |
| !(tc->format & PNG_FORMAT_FLAG_SWAPPED) && |
| (tr->tr.args & PNG_QUANTIZE_LUT) != 0); |
| |
| tc->sp = dp; |
| tc->format |= PNG_FORMAT_FLAG_COLORMAP; |
| |
| while (sp <= ep) |
| { |
| unsigned int r = sp[0]; |
| unsigned int g = sp[1]; |
| unsigned int b = sp[2]; |
| |
| /* This looks real messy, but the compiler will reduce |
| * it down to a reasonable formula. For example, with |
| * 5 bits per color, we get: |
| * p = (((r >> 3) & 0x1f) << 10) | |
| * (((g >> 3) & 0x1f) << 5) | |
| * ((b >> 3) & 0x1f); |
| */ |
| *dp++ = tr->lut[(((r >> (8 - PNG_QUANTIZE_RED_BITS)) & |
| ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << |
| (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | |
| (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & |
| ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << |
| (PNG_QUANTIZE_BLUE_BITS)) | |
| ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & |
| ((1 << PNG_QUANTIZE_BLUE_BITS) - 1))]; |
| |
| sp += channels; |
| } |
| |
| affirm(sp == ep+channels); |
| UNTESTED |
| # undef png_ptr |
| } |
| |
| static void |
| do_quantize_pal(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_quantize *tr = png_transform_cast(png_transform_quantize, |
| *transform); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| affirm(tc->bit_depth == 8 && (tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0 && |
| !(tc->format & PNG_FORMAT_FLAG_SWAPPED) && |
| (tr->tr.args & PNG_QUANTIZE_MAP) != 0); |
| |
| tc->sp = dp; |
| |
| while (sp < ep) |
| *dp++ = tr->map[*sp++]; |
| |
| UNTESTED |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_quantize(png_transformp *transform, png_transform_controlp tc) |
| { |
| if (tc->bit_depth == 8 && (tc->format & PNG_FORMAT_FLAG_COLOR) != 0) |
| { |
| /* Either colormapped input, RGB or RGBA: */ |
| if (!(tc->format & PNG_FORMAT_FLAG_COLORMAP)) /* RGB, RGBA */ |
| { |
| /* This must be a 'palette' lookup */ |
| if (((*transform)->args & PNG_QUANTIZE_LUT) != 0) |
| { |
| /* This changes the format and invalidates pretty much everything in |
| * the info struct: |
| */ |
| tc->format |= PNG_FORMAT_FLAG_COLORMAP; |
| |
| if (tc->init == PNG_TC_INIT_FINAL) |
| { |
| (*transform)->fn = do_quantize_rgb; |
| tc->invalid_info |= PNG_INFO_tRNS+PNG_INFO_hIST+PNG_INFO_pCAL+ |
| PNG_INFO_sBIT+PNG_INFO_bKGD; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(tc->png_ptr, tc->bit_depth); |
| } |
| |
| return; |
| } |
| } |
| |
| else /* colormapped */ |
| { |
| /* This must be a 'quantize' lookup */ |
| if (((*transform)->args & PNG_QUANTIZE_MAP) != 0) |
| { |
| /* This doesn't change the format, just the values: */ |
| if (tc->init == PNG_TC_INIT_FINAL) |
| { |
| (*transform)->fn = do_quantize_pal; |
| tc->invalid_info |= PNG_INFO_sBIT+PNG_INFO_pCAL; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(tc->png_ptr, tc->bit_depth); |
| } |
| |
| return; |
| } |
| } |
| } |
| |
| /* Else not applicable */ |
| (*transform)->fn = NULL; |
| } |
| |
| /* Dither file to 8-bit. Supply a palette, the current number |
| * of elements in the palette, the maximum number of elements |
| * allowed, and a histogram if possible. If the current number |
| * of colors is greater then the maximum number, the palette will be |
| * modified to fit in the maximum number. "full_quantize" indicates |
| * whether we need a quantizing cube set up for RGB images, or if we |
| * simply are reducing the number of colors in a paletted image. |
| */ |
| typedef struct png_dsort_struct |
| { |
| struct png_dsort_struct * next; |
| png_byte left; |
| png_byte right; |
| } png_dsort; |
| typedef png_dsort * png_dsortp; |
| typedef png_dsort * * png_dsortpp; |
| |
| static void |
| init_map(png_bytep map) |
| /* Initialize a mapping table to be 1:1 */ |
| { |
| png_byte b = 0U; |
| |
| do |
| map[b] = b; |
| while (b++ != 255U); |
| } |
| |
| /* Save typing and make code easier to understand */ |
| #define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ |
| abs((int)((c1).green) - (int)((c2).green)) + \ |
| abs((int)((c1).blue) - (int)((c2).blue))) |
| |
| void PNGAPI |
| png_set_quantize(png_structrp png_ptr, png_colorp palette, |
| int num_palette, int maximum_colors, png_const_uint_16p histogram, |
| int full_quantize) |
| { |
| png_debug(1, "in png_set_quantize"); |
| |
| if (png_ptr != NULL) |
| { |
| png_transform_quantize *tr = png_transform_cast(png_transform_quantize, |
| png_add_transform(png_ptr, sizeof (png_transform_quantize), |
| png_init_quantize, PNG_TR_QUANTIZE)); |
| |
| /* This is weird (consider what happens to png_set_background on a palette |
| * image with a tRNS chunk). |
| */ |
| if (palette == png_ptr->palette) |
| png_app_warning(png_ptr, "png_set_quantize: PLTE will be damaged"); |
| |
| if (maximum_colors <= 0 || num_palette > 256) |
| { |
| /* The spuriously allocated transform will be removed by the init |
| * code. |
| */ |
| png_app_error(png_ptr, "png_set_quantize: invalid color count"); |
| return; |
| } |
| |
| /* The app passed in a palette with too many colors, it's not clear why |
| * libpng is providing this functionality, it's nothing to do with PNG and |
| * can be done by the application without any PNG specific knowledge. |
| */ |
| if (num_palette > maximum_colors) |
| { |
| int map_changed = 0; |
| |
| /* The map table must be preset to do no mapping initially: */ |
| init_map(tr->map); |
| |
| if (histogram != NULL) |
| { |
| /* This is easy enough, just throw out the least used colors. |
| * Perhaps not the best solution, but good enough. |
| */ |
| int i; |
| png_byte quantize_sort[256U]; |
| |
| /* Initialize an array to sort colors */ |
| init_map(quantize_sort); |
| |
| /* Find the least used palette entries by starting a |
| * bubble sort, and running it until we have sorted |
| * out enough colors. Note that we don't care about |
| * sorting all the colors, just finding which are |
| * least used. |
| */ |
| for (i = num_palette - 1; i >= maximum_colors; i--) |
| { |
| int done; /* To stop early if the list is pre-sorted */ |
| int j; |
| |
| done = 1; |
| for (j = 0; j < i; j++) |
| { |
| if (histogram[quantize_sort[j]] < |
| histogram[quantize_sort[j+1]]) |
| { |
| png_byte t = quantize_sort[j]; |
| quantize_sort[j] = quantize_sort[j+1]; |
| quantize_sort[j+1] = t; |
| done = 0; |
| } |
| } |
| |
| if (done != 0) |
| break; |
| } |
| |
| /* Swap the palette around, and set up a table, if necessary */ |
| if (full_quantize) |
| { |
| int j = num_palette; |
| |
| /* Put all the useful colors within the max, but don't |
| * move the others. |
| * |
| * NOTE: if the app passes in the result of png_get_PLTE it will |
| * be overwritten at this point, what is the API? |
| */ |
| for (i = 0; i < maximum_colors; i++) |
| { |
| if (quantize_sort[i] >= maximum_colors) |
| { |
| do |
| j--; |
| while (quantize_sort[j] >= maximum_colors); |
| |
| /* NOTE: NOT swapped, so the original palette[i] has been |
| * lost. |
| */ |
| palette[i] = palette[j]; |
| } |
| } |
| } |
| |
| else /* !full_quantize */ |
| { |
| int j = num_palette; |
| |
| /* Move all the used colors inside the max limit, and |
| * develop a translation table. |
| */ |
| for (i = 0; i < maximum_colors; i++) |
| { |
| /* Only move the colors we need to */ |
| if (quantize_sort[i] >= maximum_colors) |
| { |
| png_color tmp_color; |
| |
| do |
| j--; |
| while (quantize_sort[j] >= maximum_colors); |
| |
| tmp_color = palette[j]; |
| palette[j] = palette[i]; |
| palette[i] = tmp_color; |
| /* Indicate where the color went */ |
| tr->map[j] = png_check_byte(png_ptr, i); |
| tr->map[i] = png_check_byte(png_ptr, j); |
| map_changed = 1; |
| } |
| } |
| |
| /* Find closest color for those colors we are not using */ |
| for (i = 0; i < num_palette; i++) |
| { |
| if (tr->map[i] >= maximum_colors) |
| { |
| int min_d, k, min_k, d_index; |
| |
| /* Find the closest color to one we threw out */ |
| d_index = tr->map[i]; |
| min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); |
| for (k = 1, min_k = 0; k < maximum_colors; k++) |
| { |
| int d; |
| |
| d = PNG_COLOR_DIST(palette[d_index], palette[k]); |
| |
| if (d < min_d) |
| { |
| min_d = d; |
| min_k = k; |
| } |
| } |
| |
| /* Point to closest color */ |
| tr->map[i] = png_check_byte(png_ptr, min_k); |
| map_changed = 1; |
| } |
| } |
| } /* !full_quantize */ |
| } /* have a histogram */ |
| |
| else /* no histogram */ |
| { |
| /* This is much harder to do simply (and quickly). Perhaps |
| * we need to go through a median cut routine, but those |
| * don't always behave themselves with only a few colors |
| * as input. So we will just find the closest two colors, |
| * and throw out one of them (chosen somewhat randomly). |
| * [We don't understand this at all, so if someone wants to |
| * work on improving it, be our guest - AED, GRP] |
| */ |
| int max_d; |
| int num_new_palette; |
| png_byte index_to_palette[256U]; |
| png_byte palette_to_index[256U]; |
| png_dsortp hash[769]; |
| |
| /* Initialize palette index sort arrays */ |
| init_map(index_to_palette); |
| init_map(palette_to_index); |
| memset(hash, 0, sizeof hash); |
| num_new_palette = num_palette; |
| |
| /* Initial wild guess at how far apart the farthest pixel |
| * pair we will be eliminating will be. Larger |
| * numbers mean more areas will be allocated, Smaller |
| * numbers run the risk of not saving enough data, and |
| * having to do this all over again. |
| * |
| * I have not done extensive checking on this number. |
| */ |
| max_d = 96; |
| |
| while (num_new_palette > maximum_colors) |
| { |
| int i; |
| png_dsortp t = NULL; |
| |
| for (i = 0; i < num_new_palette - 1; i++) |
| { |
| int j; |
| |
| for (j = i + 1; j < num_new_palette; j++) |
| { |
| int d = PNG_COLOR_DIST(palette[i], palette[j]); |
| |
| if (d <= max_d) |
| { |
| |
| t = png_voidcast(png_dsortp, png_malloc_warn(png_ptr, |
| sizeof (*t))); |
| |
| if (t == NULL) |
| break; |
| |
| t->next = hash[d]; |
| t->left = png_check_byte(png_ptr, i); |
| t->right = png_check_byte(png_ptr, j); |
| hash[d] = t; |
| } |
| } |
| if (t == NULL) |
| break; |
| } |
| |
| if (t != NULL) for (i = 0; i <= max_d; i++) |
| { |
| if (hash[i] != NULL) |
| { |
| png_dsortp p; |
| |
| for (p = hash[i]; p != NULL; p = p->next) |
| { |
| if (index_to_palette[p->left] < num_new_palette && |
| index_to_palette[p->right] < num_new_palette) |
| { |
| int j, next_j; |
| |
| if (num_new_palette & 0x01) |
| { |
| j = p->left; |
| next_j = p->right; |
| } |
| else |
| { |
| j = p->right; |
| next_j = p->left; |
| } |
| |
| num_new_palette--; |
| /* NOTE: overwrites palette */ |
| palette[index_to_palette[j]] = |
| palette[num_new_palette]; |
| |
| if (full_quantize == 0) |
| { |
| int k; |
| |
| for (k = 0; k < num_palette; k++) |
| { |
| if (tr->map[k] == index_to_palette[j]) |
| { |
| tr->map[k] = index_to_palette[next_j]; |
| map_changed = 1; |
| } |
| |
| if (tr->map[k] == num_new_palette) |
| { |
| tr->map[k] = index_to_palette[j]; |
| map_changed = 1; |
| } |
| } |
| } |
| |
| index_to_palette[palette_to_index[num_new_palette]] = |
| index_to_palette[j]; |
| |
| palette_to_index[index_to_palette[j]] = |
| palette_to_index[num_new_palette]; |
| |
| index_to_palette[j] = |
| png_check_byte(png_ptr, num_new_palette); |
| |
| palette_to_index[num_new_palette] = |
| png_check_byte(png_ptr, j); |
| } |
| |
| if (num_new_palette <= maximum_colors) |
| break; |
| } |
| |
| if (num_new_palette <= maximum_colors) |
| break; |
| } |
| } |
| |
| for (i = 0; i < 769; i++) |
| { |
| if (hash[i] != NULL) |
| { |
| png_dsortp p = hash[i]; |
| |
| while (p) |
| { |
| t = p->next; |
| png_free(png_ptr, p); |
| p = t; |
| } |
| |
| hash[i] = NULL; |
| } |
| } |
| |
| max_d += 96; |
| } /* while num_new_colors > maximum_colors */ |
| } /* no histogram */ |
| |
| num_palette = maximum_colors; |
| |
| if (map_changed) /* else the map is 1:1 */ |
| tr->tr.args |= PNG_QUANTIZE_MAP; |
| } /* num_palette > maximum_colors */ |
| |
| /* The palette has been reduced to the requested number of colors if it |
| * was over maximum colors before. |
| */ |
| |
| /* TODO: what is this? Apparently the png_struct::palette member gets |
| * updated if it didn't originally have a palette, but the update relies |
| * on the app not freeing the passed in palette. |
| */ |
| if (png_ptr->palette == NULL) |
| png_ptr->palette = palette; |
| |
| png_ptr->num_palette = png_check_bits(png_ptr, num_palette, 9); |
| |
| if (full_quantize) |
| { |
| int i; |
| png_byte distance[1U << (PNG_QUANTIZE_RED_BITS+PNG_QUANTIZE_GREEN_BITS+ |
| PNG_QUANTIZE_BLUE_BITS)]; |
| |
| memset(distance, 0xff, sizeof distance); |
| |
| for (i = 0; i < num_palette; i++) |
| { |
| int ir; |
| int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); |
| int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); |
| int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); |
| |
| for (ir = 0; ir < (1<<PNG_QUANTIZE_RED_BITS); ir++) |
| { |
| /* int dr = abs(ir - r); */ |
| int ig; |
| int dr = ((ir > r) ? ir - r : r - ir); |
| int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + |
| PNG_QUANTIZE_GREEN_BITS)); |
| |
| for (ig = 0; ig < (1<<PNG_QUANTIZE_GREEN_BITS); ig++) |
| { |
| /* int dg = abs(ig - g); */ |
| int ib; |
| int dg = ((ig > g) ? ig - g : g - ig); |
| int dt = dr + dg; |
| int dm = ((dr > dg) ? dr : dg); |
| int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); |
| |
| for (ib = 0; ib < (1<<PNG_QUANTIZE_BLUE_BITS); ib++) |
| { |
| int d_index = index_g | ib; |
| /* int db = abs(ib - b); */ |
| int db = ((ib > b) ? ib - b : b - ib); |
| int dmax = ((dm > db) ? dm : db); |
| int d = dmax + dt + db; |
| |
| if (d < distance[d_index]) |
| { |
| distance[d_index] = png_check_byte(png_ptr, d); |
| tr->lut[d_index] = png_check_byte(png_ptr, i); |
| } |
| } /* for blue */ |
| } /* for green */ |
| } /* for red */ |
| } /* num_palette */ |
| } /* full_quantize */ |
| } /* png_ptr != NULL */ |
| } |
| #endif /* READ_QUANTIZE */ |
| |
| #ifdef PNG_READ_PACK_SUPPORTED |
| /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, |
| * without changing the actual values. Thus, if you had a row with |
| * a bit depth of 1, you would end up with bytes that only contained |
| * the numbers 0 or 1. If you would rather they contain 0 and 255, use |
| * png_set_expand_gray_1_2_4_to_8 instead. |
| */ |
| static void |
| png_do_read_unpack(png_transformp *transform, png_transform_controlp tc) |
| { |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = png_voidcast(png_const_bytep, tc->dp); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| sp += PNG_TC_ROWBYTES(*tc) - 1; /* Start from end */ |
| dp += tc->width; /* output bit depth is 8 */ |
| |
| # define png_ptr (tc->png_ptr) |
| png_debug(1, "in png_do_unpack"); |
| |
| switch (tc->bit_depth) |
| { |
| case 1: |
| { |
| /* Because we copy from the last pixel down the shift required |
| * at the start is 8-pixels_in_last_byte, which is just: |
| */ |
| unsigned int shift = 7U & -tc->width; |
| |
| while (dp > ep) |
| { |
| *--dp = (*sp >> shift) & 1U; |
| shift = 7U & (shift+1U); |
| if (shift == 0U) |
| --sp; |
| } |
| |
| debug(shift == 0U); |
| break; |
| } |
| |
| case 2: |
| { |
| unsigned int shift = 7U & -(tc->width << 1); |
| |
| while (dp > ep) |
| { |
| *--dp = (*sp >> shift) & 3U; |
| shift = 7U & (shift+2U); |
| if (shift == 0U) |
| --sp; |
| } |
| |
| debug(shift == 0U); |
| break; |
| } |
| |
| case 4: |
| { |
| unsigned int shift = 7U & -(tc->width << 2); |
| |
| while (dp > ep) |
| { |
| *--dp = (*sp >> shift) & 15U; |
| shift = 7U & (shift+4U); |
| if (shift == 0U) |
| --sp; |
| } |
| |
| debug(shift == 0U); |
| break; |
| } |
| |
| default: |
| impossible("bit depth"); |
| } |
| |
| debug(dp == ep && sp == png_upcast(png_const_bytep, tc->sp)-1U); |
| tc->sp = dp; |
| |
| if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U) |
| { |
| tc->range++; |
| tc->format |= PNG_FORMAT_FLAG_RANGE; |
| } |
| |
| tc->bit_depth = 8U; |
| PNG_UNUSED(transform) |
| # undef png_ptr |
| } |
| |
| /* Called from the curiously named png_set_packing API in pngtrans.c; the read |
| * and write code is separated because read 'unpacks' (from PNG format) and |
| * write 'packs' (to PNG format.) |
| */ |
| void /* PRIVATE */ |
| png_init_read_pack(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr tc->png_ptr |
| debug(tc->init); |
| |
| if (tc->bit_depth < 8) /* else no packing/unpacking */ |
| { |
| /* For indexed images the pack operation does not invalidate the range; in |
| * fact the corresponding shift operation would! |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U) |
| { |
| tc->range++; |
| tc->format |= PNG_FORMAT_FLAG_RANGE; |
| } |
| |
| tc->bit_depth = 8U; |
| |
| if (tc->init == PNG_TC_INIT_FINAL) |
| (*transform)->fn = png_do_read_unpack/* sic: it unpacks */; |
| } |
| |
| else /* the transform is not applicable */ |
| (*transform)->fn = NULL; |
| |
| # undef png_ptr |
| } |
| #endif /* READ_PACK */ |
| |
| #if defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| static unsigned int |
| fill_transparent_pixel(png_const_structrp png_ptr, png_byte *trans) |
| /* Fill a byte array according to the transparent pixel value and return a |
| * count of the number of bytes. Low bit depth gray values are replicated in |
| * the first byte. Writes from 1 to 6 bytes. |
| */ |
| { |
| /* There must be a tRNS chunk and this must not be a palette image: */ |
| debug(png_ptr->num_trans == 1 && |
| !(png_ptr->color_type & (PNG_COLOR_MASK_ALPHA+PNG_COLOR_MASK_PALETTE))); |
| |
| if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* gray */ |
| { |
| unsigned int t = png_ptr->trans_color.gray; |
| unsigned int depth = png_ptr->bit_depth; |
| |
| if (depth < 16U) |
| { |
| /* ISO PNG 11.3.2.1 "tRNS Transparency": "If the image bit depth is |
| * less than 16, the least significant bits are used and the others are |
| * 0." So mask out the upper bits. |
| */ |
| t &= (1U<<depth)-1U; |
| |
| /* And replicate low bit-depth values across the byte: */ |
| while (depth < 8U) |
| { |
| t |= t << depth; |
| depth <<= 1; |
| } |
| |
| trans[0] = PNG_BYTE(t); |
| return 1U; |
| } |
| |
| /* Else a 16 bit value: */ |
| trans[0] = PNG_BYTE(t >> 8); |
| trans[1] = PNG_BYTE(t); |
| return 2U; |
| } |
| |
| else /* color */ switch (png_ptr->bit_depth) |
| { |
| case 8: /* 8-bit RGB */ |
| trans[0] = PNG_BYTE(png_ptr->trans_color.red); |
| trans[1] = PNG_BYTE(png_ptr->trans_color.green); |
| trans[2] = PNG_BYTE(png_ptr->trans_color.blue); |
| return 3U; |
| |
| case 16: /* 16-bit RGB */ |
| trans[0] = PNG_BYTE(png_ptr->trans_color.red >> 8); |
| trans[1] = PNG_BYTE(png_ptr->trans_color.red); |
| trans[2] = PNG_BYTE(png_ptr->trans_color.green >> 8); |
| trans[3] = PNG_BYTE(png_ptr->trans_color.green); |
| trans[4] = PNG_BYTE(png_ptr->trans_color.blue >> 8); |
| trans[5] = PNG_BYTE(png_ptr->trans_color.blue); |
| return 6U; |
| |
| default: |
| NOT_REACHED; |
| return 0U; /* safe */ |
| } |
| } |
| # endif /* READ_tRNS */ |
| #endif /* READ_EXPAND || READ_BACKGROUND */ |
| |
| #ifdef PNG_READ_EXPAND_SUPPORTED |
| /* Flags for png_init_expand */ |
| #define PNG_EXPAND_PALETTE 1U /* palette images only, includes tRNS */ |
| #define PNG_EXPAND_LBD_GRAY 2U /* grayscale low-bit depth only */ |
| #define PNG_EXPAND_tRNS 4U /* non-palette images only */ |
| |
| /* This struct is only required for tRNS matching, but it is convenient to |
| * allocated it anyway even if READ_tRNS is not supported. |
| */ |
| typedef struct |
| { |
| png_transform tr; |
| unsigned int ntrans; /* number of bytes below */ |
| png_byte transparent_pixel[6]; /* the transparent pixel value */ |
| } png_expand; |
| |
| #ifdef PNG_READ_tRNS_SUPPORTED |
| /* Look for colors matching the trans_color in png_ptr, low bit depth gray is |
| * covered below so this only need handle 8 abd 16-bit channels. |
| */ |
| static void |
| png_do_expand_tRNS(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_expand *tr = png_transform_cast(png_expand, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp; |
| const unsigned int spixel_size = PNG_TC_PIXEL_DEPTH(*tc) >> 3; |
| unsigned int alpha_size; |
| |
| /* We expect opaque and transparent pixels to be interleaved but with long |
| * sequences of each. Because we are adding an alpha channel we must copy |
| * down. |
| */ |
| debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA)); |
| debug(spixel_size == tr->ntrans); |
| sp += PNG_TC_ROWBYTES(*tc); |
| tc->sp = dp; |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| tc->invalid_info |= PNG_INFO_tRNS; |
| tc->transparent_alpha = 1U; |
| alpha_size = (PNG_TC_PIXEL_DEPTH(*tc)>>3) - spixel_size; |
| debug(alpha_size == 1 || alpha_size == 2); |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| do |
| { |
| unsigned int i = spixel_size; |
| png_byte alpha = 0U; |
| |
| dp -= alpha_size; |
| alpha = 0U; |
| |
| /* Copy and check one source pixel (backwards, to avoid any |
| * overwrite): |
| */ |
| do if ((*--dp = *--sp) != tr->transparent_pixel[--i]) /* pixel != tRNS */ |
| alpha = 0xFFU; |
| while (i != 0U); |
| |
| /* i == 0 */ |
| do |
| dp[spixel_size + i] = alpha; |
| while (++i < alpha_size); |
| } while (sp > ep); |
| |
| debug(sp == ep && dp == tc->dp); /* else overwrite */ |
| # undef png_ptr |
| } |
| #endif /* READ_tRNS */ |
| |
| /* Expand grayscale images of less than 8-bit depth to 8 bits. |
| * libpng 1.7.0: this no longer expands everything, it just expands the low bit |
| * depth gray row. It does *NOT* expand the tRNS into an alpha channel unless |
| * it is told to do so. |
| * |
| * API CHANGE: the function now does what it was always meant to do. |
| * |
| * This is like do_unpack except that the packed data is expanded to the full |
| * 8-bit range; scaled up. This is not a good thing to do on an indexed image; |
| * the indices will be invalid. |
| * |
| * The tRNS handling is included here too; speed is not important because the |
| * result will always be cached unless the PNG is very small. |
| */ |
| static void |
| png_do_expand_lbd_gray(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| const png_const_bytep ep = dp; |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const unsigned int bit_depth = tc->bit_depth; |
| # ifdef PNG_READ_sBIT_SUPPORTED |
| unsigned int insignificant_bits = 0U; |
| # endif /* READ_sBIT */ |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| unsigned int gray = 0xffffU; /* doesn't match anything */ |
| unsigned int do_alpha = 0U; |
| # endif /* READ_tRNS */ |
| |
| sp += PNG_TC_ROWBYTES(*tc); /* last byte +1 */ |
| tc->bit_depth = 8U; |
| tc->invalid_info |= PNG_INFO_tRNS; |
| # ifdef PNG_READ_sBIT_SUPPORTED |
| if (bit_depth > 1U /* irrelevant for bit depth 1 */ && |
| !(tc->invalid_info & PNG_INFO_sBIT) && |
| tc->sBIT_G > 0U/*SAFETY*/ && tc->sBIT_G < bit_depth) |
| insignificant_bits = bit_depth - tc->sBIT_G; |
| # endif /* READ_sBIT */ |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (((*transform)->args & PNG_EXPAND_tRNS) != 0) |
| { |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| tc->transparent_alpha = 1U; |
| gray = png_ptr->trans_color.gray & ((1U << bit_depth)-1U); |
| do_alpha = 1U; |
| } |
| |
| /* This helps avoid cluttering the code up with #ifdefs: */ |
| # define check_tRNS if (do_alpha) *--dp = (pixel != gray) * 255U; |
| # else /* !READ_tRNS */ |
| # define check_tRNS |
| # endif /* READ_tRNS */ |
| |
| dp += PNG_TC_ROWBYTES(*tc); /* pre-decremented below */ |
| |
| switch (bit_depth) |
| { |
| case 1: |
| { |
| unsigned int shift = 7U & -tc->width; |
| unsigned int s = *--sp; |
| |
| for(;;) |
| { |
| if (shift == 8U) s = *--sp, shift = 0; |
| |
| { |
| const unsigned int pixel = (s >> shift) & 1U; |
| |
| check_tRNS |
| *--dp = PNG_BYTE(pixel * 255U); |
| if (dp <= ep) break; |
| } |
| ++shift; |
| } |
| |
| debug(dp == ep && shift == 7U && sp == tc->sp); |
| break; |
| } |
| |
| case 2: |
| { |
| unsigned int shift = 7U & -(tc->width << 1)/*overflow ok*/; |
| unsigned int s = *--sp; |
| |
| for (;;) |
| { |
| if (shift == 8U) s = *--sp, shift = 0; |
| { |
| const unsigned int pixel = (s >> shift) & 3U; |
| |
| check_tRNS |
| |
| # ifdef PNG_READ_sBIT_SUPPORTED |
| /* 'sig_bits' must be 1 or 2 leaving insignificant_bits 0 or |
| * 1. This may look silly but it allows a compact representation |
| * of 1 bit gray + 1 bit alpha (transparency): |
| */ |
| if (insignificant_bits /* only 1 bit significant */) |
| *--dp = PNG_BYTE((pixel >> 1) * 255U); |
| |
| else |
| # endif |
| *--dp = PNG_BYTE(pixel * 85U); |
| |
| if (dp <= ep) break; |
| } |
| shift += 2U; |
| } |
| |
| debug(dp == ep && shift == 6U && sp == tc->sp); |
| break; |
| } |
| |
| case 4: |
| { |
| unsigned int shift = 7U & -(tc->width << 2)/*overflow ok*/; |
| unsigned int s = *--sp; |
| # ifdef PNG_READ_sBIT_SUPPORTED |
| const unsigned int div = (1U << (4U-insignificant_bits)) - 1U; |
| # endif |
| |
| for (;;) |
| { |
| if (shift == 8U) s = *--sp, shift = 0; |
| { |
| unsigned int pixel = (s >> shift) & 15U; |
| |
| check_tRNS |
| |
| # ifdef PNG_READ_sBIT_SUPPORTED |
| /* insignificant_bits may be 0, 1, 2 or 3, requiring a multiply |
| * by 17, 255/7, 85 or 255. Since this operation is always |
| * cached we don't much care about the time to do the divide |
| * below. |
| */ |
| if (insignificant_bits) |
| pixel = ((pixel>>insignificant_bits) * 255U + (div>>1)) / div; |
| |
| else |
| # endif |
| pixel *= 17U; |
| |
| *--dp = PNG_BYTE(pixel); |
| if (dp <= ep) break; |
| } |
| |
| shift += 4U; |
| } |
| |
| debug(dp == ep && shift == 4U && sp == tc->sp); |
| break; |
| } |
| |
| default: |
| impossible("bit depth"); |
| } |
| |
| tc->sp = ep; |
| |
| # undef check_tRNS |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_expand(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* The possible combinations are: |
| * |
| * 1) PALETTE: the 'palette' flag should be set on the transform control and |
| * all that need be done is cancel this to cause the cache code to do the |
| * expansion. |
| * |
| * 2) LBP_GRAY, LBP_GRAY+tRNS: use png_do_expand_lbd_gray to do the required |
| * expand. Can be cached. |
| * |
| * 3) tRNS: scan the row for the relevant tRNS value. |
| * |
| * Note that expanding 8 to 16 bits is a byte op in pngtrans.c (it just |
| * replicates bytes). |
| */ |
| if (tc->palette) |
| { |
| debug(tc->caching && !(tc->format & PNG_FORMAT_FLAG_COLORMAP)); |
| |
| if (((*transform)->args & PNG_EXPAND_PALETTE) != 0U) |
| { |
| tc->palette = 0U; |
| tc->invalid_info |= PNG_INFO_PLTE + PNG_INFO_tRNS; |
| tc->cost = PNG_CACHE_COST_LIMIT; /* the cache is required! */ |
| } |
| |
| /* Note that this needs to happen when the row is processed (!tc->init) as |
| * well. |
| */ |
| } |
| |
| else if (!(tc->format & PNG_FORMAT_FLAG_COLORMAP)) |
| { |
| png_uint_32 args = (*transform)->args & PNG_BIC_MASK(PNG_EXPAND_PALETTE); |
| unsigned int bit_depth = tc->bit_depth; |
| |
| debug(tc->init); |
| |
| if (bit_depth >= 8U) |
| args &= PNG_BIC_MASK(PNG_EXPAND_LBD_GRAY); |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (png_ptr->num_trans == 0U || |
| (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0U || |
| (tc->invalid_info & PNG_INFO_tRNS) != 0U) |
| # endif |
| args &= PNG_BIC_MASK(PNG_EXPAND_tRNS); |
| |
| (*transform)->args = args; |
| |
| switch (args) |
| { |
| case PNG_EXPAND_LBD_GRAY: |
| tc->bit_depth = 8U; |
| tc->invalid_info |= PNG_INFO_tRNS; |
| |
| if (tc->init == PNG_TC_INIT_FINAL) |
| (*transform)->fn = png_do_expand_lbd_gray; |
| break; |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| case PNG_EXPAND_LBD_GRAY + PNG_EXPAND_tRNS: |
| tc->bit_depth = 8U; |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| tc->invalid_info |= PNG_INFO_tRNS; |
| tc->transparent_alpha = 1U; |
| |
| /* In this case tRNS must be left unmodified for the expansion code |
| * to handle. |
| */ |
| if (tc->init == PNG_TC_INIT_FINAL) |
| (*transform)->fn = png_do_expand_lbd_gray; |
| break; |
| |
| case PNG_EXPAND_tRNS: |
| if (tc->init == PNG_TC_INIT_FINAL) |
| { |
| png_expand *tr = png_transform_cast(png_expand, *transform); |
| |
| affirm((tc->bit_depth == 8U || tc->bit_depth == 16U) && |
| (tc->format & |
| (PNG_FORMAT_FLAG_COLORMAP|PNG_FORMAT_FLAG_ALPHA)) == 0U); |
| |
| tr->ntrans = fill_transparent_pixel(png_ptr, |
| tr->transparent_pixel); |
| tr->tr.fn = png_do_expand_tRNS; |
| } /* TC_INIT_FINAL */ |
| |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| tc->invalid_info |= PNG_INFO_tRNS; |
| tc->transparent_alpha = 1U; |
| break; |
| # endif /* READ_tRNS */ |
| |
| default: /* transform not applicable */ |
| (*transform)->fn = NULL; |
| break; |
| } |
| |
| implies(tc->init == PNG_TC_INIT_FINAL, |
| (*transform)->fn != png_init_expand); |
| } |
| |
| else /* not applicable */ |
| { |
| debug(tc->init); |
| (*transform)->fn = NULL; |
| NOT_REACHED; |
| } |
| # undef png_ptr |
| } |
| |
| void PNGAPI |
| png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| png_add_transform(png_ptr, sizeof (png_expand), png_init_expand, |
| PNG_TR_EXPAND)->args |= PNG_EXPAND_LBD_GRAY; |
| } |
| |
| /* Expand paletted images to 8-bit RGB or, if there is a tRNS chunk, RGBA. |
| * Note that this is effectively handled by the read code palette optimizations. |
| * |
| * API CHANGE: this used to have the completely unexpected side effect of |
| * turning on the above two optimizations. |
| */ |
| void PNGAPI |
| png_set_palette_to_rgb(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| png_add_transform(png_ptr, sizeof (png_expand), png_init_expand, |
| PNG_TR_EXPAND)->args |= PNG_EXPAND_PALETTE; |
| } |
| |
| /* Expand paletted images to RGB, expand grayscale images of less than 8-bit |
| * depth to 8-bit depth, and expand tRNS chunks to alpha channels. I.e. all the |
| * above. |
| */ |
| void PNGAPI |
| png_set_expand(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| { |
| png_set_palette_to_rgb(png_ptr); |
| png_set_expand_gray_1_2_4_to_8(png_ptr); |
| png_set_tRNS_to_alpha(png_ptr); |
| } |
| } |
| #endif /* READ_EXPAND */ |
| |
| #if defined(PNG_READ_EXPAND_SUPPORTED) ||\ |
| defined(PNG_READ_STRIP_ALPHA_SUPPORTED) |
| |
| #define PNG_INIT_STRIP_ALPHA 1U |
| #define PNG_INIT_EXPAND_tRNS 2U |
| static void |
| png_init_alpha(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| int required = 0; |
| |
| # if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_tRNS_SUPPORTED) |
| if ((*transform)->args & PNG_INIT_EXPAND_tRNS) |
| { |
| /* Prior to 1.7 the alpha channel was stripped after expanding the tRNS |
| * chunk, so this effectively cancelled out the expand. |
| */ |
| if (png_ptr->num_trans > 0 && !tc->palette && |
| !((*transform)->args & PNG_INIT_STRIP_ALPHA)) |
| { |
| debug((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0); |
| |
| required = 1; |
| tc->expand_tRNS = 1U; |
| |
| /* This happens as a result of an explicit API call to |
| * png_set_tRNS_to_alpha, so expand low-bit-depth gray too: |
| */ |
| if (tc->init == PNG_TC_INIT_FORMAT) |
| png_add_transform(png_ptr, sizeof (png_expand), png_init_expand, |
| PNG_TR_EXPAND)->args |= PNG_EXPAND_tRNS + PNG_EXPAND_LBD_GRAY; |
| } |
| |
| else |
| (*transform)->args &= PNG_BIC_MASK(PNG_INIT_EXPAND_tRNS); |
| } |
| # endif /* READ_EXPAND && READ_tRNS */ |
| |
| # ifdef PNG_READ_STRIP_ALPHA_SUPPORTED |
| if ((*transform)->args & PNG_INIT_STRIP_ALPHA) |
| { |
| /* When compose is being done tRNS will be expanded regardless of the |
| * above test. Rather that trying to work out if this will happen the |
| * code just inserts a strip operation; it will be removed later if it |
| * is not needed. |
| */ |
| required = 1; |
| tc->strip_alpha = 1U; |
| |
| if (tc->init == PNG_TC_INIT_FORMAT) |
| png_add_strip_alpha_byte_ops(png_ptr); |
| } |
| # endif /* READ_STRIP_ALPHA */ |
| |
| if (!required) |
| (*transform)->fn = NULL; |
| # undef png_ptr |
| } |
| #endif /* READ_EXPAND || READ_STRIP_ALPHA */ |
| |
| #ifdef PNG_READ_EXPAND_SUPPORTED |
| /* Expand tRNS chunks to alpha channels. This only expands the tRNS chunk on |
| * non-palette formats; call png_set_palette_to_rgb to get the corresponding |
| * effect for a palette. |
| * |
| * Note that this will expand low bit depth gray if there is a tRNS chunk, but |
| * if not nothing will happen. |
| * |
| * API CHANGE: this used to do all the expansions, it was rather pointless |
| * calling it. |
| */ |
| void PNGAPI |
| png_set_tRNS_to_alpha(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| png_add_transform(png_ptr, 0/*size*/, png_init_alpha, PNG_TR_INIT_ALPHA)-> |
| args |= PNG_INIT_EXPAND_tRNS; |
| } |
| #endif /* READ_EXPAND */ |
| |
| #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED |
| void PNGAPI |
| png_set_strip_alpha(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| png_add_transform(png_ptr, 0/*size*/, png_init_alpha, PNG_TR_INIT_ALPHA)-> |
| args |= PNG_INIT_STRIP_ALPHA; |
| } |
| #endif /* READ_STRIP_ALPHA */ |
| |
| #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED |
| static void |
| png_do_chop_16_to_8(png_transformp *transform, png_transform_controlp tc) |
| /* This is actually a repeat of the byte transform, unnecessary code |
| * replication. |
| * |
| * TODO: remove this |
| */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); /* source */ |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); /* end+1 */ |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); /* destination */ |
| |
| debug(tc->bit_depth == 16U); |
| tc->sp = dp; |
| tc->bit_depth = 8U; |
| |
| while (sp < ep) |
| *dp++ = *sp, sp += 2; |
| |
| debug(sp == ep); |
| # undef png_ptr |
| |
| PNG_UNUSED(transform) |
| } |
| |
| /* A transform containing some useful scaling values... */ |
| typedef struct |
| { |
| png_transform tr; |
| png_uint_32 shifts; /* 4 4-bit values preceeded by a shibboleth (1) */ |
| png_uint_32 channel_scale[4]; |
| } png_transform_scale_16_to_8; |
| |
| /* Scale rows of bit depth 16 down to 8 accurately */ |
| static void |
| png_do_scale_16_to_8(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); /* source */ |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); /* end+1 */ |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); /* destination */ |
| png_transform_scale_16_to_8 *tr = |
| png_transform_cast(png_transform_scale_16_to_8, *transform); |
| png_uint_32p scale = 0; |
| png_uint_32 shift = 1U; /* set the shibboleth at the start */ |
| |
| debug(tc->bit_depth == 16U); |
| tc->sp = dp; |
| tc->bit_depth = 8U; |
| |
| while (sp < ep) |
| { |
| /* The input is an array of 16 bit components, these must be scaled to |
| * 8 bits each taking into account the sBIT setting. The calculation |
| * requires that the insignificant bits be stripped from the input value |
| * via a shift then scaled back to 8 bits: |
| * |
| * output = ((input >> shift) * scale + round) >> 24 |
| * |
| * The shifts are packed into tr->shifts, with the end of the list marked |
| * by a shibboleth, 1, which is preset above. |
| */ |
| png_uint_32 v = png_get_uint_16(sp); |
| |
| sp += 2; |
| |
| if (shift == 1U) |
| { |
| shift = tr->shifts; |
| scale = tr->channel_scale; |
| } |
| |
| *dp++ = PNG_BYTE(((v >> (shift & 0xFU)) * *scale++ + 0x800000U) >> 24); |
| shift >>= 4; |
| } |
| |
| affirm(sp == ep); |
| # undef png_ptr |
| } |
| |
| static int |
| add_scale(png_transform_scale_16_to_8 *tr, unsigned int sBIT, unsigned int ch) |
| { |
| /* This is the output max (255) scaled by 2^24 divided by the input max' |
| * (which is variable) and rounded. It gives the exact 8-bit answer for all |
| * input sBIT depths when used in the calculation: |
| * |
| * output = ((input >> shift) * scale + 0x800000U) >> 24 |
| */ |
| tr->channel_scale[ch] = (0xFF000000U + ((1U<<sBIT)>>1)) / ((1U<<sBIT)-1U); |
| tr->shifts |= ((16U-sBIT) & 0xFU) << (4U*ch); |
| |
| /* The result says whether there are 8 or fewer significant bits in the |
| * input value; if so we can just drop the low byte. |
| */ |
| return sBIT <= 8U; |
| } |
| |
| static void |
| png_init_scale_16_to_8(png_transformp *transform, png_transform_controlp tc) |
| { |
| if (tc->bit_depth == 16U) |
| { |
| # define png_ptr (tc->png_ptr) |
| tc->bit_depth = 8U; |
| /* But this invalidates tRNS (a 16-bit tRNS cannot be updated to match |
| * 8-bit data correctly). |
| */ |
| tc->invalid_info |= PNG_INFO_tRNS+PNG_INFO_hIST+PNG_INFO_pCAL; |
| /* TODO: These need further processing: PNG_INFO_bKGD */ |
| |
| if (tc->init == PNG_TC_INIT_FINAL) |
| { |
| png_transform_scale_16_to_8 *tr = |
| png_transform_cast(png_transform_scale_16_to_8, *transform); |
| |
| /* Set the scale factors for each channel (up to 4), the factors are |
| * made so that: |
| * |
| * ((channel >> shift) * factor + 0x800000U) >> 24 |
| * |
| * Gives the required 8-bit value. The 'shift' is stored in a single |
| * png_uint_32 with a shibboleth at the end. |
| */ |
| unsigned int channels = 0U; |
| int chop_ok = 1; |
| |
| tr->shifts = 0U; |
| |
| /* This adds up to four scale factors, the remainder are left as 0 |
| * which is safe and leads to obvious errors in the output images in |
| * the event of an (internal) error. |
| */ |
| if (tc->format & PNG_FORMAT_FLAG_COLOR) |
| chop_ok &= add_scale(tr, tc->sBIT_R, channels++); |
| |
| chop_ok &= add_scale(tr, tc->sBIT_G, channels++); |
| |
| if (tc->format & PNG_FORMAT_FLAG_COLOR) |
| chop_ok &= add_scale(tr, tc->sBIT_B, channels++); |
| |
| if (tc->format & PNG_FORMAT_FLAG_ALPHA) |
| chop_ok &= add_scale(tr, tc->sBIT_A, channels++); |
| |
| if (chop_ok) |
| tr->tr.fn = png_do_chop_16_to_8; |
| |
| else |
| { |
| int handled = 1; |
| |
| /* Add the shibboleth at the end */ |
| tr->shifts |= 1U << (4U*channels); |
| tr->tr.fn = png_do_scale_16_to_8; |
| |
| /* sBIT is a little tricky; it has to be processed in the scaling |
| * operation. The result will have the same number of bits unless |
| * there were more than 8 before. The sBIT flags in the transform |
| * control are left unchanged here because the data is still valid, |
| * unless all the values end up as 8 in which case there is no |
| * remaining sBIT info. |
| * |
| * Note that fields, such as alpha, which are not set for this row |
| * format will always have max values, so won't reset 'handled': |
| */ |
| if (tc->sBIT_R >= 8U) tc->sBIT_R = 8U; else handled = 0; |
| if (tc->sBIT_G >= 8U) tc->sBIT_G = 8U; else handled = 0; |
| if (tc->sBIT_B >= 8U) tc->sBIT_B = 8U; else handled = 0; |
| if (tc->sBIT_A >= 8U) tc->sBIT_A = 8U; else handled = 0; |
| |
| /* If all the sBIT values were >= 8U all the bits are now |
| * significant: |
| */ |
| if (handled) |
| tc->invalid_info |= PNG_INFO_sBIT; |
| } |
| } |
| |
| # undef png_ptr |
| } |
| |
| else /* not applicable */ |
| (*transform)->fn = NULL; |
| } |
| |
| void PNGAPI |
| png_set_scale_16(png_structrp png_ptr) |
| { |
| if (png_ptr != NULL) |
| png_add_transform(png_ptr, sizeof (png_transform_scale_16_to_8), |
| png_init_scale_16_to_8, PNG_TR_SCALE_16_TO_8); |
| } |
| #endif /* READ_SCALE_16_TO_8 */ |
| |
| #ifdef PNG_READ_GAMMA_SUPPORTED |
| /* Code that depends on READ_GAMMA support; RGB to gray convertion and |
| * background composition (including the various alpha-mode handling |
| * operations which produce pre-multiplied alpha by composing on 0). |
| */ |
| /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ |
| static png_fixed_point |
| png_reciprocal(png_fixed_point a) |
| { |
| #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED |
| double r = floor(1E10/a+.5); |
| |
| if (r <= 2147483647. && r >= -2147483648.) |
| return (png_fixed_point)r; |
| #else |
| png_fixed_point res; |
| |
| if (png_muldiv(&res, PNG_FP_1, PNG_FP_1, a) != 0) |
| return res; |
| #endif |
| |
| return 0; /* error/overflow */ |
| } |
| |
| /* This is the shared test on whether a gamma value is 'significant' - whether |
| * it is worth doing gamma correction. 'significant_bits' is the number of bits |
| * in the values to be corrected which are significant. |
| */ |
| static int |
| png_gamma_significant(png_const_structrp png_ptr, png_fixed_point gamma_val, |
| unsigned int sbits) |
| { |
| #if 0 |
| /* This seems to be wrong. The issue is that when the app asks for a higher |
| * bit depth output than the input has significant bits it causes gamma |
| * correction to be skipped (this was the intent) however there's no |
| * particular guarantee that the app won't go on to do further gamma |
| * processing - pngstest does this - and this messes up the results |
| * completely. |
| * |
| * TODO: work out how to optimize this correctly. |
| */ |
| /* The following table lists the threshold as a difference from PNG_FP_1 at |
| * which the gamma correction will make a change to at least an 'sbits' |
| * value. There is no entry for 1 bit values; gamma correction is never |
| * significant. |
| */ |
| static const png_uint_16 gamma_threshold_by_sbit[15][2] = |
| { |
| { 36907, 63092 }, /* 2 bits */ |
| { 17812, 21518 }, /* 3 bits */ |
| { 8675, 9496 }, /* 4 bits */ |
| { 4290, 4484 }, /* 5 bits */ |
| { 2134, 2181 }, /* 6 bits */ |
| { 1064, 1075 }, /* 7 bits */ |
| { 531, 534 }, /* 8 bits */ |
| { 265, 266 }, /* 9 bits */ |
| { 132, 132 }, /* 10 bits */ |
| { 66, 66 }, /* 11 bits */ |
| { 33, 33 }, /* 12 bits */ |
| { 16, 16 }, /* 13 bits */ |
| { 8, 8 }, /* 14 bits */ |
| { 4, 4 }, /* 15 bits */ |
| { 2, 2 }, /* 16 bits */ |
| }; |
| |
| /* Handle out of range values in release by doing the gamma correction: */ |
| debug_handled(sbits > 0U && sbits <= 16U); |
| if (sbits == 0U || sbits > 16U) |
| return 1; |
| |
| /* 1 bit input or zero gamma, no correction possible/required: */ |
| if (gamma_val == 0 || sbits < 2U) |
| return 0; |
| |
| if (gamma_val < PNG_FP_1 - gamma_threshold_by_sbit[sbits-2U][0U]) |
| return gamma_val < PNG_FP_1 - png_ptr->gamma_threshold; |
| |
| else if (gamma_val > PNG_FP_1 + gamma_threshold_by_sbit[sbits-2U][1U]) |
| return gamma_val > PNG_FP_1 + png_ptr->gamma_threshold; |
| #else /* FIXUP */ |
| if (gamma_val < PNG_FP_1) |
| return gamma_val < PNG_FP_1 - png_ptr->gamma_threshold; |
| |
| else if (gamma_val > PNG_FP_1) |
| return gamma_val > PNG_FP_1 + png_ptr->gamma_threshold; |
| |
| PNG_UNUSED(sbits) |
| #endif /* FIXUP */ |
| |
| return 0; /* not significant */ |
| } |
| |
| static int |
| png_gamma_equal(png_const_structrp png_ptr, png_fixed_point g1, |
| png_fixed_point g2, png_fixed_point *c, unsigned int sbits) |
| /* Gamma values are equal, or at least one is unknown; c is the correction |
| * factor from g1 to g2, i.e. g2/g1. |
| */ |
| { |
| return sbits == 1U || g1 == 0 || g2 == 0 || g1 == g2 || |
| (png_muldiv(c, g2, PNG_FP_1, g1) && |
| !png_gamma_significant(png_ptr, *c, sbits)); |
| } |
| |
| #ifdef PNG_SIMPLIFIED_READ_SUPPORTED |
| int |
| png_need_gamma_correction(png_const_structrp png_ptr, png_fixed_point gamma, |
| int sRGB_output) |
| /* This is a hook for the simplified code; it just decides whether or not the |
| * given gamma (which defaults to that of the PNG data) is close enough to |
| * linear or sRGB not to require gamma correction. |
| */ |
| { |
| if (gamma == 0) |
| gamma = png_ptr->colorspace.gamma; |
| |
| if (gamma != 0 && |
| (png_ptr->colorspace.flags & |
| (PNG_COLORSPACE_INVALID|PNG_COLORSPACE_HAVE_GAMMA)) == |
| PNG_COLORSPACE_HAVE_GAMMA) |
| { |
| |
| if (sRGB_output && !png_muldiv(&gamma, gamma, PNG_GAMMA_sRGB, PNG_FP_1)) |
| return 0; /* overflow, so no correction */ |
| |
| return png_gamma_significant(png_ptr, gamma, (png_ptr->color_type & |
| PNG_COLOR_MASK_PALETTE) ? 8U : png_ptr->bit_depth); |
| } |
| |
| return 0; /* no info, no correction */ |
| } |
| #endif /* SIMPLIFIED_READ */ |
| |
| #ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED |
| /* Fixed point gamma. |
| * |
| * The code to calculate the tables used below can be found in the shell script |
| * contrib/tools/intgamma.sh |
| * |
| * To calculate gamma this code implements fast log() and exp() calls using only |
| * fixed point arithmetic. This code has sufficient precision for either 8-bit |
| * or 16-bit sample values. |
| * |
| * The tables used here were calculated using simple 'bc' programs, but C double |
| * precision floating point arithmetic would work fine. |
| * |
| * 8-bit log table |
| * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to |
| * 255, so it's the base 2 logarithm of a normalized 8-bit floating point |
| * mantissa. The numbers are 32-bit fractions. |
| */ |
| static const png_uint_32 |
| png_8bit_l2[128] = |
| { |
| 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, |
| 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, |
| 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, |
| 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, |
| 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, |
| 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, |
| 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, |
| 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, |
| 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, |
| 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, |
| 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, |
| 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, |
| 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, |
| 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, |
| 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, |
| 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, |
| 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, |
| 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, |
| 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, |
| 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, |
| 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, |
| 24347096U, 0U |
| |
| #if 0 /* NOT USED */ |
| /* The following are the values for 16-bit tables - these work fine for the |
| * 8-bit conversions but produce very slightly larger errors in the 16-bit |
| * log (about 1.2 as opposed to 0.7 absolute error in the final value). To |
| * use these all the shifts below must be adjusted appropriately. |
| */ |
| 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, |
| 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, |
| 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, |
| 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, |
| 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, |
| 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, |
| 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, |
| 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, |
| 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, |
| 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, |
| 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, |
| 1119, 744, 372 |
| #endif |
| }; |
| |
| #if 0 /* UNUSED */ |
| static png_int_32 |
| png_log8bit(unsigned int x) |
| { |
| png_uint_32 lg2 = 0U; |
| |
| /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, |
| * because the log is actually negate that means adding 1. The final |
| * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 |
| * input), return -1 for the overflow (log 0) case, - so the result is |
| * always at most 19 bits. |
| */ |
| if ((x &= 0xffU) == 0U) /* 0 input, -inf output */ |
| return -0xfffff; |
| |
| if ((x & 0xf0U) == 0U) |
| lg2 = 4U, x <<= 4; |
| |
| if ((x & 0xc0U) == 0U) |
| lg2 += 2U, x <<= 2; |
| |
| if ((x & 0x80U) == 0U) |
| lg2 += 1U, x <<= 1; |
| |
| /* result is at most 19 bits, so this cast is safe: */ |
| return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128U]+32768U)>>16)); |
| } |
| #endif /* UNUSED */ |
| |
| /* The above gives exact (to 16 binary places) log2 values for 8-bit images, |
| * for 16-bit images we use the most significant 8 bits of the 16-bit value to |
| * get an approximation then multiply the approximation by a correction factor |
| * determined by the remaining up to 8 bits. This requires an additional step |
| * in the 16-bit case. |
| * |
| * We want log2(value/65535), we have log2(v'/255), where: |
| * |
| * value = v' * 256 + v'' |
| * = v' * f |
| * |
| * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 |
| * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less |
| * than 258. The final factor also needs to correct for the fact that our 8-bit |
| * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. |
| * |
| * This gives a final formula using a calculated value 'x' which is value/v' and |
| * scaling by 65536 to match the above table: |
| * |
| * log2(x/257) * 65536 |
| * |
| * Since these numbers are so close to '1' we can use simple linear |
| * interpolation between the two end values 256/257 (result -368.61) and 258/257 |
| * (result 367.179). The values used below are scaled by a further 64 to give |
| * 16-bit precision in the interpolation: |
| * |
| * Start (256): -23591 |
| * Zero (257): 0 |
| * End (258): 23499 |
| * |
| * In libpng 1.7.0 this is further generalized to return -log2(value/maxval) for |
| * any maxval up to 65535. This is done by evaluating -log2(value/65535) first |
| * then adjusting for the required maxval: |
| * |
| * ( value) (value 65535) (value) ( 65535) |
| * -log2(------) = -log2(----- x ------) = -log2(-----)-log2(------) |
| * (maxval) (65535 maxval) (65535) (maxval) |
| * |
| * The extra argument, 'factor', is (2^(16+12))*log2(65535/maxval) (a positive |
| * value less than 2^32) and this is *subtracted* from the intermediate |
| * calculation below. |
| */ |
| static png_int_32 |
| png_log(unsigned int x, png_uint_32 factor) |
| /* x: a value of up to 16 bits, |
| * factor: a 4.28 number which is subtracted from the log below |
| */ |
| { |
| png_uint_32 lg2 = 0U; |
| |
| /* As above, but now the input has 16 bits. */ |
| if ((x &= 0xffffU) == 0U) |
| return -0xfffff; |
| |
| if ((x & 0xff00U) == 0U) |
| lg2 = 8U, x <<= 8; |
| |
| if ((x & 0xf000U) == 0U) |
| lg2 += 4U, x <<= 4; |
| |
| if ((x & 0xc000U) == 0U) |
| lg2 += 2U, x <<= 2; |
| |
| if ((x & 0x8000U) == 0U) |
| lg2 += 1U, x <<= 1; |
| |
| /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional |
| * value. |
| */ |
| lg2 <<= 28; |
| lg2 += (png_8bit_l2[(x>>8)-128U]+8U) >> 4; |
| |
| /* Now we need to interpolate the factor, this requires a division by the top |
| * 8 bits. Do this with maximum precision. |
| */ |
| { |
| png_uint_32 i = x; |
| |
| i = ((i << 16) + (i >> 9)) / (x>> 8); |
| |
| /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, |
| * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us |
| * exactly 16 bits to interpolate to get the low bits of the result. |
| * Round the answer. Note that the end point values are scaled by 64 to |
| * retain overall precision and that 'lg2' is current scaled by an extra |
| * 12 bits, so adjust the overall scaling by 6-12. Round at every step. |
| */ |
| i -= 1U << 24; |
| |
| if (i <= 65536U) /* <= '257' */ |
| lg2 += ((23591U * (65536U-i)) + (1U << (16+6-12-1))) >> (16+6-12); |
| |
| else |
| lg2 -= ((23499U * (i-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); |
| } |
| |
| if (lg2 >= factor) |
| return (png_int_32)/*SAFE*/((lg2 - factor + 2048U) >> 12); |
| |
| else /* the result will be greater than 1.0, so negative: */ |
| return -(png_int_32)/*SAFE*/((factor - lg2 + 2048U) >> 12); |
| } |
| |
| #if 0 /* UNUSED */ |
| static png_int_32 |
| png_log16bit(unsigned int x) |
| { |
| return png_log(x, 0U); |
| } |
| #endif /* UNUSED */ |
| |
| /* libpng 1.7.0: generalization of png_log{8,16}bit to accept an n-bit input |
| * value. We want to maintain 1% accuracy in linear light space. This |
| * corresponds to, approximately, (1*g)% in a gamma encoded space where the |
| * gamma encoding is 'g' (in the PNG sense, e.g. 0.45455 for sRGB). Apparently |
| * this requires unbounded accuracy as the gamma encoding value goes down and |
| * this is a problem for modern HDR data because it may require a high gamma to |
| * accurately encode image data over a wide dynamic range; the dynamic range of |
| * 16-bit linear data is only 655:1 if 1% accuracy is needed! |
| * |
| * However 16-bit gamma encoded data is still limited because PNG can only |
| * express gamma encoding. (A log-to-base-1.01 encoding is unlimited; a 12-bit |
| * value, with 4094 steps, has a dynamic range of more than 1:10^17, which |
| * exceeds the human eye's range of 1:10^14.) |
| * |
| * Notice that sRGB uses a 1/2.4 encoding and CIELab uses a 1/3 encoding. It is |
| * obvious that, if we assume a maximum D difference in the luminance of |
| * adjacent pixel values the dynamic range is given by the lowest pixel value |
| * which is D or less greater than its predecessor, so: |
| * |
| * ( P ) (1) |
| * (---)^(-) = D |
| * (P-1) (g) |
| * |
| * and the maximum dynamic range that can be achieved using M+1 separate values, |
| * where M+1 is 2^N-1 for an N bit value, reserving the first value for 0, is: |
| * |
| * (M) (1) |
| * range(R) = (-)^(-) |
| * (P) (g) |
| * |
| * So we can eliminate 'P' from the two equations: |
| * |
| * P = (P-1) x (D^g) |
| * |
| * D^g |
| * P = ----- |
| * D^g-1 |
| * |
| * (M x (D^g-1)) (1) |
| * R = (-----------)^(-) |
| * ( D^g ) (g) |
| * |
| * (M x (D^g-1)) ^ (1/g) |
| * = --------------------- |
| * D |
| * |
| * Which is a function in two variables (R and g) for a given D (maximum delta |
| * between two adjacent pixel values) and M (number of pixel values, controlled |
| * by the channel bit depth). |
| * |
| * See contrib/tools/dynamic-range.c for code exploring this function. This |
| * program will output the optimal gamma for a given number of bits and |
| * precision. |
| * |
| * The range of sensitivity of human vision is roughly as follows (this comes |
| * from the wikipedia article on scotopic vision): |
| * |
| * scotopic: 10^-6 to 10^-3.5 cd/m^2 |
| * mesopic: 10^-3 to 10^0.5 cd/m^2 |
| * photopic: 10 to 10^8 cd/m^2 |
| * |
| * Giving a total range of about 1:10^14. The maximum precision at which this |
| * range can be achieved using 16-bit channels is about .15% using a gamma of |
| * 36, higher ranges are possible using higher gammas but precision is reduced. |
| * The range with 1% precision and 16-bit channels is 1:10^104, using a gamma of |
| * 240. |
| * |
| * In general the optimal gamma for n-bit channels (where 'n' is at least 7 and |
| * precision is .01 or less) is: |
| * |
| * 2^n * precision |
| * gamma = --------------- |
| * 2.736 |
| * |
| * Or: (24000 * precision) for 16-bit data. |
| * |
| * The net effect is that we can't rely on the encoding gamma being limited to |
| * values around 1/2.5! |
| */ |
| static png_int_32 |
| png_log_nbit(unsigned int x, unsigned int nbits) |
| { |
| static const png_uint_32 factors[16] = |
| { |
| 4294961387U, /* 1 bit */ |
| 3869501255U, /* 2 bit */ |
| 3541367788U, /* 3 bit */ |
| 3246213428U, /* 4 bit */ |
| 2965079441U, /* 5 bit */ |
| 2690447525U, /* 6 bit */ |
| 2418950626U, /* 7 bit */ |
| 2148993476U, /* 8 bit */ |
| 1879799410U, /* 9 bit */ |
| 1610985205U, /* 10 bit */ |
| 1342360514U, /* 11 bit */ |
| 1073830475U, /* 12 bit */ |
| 805347736U, /* 13 bit */ |
| 536888641U, /* 14 bit */ |
| 268441365U, /* 15 bit */ |
| 0U /* 16 bit */ |
| }; |
| |
| return png_log(x, factors[nbits-1]); |
| } |
| |
| |
| /* The 'exp()' case must invert the above, taking a 20-bit fixed point |
| * logarithmic value and returning a 16 or 8-bit number as appropriate. In |
| * each case only the low 16 bits are relevant - the fraction - since the |
| * integer bits (the top 4) simply determine a shift. |
| * |
| * The worst case is the 16-bit distinction between 65535 and 65534. This |
| * requires perhaps spurious accuracy in the decoding of the logarithm to |
| * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance |
| * of needing this accuracy in practice. |
| * |
| * To deal with this the following exp() function works out the exponent of the |
| * frational part of the logarithm by using an accurate 32-bit value from the |
| * top four fractional bits then multiplying in the remaining bits. |
| */ |
| static const png_uint_32 |
| png_32bit_exp[16] = |
| { |
| /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ |
| 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, |
| 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, |
| 2553802834U, 2445529972U, 2341847524U, 2242560872U |
| }; |
| |
| /* Adjustment table; provided to explain the numbers in the code below. */ |
| #if 0 /* BC CODE */ |
| for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} |
| 11 44937.64284865548751208448 |
| 10 45180.98734845585101160448 |
| 9 45303.31936980687359311872 |
| 8 45364.65110595323018870784 |
| 7 45395.35850361789624614912 |
| 6 45410.72259715102037508096 |
| 5 45418.40724413220722311168 |
| 4 45422.25021786898173001728 |
| 3 45424.17186732298419044352 |
| 2 45425.13273269940811464704 |
| 1 45425.61317555035558641664 |
| 0 45425.85339951654943850496 |
| #endif |
| |
| static png_uint_32 |
| png_exp(png_int_32 x) |
| /* Utility, the value 'x' must be in the range 0..0x1fffff */ |
| { |
| /* Obtain a 4-bit approximation */ |
| png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; |
| |
| /* Incorporate the low 12 bits - these decrease the returned value by |
| * multiplying by a number less than 1 if the bit is set. The multiplier |
| * is determined by the above table and the shift. Notice that the values |
| * converge on 45426 and this is used to allow linear interpolation of the |
| * low bits. |
| */ |
| if (x & 0x800) |
| e -= (((e >> 16) * 44938U) + 16U) >> 5; |
| |
| if (x & 0x400) |
| e -= (((e >> 16) * 45181U) + 32U) >> 6; |
| |
| if (x & 0x200) |
| e -= (((e >> 16) * 45303U) + 64U) >> 7; |
| |
| if (x & 0x100) |
| e -= (((e >> 16) * 45365U) + 128U) >> 8; |
| |
| if (x & 0x080) |
| e -= (((e >> 16) * 45395U) + 256U) >> 9; |
| |
| if (x & 0x040) |
| e -= (((e >> 16) * 45410U) + 512U) >> 10; |
| |
| /* And handle the low 6 bits in a single block. */ |
| e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; |
| |
| /* Handle the upper bits of x, note that this works for x up to 0x1fffff but |
| * fails for larger or negative x, where the shift (x >> 16) exceeds 31: |
| */ |
| e >>= x >> 16; |
| return e; |
| } |
| |
| #if 0 /* UNUSED */ |
| static png_byte |
| png_exp8bit(png_int_32 lg2) |
| { |
| /* The input is a negative fixed point (16:16) logarithm with a useable range |
| * of [0.0..8.0). Clamp the value so that the output of png_exp is in the |
| * range (254.5/255..0.5/255): |
| */ |
| if (lg2 <= 185) /* -log2(254.5/255) */ |
| return 255U; |
| |
| else if (lg2 > 589453) /* -log2(0.5/255) */ |
| return 0U; |
| |
| else |
| { |
| /* Get a 32-bit value: */ |
| png_uint_32 x = png_exp(lg2); |
| |
| /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that |
| * the second, rounding, step can't overflow because of the first, |
| * subtraction, step. |
| */ |
| x -= x >> 8; |
| return PNG_BYTE((x + 0x7fffffU) >> 24); |
| } |
| } |
| |
| static png_uint_16 |
| png_exp16bit(png_int_32 lg2) |
| { |
| if (lg2 <= 0) /* -log2(65534.5/65535) */ |
| return 65535U; |
| |
| else if (lg2 > 1114110) /* -log2(0.5/65535) */ |
| return 0U; |
| |
| else |
| { |
| /* Get a 32-bit value: */ |
| png_uint_32 x = png_exp(lg2); |
| |
| /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ |
| x -= x >> 16; |
| return PNG_UINT_16((x + 32767U) >> 16); |
| } |
| } |
| #endif /* UNUSED */ |
| |
| static png_uint_32 |
| png_exp_nbit(png_int_32 lg2, unsigned int n) |
| { |
| /* These pre-computed limits give the low value of lg2 at and below which |
| * 2^(-lg2/65536) * (2^n-1) gives (2^n-1) and the high value of lg2 above |
| * which 2(^-lg2/65536) * (2^n-1) gives 0: |
| */ |
| static const png_int_32 limits[16][2] = |
| { |
| { 65535, 65535 }, /* bits = 1 */ |
| { 17238, 169408 }, /* bits = 2 */ |
| { 7006, 249518 }, /* bits = 3 */ |
| { 3205, 321577 }, /* bits = 4 */ |
| { 1537, 390214 }, /* bits = 5 */ |
| { 753, 457263 }, /* bits = 6 */ |
| { 372, 523546 }, /* bits = 7 */ |
| { 185, 589453 }, /* bits = 8 */ |
| { 92, 655175 }, /* bits = 9 */ |
| { 46, 720803 }, /* bits = 10 */ |
| { 23, 786385 }, /* bits = 11 */ |
| { 11, 851944 }, /* bits = 12 */ |
| { 5, 917492 }, /* bits = 13 */ |
| { 2, 983034 }, /* bits = 14 */ |
| { 1, 1048573 }, /* bits = 15 */ |
| { 0, 1114110 } /* bits = 16 */ |
| }; |
| |
| /* If 'max' is 2^n-1: */ |
| if (lg2 <= limits[n-1][0]) /* -log2((max-.5)/max) */ |
| return (1U << n)-1U; |
| |
| else if (lg2 > limits[n-1][1]) /* -log2(.5/max) */ |
| return 0U; |
| |
| else /* 'n' will be at least 2 */ |
| { |
| /* Get a 32-bit value: */ |
| png_uint_32 x = png_exp(lg2); |
| |
| /* Convert the 32-bit value to 0..(2^n-1) by multiplying by 2^n-1: */ |
| x -= x >> n; |
| return (x + ((1U<<(31U-n))-1U)) >> (32U-n); |
| } |
| } |
| #endif /* !FLOATING_ARITHMETIC */ |
| |
| #if 0 /* UNUSED */ |
| static png_byte |
| png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) |
| { |
| if (value == 0U) |
| return 0U; |
| |
| else if (value >= 255U) |
| return 255U; |
| |
| else |
| { |
| # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED |
| /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly |
| * convert this to a floating point value. This includes values that |
| * would overflow if 'value' were to be converted to 'int'. |
| * |
| * Apparently GCC, however, does an intermediate conversion to (int) |
| * on some (ARM) but not all (x86) platforms, possibly because of |
| * hardware FP limitations. (E.g. if the hardware conversion always |
| * assumes the integer register contains a signed value.) This results |
| * in ANSI-C undefined behavior for large values. |
| * |
| * Other implementations on the same machine might actually be ANSI-C90 |
| * conformant and therefore compile spurious extra code for the large |
| * values. |
| * |
| * We can be reasonably sure that an unsigned to float conversion |
| * won't be faster than an int to float one. Therefore this code |
| * assumes responsibility for the undefined behavior, which it knows |
| * can't happen because of the check above. |
| * |
| * Note the argument to this routine is an (unsigned int) because, on |
| * 16-bit platforms, it is assigned a value which might be out of |
| * range for an (int); that would result in undefined behavior in the |
| * caller if the *argument* ('value') were to be declared (int). |
| */ |
| double r = 255*pow((int)/*SAFE*/value/255.,gamma_val*.00001); |
| if (r < .5) |
| return 0U; |
| |
| else if (r >= 254.5) |
| return 255U; |
| |
| r = floor(r+.5); |
| return (png_byte)/*SAFE*/r; |
| # else |
| png_int_32 lg2 = png_log8bit(value); |
| png_int_32 res; |
| |
| /* Overflow in the muldiv means underflow in the calculation, this is |
| * OK (it happens for ridiculously high gamma). |
| */ |
| if (!png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) |
| return 0U; /* underflow */ |
| |
| return png_exp8bit(res); |
| # endif |
| } |
| } |
| #endif /* UNUSED */ |
| |
| /* libpng-1.7.0: this private function converts an n-bit input value to an |
| * m-bit output value. |
| */ |
| unsigned int |
| png_gamma_nxmbit_correct(unsigned int value, png_fixed_point gamma_val, |
| unsigned int n/*input bits*/, unsigned int m/*output bits */) |
| { |
| if (value == 0U) |
| return 0U; |
| |
| else |
| { |
| unsigned int min = (1U<<n) - 1U; |
| unsigned int mout = (1U<<m) - 1U; |
| |
| if (value >= min) |
| return mout; |
| |
| else |
| { |
| # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED |
| double r = value; |
| r /= min; |
| r = floor(mout * pow(r, gamma_val*.00001)+.5); |
| if (r < 1) |
| return 0U; |
| |
| else if (r >= mout) |
| return mout; |
| |
| return (unsigned int)/*SAFE*/r; |
| # else |
| png_int_32 lg2 = png_log_nbit(value, n); |
| png_int_32 res; |
| |
| if (!png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) |
| return 0U; /* underflow */ |
| |
| return png_exp_nbit(res, m); |
| # endif |
| } |
| } |
| } |
| |
| #if 0 /*UNUSED*/ |
| static unsigned int |
| png_gamma_sbit_correct(unsigned int value, png_fixed_point gamma_val, |
| unsigned int n/*input bits*/, unsigned int sbits, |
| unsigned int m/*output bits */) |
| /* As above but the number of significant bits in 'n' is passed in. */ |
| { |
| if (sbits < n) |
| { |
| value >>= (n-sbits); |
| n = sbits; |
| } |
| |
| return png_gamma_nxmbit_correct(value, gamma_val, n, m); |
| } |
| #endif /*UNUSED*/ |
| |
| static int |
| push_gamma_expand(png_transformp *transform, png_transform_controlp tc, |
| int need_alpha) |
| /* Utility to push a transform to expand low-bit-depth gray and, where |
| * required, tRNS chunks. The caller must return immediately if this |
| * returns true because the init of the new transform has been run in place |
| * of the caller's. |
| */ |
| { |
| # define png_ptr (tc->png_ptr) |
| unsigned int expand = 0; |
| |
| affirm(tc->init == PNG_TC_INIT_FINAL); |
| |
| if (tc->bit_depth < 8U) /* low bit gray: expand to 8 bits */ |
| expand = PNG_EXPAND_LBD_GRAY; |
| |
| /* Gamma correction invalidates tRNS, so if it is being expanded and |
| * alpha is not being stripped expand it now. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette && |
| png_ptr->num_trans == 1 && (tc->invalid_info & PNG_INFO_tRNS) == 0) |
| { |
| if (need_alpha || (tc->expand_tRNS && !tc->strip_alpha)) |
| expand |= PNG_EXPAND_tRNS; |
| |
| else |
| tc->invalid_info |= PNG_INFO_tRNS; |
| } |
| |
| if (expand == 0) |
| return 0; /* nothing needs to be done */ |
| |
| { |
| png_transformp tr = png_push_transform(png_ptr, sizeof (png_expand), |
| png_init_expand, transform, NULL/*don't run init*/); |
| |
| debug(tr == *transform); |
| tr->args |= expand; |
| |
| /* This must be run immediately, because it just got inserted where this |
| * transform is; this is safe, the caller must return immediately. |
| */ |
| png_init_expand(transform, tc); |
| affirm(tr->fn != NULL); /* because it should need to do something! */ |
| } |
| |
| return 1; |
| # undef png_ptr |
| } |
| |
| /* Low bit depth gray gamma correction. The 1-bit case is a no-op because 0 and |
| * 1 always map to 0 and 1. The 2-bit case has the following possiblities: |
| * |
| * bits/correction: g0 g1 g2 g3 g4 g5 g6 |
| * 00 -> 00 00 00 00 00 00 00 |
| * 01 -> 11 10 10 01 00 00 00 |
| * 10 -> 11 11 10 10 10 01 00 |
| * 11 -> 11 11 11 11 11 11 11 |
| * |
| * Where the breakpoints are: |
| * |
| * g0: correction <= 16595 (1 - log(2.5/3)) |
| * g1: 16595 < correction <= 44966 (log(2.5/3)/log(2/3)) |
| * g2: 44966 < correction <= 63092 (1 - log(1.5/3)) |
| * g3: 63092 < correction <= 163092 (1 - log(.5/3)) |
| * g4: 163092 < correction <= 170951 (log(1.5/3)/log(2/3)) |
| * g5: 170951 < correction <= 441902 (log(.5/3)/log(2/3) |
| * g6 441902 < correction |
| * |
| * This can be done by bit-hacking on the byte values (4 pixels), given that |
| * the correction is fixed (indeed, it can be done on whole 32-bit values!) |
| * |
| * g0: B |= B>>1; B &= 0x55U; B |= B<<1; * either bit set |
| * g1: B ^= B>>1; B &= 0x55U; B += B; * one bit set |
| * g2: B &= (~B)>>1; B &= 0x55U; B += B; * low bit set, high bit unset |
| * g3: no-op |
| * g4: B &= (~B)>>1; B &= 0x55U; B -= B; * low bit set, high bit unset |
| * g5: B ^= B>>1; B &= 0x55U; B -= B; * one bit set |
| * g6: B &= B>>1; B &= 0x55U; B |= B<<1; * both bits set |
| */ |
| typedef struct |
| { |
| png_transform tr; |
| png_fixed_point correct; |
| png_fixed_point to_gamma; |
| png_uint_32 shifts; /* 1 followed by up to 4 4-bit shifts */ |
| png_uint_32 channel_scale[4]; /* up to 4 channel scale factors */ |
| /* These factors are used: |
| * |
| * (input >> (shifts & 0xFU) * channel_scale + SCALE_R) >> SCALE_S |
| * |
| * Where the rounding value, SCALE_R and the shift SCALE_S are dependent |
| * on the bit depth: |
| * |
| * SCALE_S = 32 - bit_depth range 16..31 |
| * SCALE_R = 1 << (SCALE_S-1) |
| */ |
| unsigned int to_bit_depth; |
| unsigned int encode_alpha :1; |
| unsigned int optimize_alpha :1; |
| } png_transform_gamma; |
| |
| static unsigned int |
| init_gamma_sBIT(png_transform_gamma *tr, png_transform_controlp tc) |
| /* Returns true if sBIT processing is required, otherwise all relevant sBIT |
| * values match the from (tc) bit depth. |
| */ |
| { |
| /* The to_bit_depth and to_gamma fields are already set, but updated values |
| * are needed for sBIT and the shifts and channel_scale fields must be filled |
| * in correctly. The do_gamma setting says whether gamma correction will be |
| * done, but the scale factors are filled in regardless. |
| * |
| * The general scaling equation is: |
| * |
| * ((in >> shift) * factor + round) >> (32 - to_bit_depth) |
| * |
| * 'factor' is then the rounded value of: |
| * |
| * out_max |
| * ------- . (1 << (32-to_bit_depth)) |
| * in_max |
| */ |
| # define png_ptr (tc->png_ptr) |
| const unsigned int to_bit_depth = tr->to_bit_depth; |
| const png_uint_32 numerator = ((1U<<to_bit_depth)-1U) << (32U-to_bit_depth); |
| /* in_max depends on the number of significant bits */ |
| const unsigned int from_bit_depth = tc->bit_depth; |
| |
| /* The data in the gamma transform is stored in the order of the channels in |
| * the input row, which is the PNG order. It may be reversed below. |
| */ |
| png_uint_32p channel_scale = tr->channel_scale; |
| png_uint_32 shifts = 0U; |
| unsigned int count = 0U; |
| unsigned int need_sBIT = 0U; |
| |
| if (tc->format & PNG_FORMAT_FLAG_COLOR) |
| { |
| const unsigned int sBIT = tc->sBIT_R; |
| |
| if (sBIT < from_bit_depth) |
| need_sBIT = 1U; |
| |
| debug(sBIT > 0U && sBIT <= from_bit_depth); |
| shifts |= (from_bit_depth - sBIT) << count; |
| count += 4U; |
| /* round the scale: */ |
| *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U); |
| } |
| |
| { |
| const unsigned int sBIT = tc->sBIT_G; |
| |
| if (sBIT < from_bit_depth) |
| need_sBIT = 1U; |
| |
| debug(sBIT > 0U && sBIT <= from_bit_depth); |
| shifts |= (from_bit_depth - sBIT) << count; |
| count += 4U; |
| *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U); |
| } |
| |
| if (tc->format & PNG_FORMAT_FLAG_COLOR) |
| { |
| const unsigned int sBIT = tc->sBIT_B; |
| |
| if (sBIT < from_bit_depth) |
| need_sBIT = 1U; |
| |
| debug(sBIT > 0U && sBIT <= from_bit_depth); |
| shifts |= (from_bit_depth - sBIT) << count; |
| count += 4U; |
| /* round the scale: */ |
| *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U); |
| } |
| |
| if (tc->format & PNG_FORMAT_FLAG_ALPHA) |
| { |
| const unsigned int sBIT = tc->sBIT_A; |
| |
| if (sBIT < from_bit_depth) |
| need_sBIT = 1U; |
| |
| debug(sBIT > 0U && sBIT <= from_bit_depth); |
| shifts |= (from_bit_depth - sBIT) << count; |
| count += 4U; |
| /* round the scale: */ |
| *channel_scale++ = (numerator + (1U<<(sBIT-1U))) / ((1U << sBIT)-1U); |
| } |
| |
| tr->shifts = shifts | (1U << count); |
| |
| return need_sBIT; |
| # undef png_ptr |
| } |
| |
| static void |
| reverse_gamma_sBIT(png_transform_gamma *tr) |
| { |
| /* This is called for the 'down' gamma implementations, they read the shifts |
| * and the channel scales in reverse, so: |
| */ |
| png_uint_32 shifts = tr->shifts; |
| png_uint_32 scales[4U]; |
| unsigned int count = 0U; |
| |
| tr->shifts = 1U; |
| |
| while (shifts != 1U) |
| { |
| scales[3U-count] = tr->channel_scale[count]; |
| ++count; |
| tr->shifts <<= 4; |
| tr->shifts |= shifts & 0xFU; |
| shifts >>= 4; |
| } |
| |
| memcpy(tr->channel_scale, scales+(4U-count), count * sizeof (png_uint_32)); |
| } |
| |
| static void |
| png_do_gamma8_up(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const png_fixed_point correct = tr->correct; |
| const unsigned int bit_depth = tr->to_bit_depth; |
| const png_uint_32 shifts = tr->shifts; |
| |
| affirm(tc->bit_depth == 8U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| debug((shifts & 0x8888U) == 0U); /* all shifts 7 or less */ |
| debug(!tr->encode_alpha && !tr->optimize_alpha); /* only set for 16 bits */ |
| |
| tc->sp = dp; |
| tc->bit_depth = bit_depth; |
| tc->gamma = tr->to_gamma; |
| |
| /* Handle the <8 bit output case differently because there can be no alpha |
| * channel. |
| */ |
| if (bit_depth < 8U) |
| { |
| const unsigned int shift = shifts & 0xFU; |
| unsigned int bits = 8U; |
| unsigned int ob = 0U; |
| |
| debug((shifts >> 4) == 1U && shift < 8U); |
| affirm(PNG_TC_CHANNELS(*tc) == 1); |
| |
| do |
| { |
| const unsigned int inb = png_gamma_nxmbit_correct( |
| *sp++ >> shift, correct, 8U-shift, bit_depth); |
| bits -= bit_depth; |
| ob = ob | (inb << bits); |
| if (bits == 0U) |
| bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U; |
| } |
| while (sp < ep); |
| |
| if (bits < 8U) |
| *dp++ = PNG_BYTE(ob); |
| } |
| |
| else /* 8-bit --> 8-bit */ |
| { |
| png_uint_32 alpha_scale; |
| const unsigned int channels = PNG_TC_CHANNELS(*tc); |
| unsigned int channel, alpha; |
| |
| debug(bit_depth == 8U && (shifts >> (4*channels)) == 1U); |
| |
| /* The alpha channel is always last, so if present checking against the |
| * top bits of 'channels' works because of the 1U shibboleth at the end. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0) |
| alpha_scale = alpha = 0U; |
| |
| else |
| { |
| alpha = shifts >> (4U*(channels-1U)); |
| alpha_scale = tr->channel_scale[channels-1U]; |
| } |
| |
| channel = 1U; |
| |
| do |
| { |
| unsigned int inb = *sp++, shift; |
| |
| if (channel == 1U) |
| channel = shifts; |
| |
| shift = channel & 0xFU; |
| inb >>= shift; |
| |
| /* The alpha channel is not gamma encoded but it may need some |
| * appropriate scaling. |
| */ |
| if (channel == alpha) |
| inb = (inb * alpha_scale + 0x800000U) >> 24; |
| |
| else |
| inb = png_gamma_nxmbit_correct(inb, correct, 8U-shift, 8U); |
| |
| channel >>= 4; /* for the next channel, or the shibboleth */ |
| *dp++ = PNG_BYTE(inb); |
| } |
| while (sp < ep); |
| |
| debug(channel == 1U); |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_gamma16_up(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/; |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const png_fixed_point correct = tr->correct; |
| const unsigned int bit_depth = tr->to_bit_depth; |
| const png_uint_32 shifts = tr->shifts; |
| |
| affirm(tc->bit_depth == 16U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| debug(!tr->optimize_alpha); |
| |
| /* This is exactly the same as above but the input has 16 bits per component, |
| * not 8. |
| */ |
| tc->sp = dp; |
| tc->bit_depth = bit_depth; |
| tc->gamma = tr->to_gamma; |
| |
| /* Handle the <8 bit output case differently, the input cannot be color (at |
| * present) and, if there is an alpha channel, then it is for the |
| * low-bit-depth gray input case and we expect the alpha to be transparent. |
| */ |
| if (bit_depth < 8U) |
| { |
| const unsigned int shift = shifts & 0xFU; |
| unsigned int bits = 8U; |
| unsigned int ob = 0U; |
| |
| affirm((tc->format & PNG_FORMAT_FLAG_COLOR) == 0U); |
| |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0U) |
| { |
| debug((shifts >> 4) == 1U && shift < 16U); |
| debug(!tr->encode_alpha && !tr->optimize_alpha); |
| |
| do |
| { |
| unsigned int inb = *sp++ << 8; /* high bits first */ |
| inb = png_gamma_nxmbit_correct( |
| (inb + *sp++) >> shift, correct, 16U-shift, bit_depth); |
| |
| bits -= bit_depth; |
| ob = ob | (inb << bits); |
| if (bits == 0U) |
| bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U; |
| } |
| while (sp < ep); |
| |
| UNTESTED |
| } |
| |
| else /* low bit GA intermediate format */ |
| { |
| debug((shifts >> 8) == 1U && shift < 16U); |
| debug(!tr->encode_alpha && !tr->optimize_alpha); |
| debug(tc->transparent_alpha); |
| |
| /* Gray is first then the alpha component, the alpha component is just |
| * mapped to 0 or 1. |
| */ |
| do |
| { |
| unsigned int gray = *sp++ << 8; /* high bits first */ |
| unsigned int alpha; |
| gray += *sp++; |
| |
| alpha = (*sp++ << 8); |
| alpha += *sp++; |
| |
| if (alpha == 0U) |
| gray = 0U; /* will be replaced later */ |
| |
| else |
| { |
| gray = png_gamma_nxmbit_correct(gray >> shift, correct, |
| 16U-shift, bit_depth); |
| debug(alpha == 65535U); |
| alpha = (1U << bit_depth)-1U; |
| } |
| |
| bits -= bit_depth; |
| ob = ob | (gray << bits); |
| bits -= bit_depth; |
| ob = ob | (alpha << bits); |
| |
| if (bits == 0U) |
| bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U; |
| } |
| while (sp < ep-2U); |
| } |
| |
| if (bits < 8U) |
| *dp++ = PNG_BYTE(ob); |
| |
| debug(sp == ep+1U); |
| } |
| |
| else |
| { |
| png_uint_32 alpha_scale; |
| const unsigned int channels = PNG_TC_CHANNELS(*tc); |
| unsigned int channel, alpha; |
| |
| debug((bit_depth == 8U || bit_depth == 16U) && |
| (shifts >> (4*channels)) == 1U); |
| |
| /* Note that 'encode_alpha' turns on gamma encoding of the alpha |
| * channel (and this is a really weird operation!) |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 || tr->encode_alpha) |
| alpha_scale = alpha = 0U; |
| |
| else |
| { |
| alpha = shifts >> (4U*(channels-1U)); |
| alpha_scale = tr->channel_scale[channels-1U]; |
| } |
| |
| channel = 1U; |
| |
| if (bit_depth == 16U) |
| { |
| do |
| { |
| unsigned int inb = *sp++ << 8, shift; |
| inb += *sp++; |
| |
| if (channel == 1U) |
| channel = shifts; |
| |
| shift = channel & 0xFU; |
| inb >>= shift; |
| |
| /* The 16-16bit scaling factor equation may be off-by-1 but this |
| * hardly matters for alpha or for gamma operations. |
| */ |
| if (channel == alpha) |
| inb = (inb * alpha_scale + 0x8000U) >> 16; |
| |
| else |
| inb = png_gamma_nxmbit_correct(inb, correct, 16U-shift, 16U); |
| |
| channel >>= 4; /* for the next channel, or the shibboleth */ |
| *dp++ = PNG_BYTE(inb >> 8); |
| *dp++ = PNG_BYTE(inb); |
| } |
| while (sp < ep); |
| |
| debug(channel == 1U && sp == ep+1U); |
| } |
| |
| else /* bit_depth == 8U */ |
| { |
| do |
| { |
| unsigned int inb = *sp++ << 8, shift; |
| inb += *sp++; |
| |
| if (channel == 1U) |
| channel = shifts; |
| |
| shift = channel & 0xFU; |
| inb >>= shift; |
| |
| if (channel == alpha) |
| inb = (inb * alpha_scale + 0x800000U) >> 24; |
| |
| else |
| inb = png_gamma_nxmbit_correct(inb, correct, 16U-shift, 8U); |
| |
| channel >>= 4; /* for the next channel, or the shibboleth */ |
| *dp++ = PNG_BYTE(inb); |
| } |
| while (sp < ep); |
| |
| debug(channel == 1U && sp == ep+1U); |
| } |
| } |
| # undef png_ptr |
| } |
| |
| #ifdef PNG_READ_ALPHA_MODE_SUPPORTED |
| static void |
| png_do_gamma16_up_optimize(png_transformp *transform, png_transform_controlp tc) |
| /* As above, but the alpha channel is 'optimized' */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const png_fixed_point correct = tr->correct; |
| |
| /* The input always as 16 bits, the output 8 or 16. There is always an alpha |
| * channel and it is converted to the 'optimized' form, where pixels with |
| * alpha not 0.0 or 1.0 are left in linear form (not gamma corrected.) Where |
| * bit depth convertion is required it is from 16-bits to 8-bits and the |
| * DIV257 macro can be used. |
| * |
| * The following affirms and NOT_REACHED cases are consequences of the way |
| * the background (compose) code works: |
| */ |
| affirm(tr->optimize_alpha && !tr->encode_alpha && tc->bit_depth == 16U); |
| |
| /* TODO: split this into separate functions */ |
| switch (tr->to_bit_depth) |
| { |
| case 8U: /* 16-bit --> 8-bit */ |
| tc->sp = dp; |
| tc->bit_depth = 8U; |
| tc->gamma = tr->to_gamma; |
| |
| switch (PNG_TC_CHANNELS(*tc)) |
| { |
| case 2:/* GA */ |
| debug(tr->shifts == 0x100U); |
| ep -= 3U; /*SAFETY*/ |
| |
| do |
| { |
| png_uint_32 alpha = PNG_DIV257((sp[2] << 8) + sp[3]); |
| |
| switch (alpha) |
| { |
| case 0U: |
| dp[1] = dp[0] = 0U; |
| break; |
| |
| default: /* optimized case: linear color data */ |
| dp[0] = png_check_byte(png_ptr, |
| PNG_DIV257((sp[0] << 8) + sp[1])); |
| dp[1] = PNG_BYTE(alpha); |
| break; |
| |
| case 255U: /* opaque pixels are encoded */ |
| dp[0] = PNG_BYTE(png_gamma_nxmbit_correct( |
| (sp[0] << 8) + sp[1], correct, 16U, 8U)); |
| dp[1] = 255U; |
| break; |
| } |
| |
| sp += 4U; |
| dp += 2U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+3U); |
| break; |
| |
| case 4:/* RGBA */ |
| debug(tr->shifts == 0x10000U); |
| ep -= 7U; /*SAFETY*/ |
| |
| do |
| { |
| png_uint_32 alpha = PNG_DIV257((sp[6] << 8) + sp[7]); |
| |
| switch (alpha) |
| { |
| case 0U: |
| memset(dp, 0U, 4U); |
| break; |
| |
| default: /* optimized case: linear color data */ |
| dp[0] = PNG_BYTE(PNG_DIV257((sp[0] << 8) + sp[1])); |
| dp[1] = PNG_BYTE(PNG_DIV257((sp[2] << 8) + sp[3])); |
| dp[2] = PNG_BYTE(PNG_DIV257((sp[4] << 8) + sp[5])); |
| dp[3] = PNG_BYTE(alpha); |
| break; |
| |
| case 255U: /* opaque pixels are encoded */ |
| dp[0] = PNG_BYTE(png_gamma_nxmbit_correct( |
| (sp[0] << 8) + sp[1], correct, 16U, 8U)); |
| dp[1] = PNG_BYTE(png_gamma_nxmbit_correct( |
| (sp[2] << 8) + sp[3], correct, 16U, 8U)); |
| dp[2] = PNG_BYTE(png_gamma_nxmbit_correct( |
| (sp[4] << 8) + sp[5], correct, 16U, 8U)); |
| dp[3] = 255U; |
| break; |
| } |
| |
| sp += 8U; |
| dp += 4U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+7U); |
| break; |
| |
| default: |
| NOT_REACHED; |
| break; |
| } |
| break; |
| |
| case 16: /* 16-bit to 16-bit */ |
| tc->sp = dp; |
| tc->bit_depth = 16U; |
| tc->gamma = tr->to_gamma; |
| |
| switch (PNG_TC_CHANNELS(*tc)) |
| { |
| case 2:/* GA */ |
| debug(tr->shifts == 0x100U); |
| ep -= 3U; /*SAFETY*/ |
| |
| do |
| { |
| unsigned int alpha = (sp[2] << 8) + sp[3]; |
| |
| switch (alpha) |
| { |
| case 0U: |
| memset(dp, 0U, 4U); |
| break; |
| |
| default: /* optimized case: linear color data */ |
| if (dp != sp) |
| { |
| memcpy(dp, sp, 4U); |
| UNTESTED |
| } |
| break; |
| |
| case 65535U: /* opaque pixels are encoded */ |
| { |
| unsigned int gray = png_gamma_nxmbit_correct( |
| (sp[0] << 8) + sp[1], correct, 16U, 16U); |
| dp[0] = PNG_BYTE(gray >> 8); |
| dp[1] = PNG_BYTE(gray); |
| } |
| dp[3] = dp[2] = 255U; |
| break; |
| } |
| |
| sp += 4U; |
| dp += 4U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+3U); |
| break; |
| |
| case 4:/* RGBA */ |
| debug(tr->shifts == 0x10000U); |
| ep -= 7U; /*SAFETY*/ |
| |
| do |
| { |
| unsigned int alpha = (sp[6] << 8) + sp[7]; |
| |
| switch (alpha) |
| { |
| case 0U: |
| memset(dp, 0U, 8U); |
| break; |
| |
| default: /* optimized case: linear color data */ |
| if (dp != sp) |
| { |
| memcpy(dp, sp, 8U); |
| UNTESTED |
| } |
| break; |
| |
| case 65535U: /* opaque pixels are encoded */ |
| { |
| unsigned int c = png_gamma_nxmbit_correct( |
| (sp[0] << 8) + sp[1], correct, 16U, 16U); |
| dp[0] = PNG_BYTE(c >> 8); |
| dp[1] = PNG_BYTE(c); |
| |
| c = png_gamma_nxmbit_correct( |
| (sp[2] << 8) + sp[3], correct, 16U, 16U); |
| dp[2] = PNG_BYTE(c >> 8); |
| dp[3] = PNG_BYTE(c); |
| |
| c = png_gamma_nxmbit_correct( |
| (sp[4] << 8) + sp[5], correct, 16U, 16U); |
| dp[4] = PNG_BYTE(c >> 8); |
| dp[5] = PNG_BYTE(c); |
| } |
| dp[7] = dp[6] = 255U; |
| break; |
| } |
| |
| sp += 8U; |
| dp += 8U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+7U); |
| break; |
| |
| default: |
| NOT_REACHED; |
| break; |
| } |
| break; |
| |
| default: |
| NOT_REACHED; |
| break; |
| } |
| # undef png_ptr |
| } |
| #endif /* READ_ALPHA_MODE */ |
| |
| static void |
| png_do_scale16_up(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const unsigned int bit_depth = tr->to_bit_depth; |
| |
| affirm(tc->bit_depth == 16U && bit_depth < 8U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| |
| /* This is exactly the same as above but without the gamma correction and |
| * without the 8-bit target support. The code handles one or two channels, |
| * but the result is not a PNG format unless the number of channels is just |
| * 1 (grayscale). |
| * |
| * For multi-channel low bit depth the channels are packed into bytes using |
| * the standard PNG big-endian packing. |
| */ |
| affirm((tc->format & PNG_FORMAT_FLAG_COLOR) == 0); |
| /* The alpha shift is actually ignored; at present we only get here with an |
| * alpha channel if it is to be removed for transparent alpha processing. |
| */ |
| debug(tc->format & PNG_FORMAT_FLAG_ALPHA ? |
| (tr->shifts >> 8) == 1U : (tr->shifts >> 4) == 1U); |
| debug(tc->transparent_alpha); |
| |
| tc->sp = dp; |
| /* This is a pure scaling operation so sBIT is not invalidated or altered. */ |
| tc->bit_depth = bit_depth; |
| |
| /* TODO: maybe do this properly and use the alpha shift, but only the top bit |
| * matters. |
| */ |
| { |
| const unsigned int shift = tr->shifts & 0xFU; |
| const png_uint_32 factor = tr->channel_scale[0]; |
| const png_uint_32 round = 1U << (31U-bit_depth); |
| unsigned int bits = 8U; |
| unsigned int ob = 0U; |
| |
| do |
| { |
| png_uint_32 inb = *sp++ << 8; /* high bits first */ |
| inb += *sp++; |
| |
| inb = ((inb >> shift) * factor + round) >> (32U-bit_depth); |
| bits -= bit_depth; |
| ob = ob | (inb << bits); |
| if (bits == 0U) |
| bits = 8U, *dp++ = PNG_BYTE(ob), ob = 0U; |
| } |
| while (sp < ep); |
| |
| if (bits < 8U) |
| *dp++ = PNG_BYTE(ob); |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_gamma8_down(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp + 1U/*safety*/; |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const png_fixed_point correct = tr->correct; |
| const png_uint_32 shifts = tr->shifts; |
| |
| affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| debug((shifts & 0x8888U) == 0U); /* all shifts 7 or less */ |
| debug(!tr->encode_alpha && !tr->optimize_alpha); /* only set for 16 bits */ |
| |
| sp += PNG_TC_ROWBYTES(*tc); |
| tc->sp = dp; |
| tc->bit_depth = tr->to_bit_depth; |
| tc->gamma = tr->to_gamma; |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| { |
| png_uint_32 alpha_scale; |
| unsigned int channel, alpha; |
| |
| debug((shifts >> (4*PNG_TC_CHANNELS(*tc))) == 1U); |
| |
| /* We are going down so alpha, if present, is first. Notice that the init |
| * routine has to reverse both 'shifts' and 'channel_scale' for the _down |
| * cases. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0) |
| alpha_scale = alpha = 0U; |
| |
| else |
| { |
| alpha = shifts; |
| alpha_scale = tr->channel_scale[0U]; |
| } |
| |
| channel = 1U; |
| |
| do /* 8-bit --> 16-bit */ |
| { |
| unsigned int inb = *--sp, shift; |
| |
| if (channel == 1U) |
| channel = shifts; |
| |
| shift = channel & 0xFU; |
| inb >>= shift; |
| |
| if (channel == alpha) /* unencoded alpha, must scale */ |
| inb = (inb * alpha_scale + 0x8000U) >> 16; |
| |
| else |
| inb = png_gamma_nxmbit_correct(inb, correct, 8U-shift, 16U); |
| |
| channel >>= 4; |
| |
| *--dp = PNG_BYTE(inb); |
| *--dp = PNG_BYTE(inb >> 8); |
| } |
| while (dp > ep); |
| |
| debug(channel == 1U && dp == ep-1U); |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_expand8_down(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp + 1U/*safety*/; |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| const png_uint_32 shifts = tr->shifts; |
| |
| affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| |
| sp += PNG_TC_ROWBYTES(*tc); |
| tc->sp = dp; |
| tc->bit_depth = 16U; |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| { |
| png_uint_32 channel = 1U; |
| png_const_uint_32p scale = 0U; |
| |
| do /* 8-bit -> 16-bit */ |
| { |
| unsigned int inb = *--sp, shift; |
| |
| if (channel == 1U) |
| channel = shifts, scale = tr->channel_scale; |
| |
| shift = channel & 0xFU; |
| channel >>= 4; |
| inb >>= shift; |
| inb = (inb * *scale++ + 0x8000U) >> 16; |
| /* dp starts beyond the end: */ |
| *--dp = PNG_BYTE(inb); |
| *--dp = PNG_BYTE(inb >> 8); |
| } |
| while (dp > ep); |
| |
| debug(channel == 1U && dp == ep-1U); |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_expand8_down_fast(png_transformp *transform, png_transform_controlp tc) |
| /* Optimized version of the above for when the sBIT settings are all a full 8 |
| * bits (the normal case). |
| */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp + 1U/*safety*/; |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| |
| affirm(tc->bit_depth == 8U && tr->to_bit_depth == 16U); |
| affirm(tr->shifts != 0U/*uninitialized*/); |
| |
| sp += PNG_TC_ROWBYTES(*tc); |
| tc->sp = dp; |
| tc->bit_depth = 16U; |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| do |
| dp -= 2, dp[0] = dp[1] = *--sp; |
| while (dp > ep); |
| |
| debug(dp == ep-1U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_gamma_uncached(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| |
| debug(tc->init == PNG_TC_INIT_FINAL); |
| |
| /* Set this first; the result says if the sBIT data is significant, but it is |
| * ignored here. |
| */ |
| (void)init_gamma_sBIT(tr, tc); |
| |
| /* If png_set_alpha_mode is called but no background processing needs to be |
| * done (because there is no alpha channel or tRNS) we get to here with |
| * potentially spurious alpha mode flags. |
| */ |
| if (!(tc->format & PNG_FORMAT_FLAG_ALPHA)) |
| tr->encode_alpha = tr->optimize_alpha = 0U; |
| |
| /* Use separate functions for the two input depths but not for the five |
| * possible output depths and four channel counts. |
| */ |
| if (tc->bit_depth == 8U) |
| { |
| if (tr->to_bit_depth <= 8U) |
| tr->tr.fn = png_do_gamma8_up; |
| |
| else |
| { |
| debug(tr->to_bit_depth == 16U); |
| reverse_gamma_sBIT(tr); |
| tr->tr.fn = png_do_gamma8_down; |
| } |
| } |
| |
| else |
| { |
| affirm(tc->bit_depth == 16U); |
| # ifdef PNG_READ_ALPHA_MODE_SUPPORTED |
| if (!tr->optimize_alpha) |
| tr->tr.fn = png_do_gamma16_up; |
| else |
| tr->tr.fn = png_do_gamma16_up_optimize; |
| # else /* !READ_ALPHA_MODE */ |
| tr->tr.fn = png_do_gamma16_up; |
| # endif /* !READ_ALPHA_MODE */ |
| } |
| |
| /* Since the 'do' routines always perform gamma correction they will always |
| * expand the significant bits to the full output bit depth. |
| */ |
| tc->invalid_info |= PNG_INFO_sBIT; |
| tc->bit_depth = tr->to_bit_depth; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = |
| png_check_byte(png_ptr, tc->bit_depth); |
| if (tr->encode_alpha) |
| tc->sBIT_A = tc->sBIT_G; |
| tc->gamma = tr->to_gamma; |
| # undef png_ptr |
| } |
| |
| #ifdef PNG_READ_sBIT_SUPPORTED |
| static unsigned int |
| tc_sBIT(png_const_transform_controlp tc) |
| /* Determine the maximum number of significant bits in the row at this point. |
| * This uses the png_struct::sig_bit field if it has not been invalidated, |
| * otherwise it just returns the current bit depth. |
| */ |
| { |
| const png_structrp png_ptr = tc->png_ptr; |
| unsigned int bit_depth = tc->bit_depth; |
| |
| if ((tc->invalid_info & PNG_INFO_sBIT) == 0U) |
| { |
| /* Normally the bit depth will not have been changed from the original PNG |
| * depth, but it currently is changed by the grayscale expand to 8 bits, |
| * an operation which doesn't invalidate sBIT. |
| */ |
| unsigned int sBIT; |
| |
| if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0U) |
| { |
| /* Must use the largest of the sBIT depths, except that unset values |
| * take priority. |
| */ |
| sBIT = png_ptr->sig_bit.red && png_ptr->sig_bit.green && |
| png_ptr->sig_bit.blue; |
| |
| if (sBIT != 0U) |
| { |
| sBIT = png_ptr->sig_bit.red; |
| |
| if (png_ptr->sig_bit.green > sBIT) |
| sBIT = png_ptr->sig_bit.green; |
| if (png_ptr->sig_bit.blue > sBIT) |
| sBIT = png_ptr->sig_bit.blue; |
| } |
| } |
| |
| else |
| sBIT = png_ptr->sig_bit.gray; |
| |
| if (sBIT > 0U && sBIT < bit_depth) |
| bit_depth = sBIT; |
| } |
| |
| return bit_depth; |
| } |
| #else /* !READ_sBIT */ |
| # define tc_sBIT(tc) ((tc)->bit_depth) |
| #endif /* READ_sBIT */ |
| |
| static void |
| png_init_gamma(png_transformp *transform, png_transform_controlp tc) |
| { |
| const png_structrp png_ptr = tc->png_ptr; |
| png_transform_gamma *tr = |
| png_transform_cast(png_transform_gamma, *transform); |
| |
| if (tc->init == PNG_TC_INIT_FORMAT) |
| { |
| /* This should only happen for the final encode gamma transform, which |
| * never initializes the target bit depth (see png_set_gamma and |
| * png_set_alpha_mode). The affirm is required here; in we can't continue |
| * safely if the bit depth has been set somehow. |
| */ |
| debug(tr->tr.order == PNG_TR_GAMMA_ENCODE); |
| affirm(tr->to_gamma > 0 && tr->to_bit_depth == 0U); |
| |
| /* At this point the output gamma should not have been set yet: */ |
| debug(png_ptr->row_gamma == 0); |
| |
| /* The following must be true; png_set_gamma and png_set_alpha_mode set |
| * (or default) the PNG gamma and other routines that insert a gamma |
| * transform must only do in PNG_TC_INIT_FINAL: |
| */ |
| debug(tc->gamma > 0); |
| |
| /* At this point the data gamma must be updated so that we get the correct |
| * png_struct::row_gamma at the end of the init: |
| */ |
| tc->gamma = tr->to_gamma; |
| |
| /* For safety invalidate the sBIT information too; we don't know yet |
| * whether a gamma transform will be required but if it is the sBIT |
| * information becomes invalid. |
| */ |
| tc->invalid_info |= PNG_INFO_sBIT; |
| } |
| |
| else /* PNG_TC_INIT_FINAL */ |
| { |
| /* It is very bad if we get here when processing a row: */ |
| affirm(tc->init == PNG_TC_INIT_FINAL && png_ptr->row_bit_depth > 0); |
| |
| /* There are three cases: |
| * |
| * 1) Gamma correction is required, output bit depth may need to be |
| * defaulted. |
| * 2) Gamma correction is not required but a bit depth change is |
| * necessary. |
| * 3) Neither is required; the transform can be eliminated. |
| * |
| * First default the bit depth if it is not already set. Note that if the |
| * output is a palette then 'row_bit_depth' refers to the palette size and |
| * 8U must be used here. tc->palette is irrelevant; it only tells us that |
| * the data came from a palette. |
| */ |
| if (tr->to_bit_depth == 0) |
| { |
| if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0U) |
| tr->to_bit_depth = 8U; |
| |
| else |
| tr->to_bit_depth = png_ptr->row_bit_depth; |
| } |
| |
| /* (1); is gamma correction required? If tc->gamma is 0 at this point it |
| * is not, but then the png_struct::row_gamma should be 0 too. |
| */ |
| implies(tc->gamma == 0, png_ptr->row_gamma == 0); |
| implies(tr->to_gamma == 0, tc->gamma == 0); |
| |
| if (!png_gamma_equal(png_ptr, tc->gamma, tr->to_gamma, &tr->correct, |
| tc_sBIT(tc))) |
| { |
| /* First make sure the input doesn't have a tRNS chunk which needs to |
| * be expanded now; if it does push_gamma_expand will push an |
| * appropriate transform *before* this one and we need to return |
| * immediately (the caller will call back to this function). |
| */ |
| if (push_gamma_expand(transform, tc, 0/*need alpha*/)) |
| { |
| affirm(tc->bit_depth >= 8U && |
| (tc->invalid_info & PNG_INFO_tRNS) != 0U && |
| *transform != &tr->tr); |
| return; |
| } |
| |
| debug(*transform == &tr->tr && tc->bit_depth >= 8U); |
| |
| /* The format is now 8 or 16-bit G, GA, RGB or RGBA and gamma |
| * correction is required. |
| */ |
| png_init_gamma_uncached(transform, tc); |
| /* TODO: implement caching for the !tc->caching cases! */ |
| return; |
| } |
| |
| /* The cases where the two gamma values are close enough to be considered |
| * equal. The code lies about the gamma; this prevents apps and the |
| * simplified API getting into loops or bad conditions because the gamma |
| * was not set to the expected value. |
| * |
| * Note that png_transform_control::gamma is only set here if both the |
| * input and output gamma values are known, otherwise the transform |
| * introduces a spurious know gamma value. |
| */ |
| if (tr->to_gamma > 0 && tc->gamma > 0) |
| tc->gamma = tr->to_gamma; |
| |
| if (tr->to_bit_depth > tc->bit_depth) |
| { |
| /* This is either the to-linear operation, in which case the expected |
| * bit depth is 16U, or it is the final encode in the case where an |
| * 'expand' operation was also specified. |
| * |
| * We don't care about the PNG_TR_GAMMA_ENCODE case because we know |
| * that there has to be an expand operation further down the pipeline. |
| */ |
| if (tr->tr.order < PNG_TR_GAMMA_ENCODE) |
| { |
| affirm(tr->to_bit_depth == 16U); |
| |
| if (push_gamma_expand(transform, tc, 0/*need alpha*/)) |
| { |
| affirm(tc->bit_depth == 8U && |
| (tc->invalid_info & PNG_INFO_tRNS) != 0U && |
| *transform != &tr->tr); |
| return; |
| } |
| |
| debug(*transform == &tr->tr); |
| affirm(tc->bit_depth == 8U); /* if 16U we would not be here! */ |
| |
| /* not using byte_ops here, but if there is no sBIT required |
| * (normally the case) the fast code can be used: |
| */ |
| if (init_gamma_sBIT(tr, tc)) |
| tr->tr.fn = png_do_expand8_down; |
| |
| else |
| tr->tr.fn = png_do_expand8_down_fast; |
| |
| tc->bit_depth = 16U; |
| } |
| |
| else /* PNG_TR_GAMMA_ENCODE: nothing need be done */ |
| tr->tr.fn = NULL; |
| } |
| |
| else if (tr->to_bit_depth < tc->bit_depth) |
| { |
| /* No gamma correction but bit depth *reduction* is required. Expect |
| * the 'from' bit depth to always be 16, otherwise this transform |
| * should not have been pushed. Also expect this to be the gamma |
| * 'encode' operation at the end of the arithmetic. |
| */ |
| affirm(tc->bit_depth == 16U && tr->tr.order == PNG_TR_GAMMA_ENCODE); |
| |
| /* If the target bit depth is 8-bit delay the operation and use the |
| * standard 16-8-bit scale code. For low bit depth do it now. |
| */ |
| if (tr->to_bit_depth == 8U) |
| { |
| png_set_scale_16(png_ptr); |
| tr->tr.fn = NULL; |
| } |
| |
| else /* low bit depth */ |
| { |
| (void)init_gamma_sBIT(tr, tc); |
| tr->tr.fn = png_do_scale16_up; |
| tc->bit_depth = tr->to_bit_depth; |
| } |
| } |
| |
| else /* gamma !significant and nothing to do */ |
| tr->tr.fn = NULL; |
| } |
| } |
| |
| static png_fixed_point |
| translate_gamma_flags(png_const_structrp png_ptr, png_fixed_point gamma, |
| int is_screen) |
| /* If 'is_screen' is set this returns the inverse of the supplied value; i.e. |
| * this routine always returns an encoding value. |
| */ |
| { |
| /* Check for flag values. The main reason for having the old Mac value as a |
| * flag is that it is pretty near impossible to work out what the correct |
| * value is from Apple documentation - a working Mac system is needed to |
| * discover the value! |
| */ |
| switch (gamma) |
| { |
| case PNG_DEFAULT_sRGB: |
| case PNG_GAMMA_sRGB: |
| case PNG_FP_1/PNG_GAMMA_sRGB: /* stupid case: -100000 */ |
| gamma = PNG_GAMMA_sRGB_INVERSE; |
| break; |
| |
| case PNG_GAMMA_MAC_18: |
| case PNG_FP_1/PNG_GAMMA_MAC_18: /* stupid case: -50000 */ |
| gamma = PNG_GAMMA_MAC_INVERSE; |
| break; |
| |
| default: |
| if (is_screen) |
| { |
| /* Check for a ridiculously low value; this will result in an |
| * overflow |
| * in the reciprocal calculation. |
| */ |
| if (gamma < 5) |
| { |
| png_app_error(png_ptr, "invalid screen gamma (too low)"); |
| gamma = 0; |
| } |
| |
| else if (gamma != PNG_FP_1) /* optimize linear */ |
| gamma = png_reciprocal(gamma); |
| } |
| |
| else if (gamma <= 0) |
| { |
| png_app_error(png_ptr, "invalid file gamma (too low)"); |
| gamma = 0; |
| } |
| break; |
| } |
| |
| return gamma; |
| } |
| |
| static png_transform_gamma * |
| add_gamma_transform(png_structrp png_ptr, unsigned int order, |
| png_fixed_point gamma, unsigned int bit_depth, int force) |
| { |
| /* Add a png_transform_gamma transform at the given position; this is a |
| * utility which just adds the transform and (unconditionally) overwrites the |
| * to_gamma field. gamma must be valid. If 'force' is true the gamma value |
| * in an existing transform will be overwritten, otherwise this is just a |
| * default value. |
| */ |
| png_transform_gamma *tr = png_transform_cast(png_transform_gamma, |
| png_add_transform(png_ptr, sizeof (png_transform_gamma), png_init_gamma, |
| order)); |
| |
| if (force || tr->to_gamma == 0) |
| tr->to_gamma = gamma; |
| |
| tr->to_bit_depth = bit_depth; |
| |
| return tr; |
| } |
| |
| void PNGFAPI |
| png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, |
| png_fixed_point file_gamma) |
| { |
| png_debug(1, "in png_set_gamma_fixed"); |
| |
| /* Validate the passed in file gamma value: */ |
| file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); |
| |
| /* The returned value may be 0, this results in a png_app_error above which |
| * may be ignored; if that happens simply ignore the setting. |
| */ |
| if (file_gamma > 0) |
| { |
| /* Set the colorspace gamma value unconditionally - this overrides the |
| * value in the PNG file if a gAMA chunk was present. png_set_alpha_mode |
| * provides a different, easier, way to default the file gamma. |
| */ |
| png_ptr->colorspace.gamma = file_gamma; |
| if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) |
| png_ptr->colorspace.flags = PNG_COLORSPACE_HAVE_GAMMA; |
| else |
| png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; |
| } |
| |
| /* Do the same thing with the screen gamma; check it and handle it if valid. |
| * This adds/sets the encoding of the final gamma transform in the chain. |
| * png_set_alpha_mode does the same thing. |
| */ |
| scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); |
| |
| if (scrn_gamma > 0) |
| (void)add_gamma_transform(png_ptr, PNG_TR_GAMMA_ENCODE, scrn_gamma, |
| 0/*bit depth*/, 1/*force to_gamma to scrn_gamma*/); |
| } |
| |
| #ifdef PNG_FLOATING_POINT_SUPPORTED |
| static png_fixed_point |
| convert_gamma_value(png_structrp png_ptr, double output_gamma) |
| { |
| /* The following silently ignores cases where fixed point (times 100,000) |
| * gamma values are passed to the floating point API. This is safe and it |
| * means the fixed point constants work just fine with the floating point |
| * API. The alternative would just lead to undetected errors and spurious |
| * bug reports. Negative values fail inside the _fixed API unless they |
| * correspond to the flag values. |
| */ |
| if (output_gamma < 0 || output_gamma > 128) |
| output_gamma *= .00001; |
| |
| return png_fixed(png_ptr, output_gamma, "gamma value"); |
| } |
| |
| void PNGAPI |
| png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) |
| { |
| png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), |
| convert_gamma_value(png_ptr, file_gamma)); |
| } |
| #endif /* FLOATING_POINT */ |
| #endif /* READ_GAMMA */ |
| |
| #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED |
| static void |
| png_do_rtog_48(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| const png_uint_32 r = (*transform)->args >> 16; |
| const png_uint_32 g = (*transform)->args & 0xFFFFU; |
| const png_uint_32 b = 65536U - r - g; |
| |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 6U; |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_FLAG_COLOR && |
| (tc->gamma == 0U || !png_gamma_significant(png_ptr, tc->gamma, 16U))); |
| |
| tc->sp = dp; |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR); |
| |
| while (sp <= ep) |
| { |
| png_uint_32 gray = (((sp[0] << 8) + sp[1]) * r + |
| ((sp[2] << 8) + sp[3]) * g + |
| ((sp[4] << 8) + sp[5]) * b + 32767U) >> 16; |
| |
| debug(gray < 65536U); |
| *dp++ = PNG_BYTE(gray >> 8); |
| *dp++ = PNG_BYTE(gray); |
| sp += 6U; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_rtog_64(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| const png_uint_32 r = (*transform)->args >> 16; |
| const png_uint_32 g = (*transform)->args & 0xFFFFU; |
| const png_uint_32 b = 65536U - r - g; |
| |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 8U; |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| debug(tc->bit_depth == 16U && |
| tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA && |
| (tc->gamma == 0U || !png_gamma_significant(png_ptr, tc->gamma, 16U))); |
| |
| tc->sp = dp; |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR); |
| |
| while (sp <= ep) |
| { |
| png_uint_32 gray = (((sp[0] << 8) + sp[1]) * r + |
| ((sp[2] << 8) + sp[3]) * g + |
| ((sp[4] << 8) + sp[5]) * b + 32767U) >> 16; |
| |
| debug(gray < 65536U); |
| *dp++ = PNG_BYTE(gray >> 8); |
| *dp++ = PNG_BYTE(gray); |
| sp += 6U; |
| *dp++ = *sp++; /* alpha */ |
| *dp++ = *sp++; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_rgb_to_gray_arithmetic(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* This only gets used in the final init stage: */ |
| debug(tc->init == PNG_TC_INIT_FINAL && tc->bit_depth == 16U && |
| (tc->format & PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA)) == |
| PNG_FORMAT_FLAG_COLOR); |
| |
| (*transform)->fn = (tc->format & PNG_FORMAT_FLAG_ALPHA) ? png_do_rtog_64 : |
| png_do_rtog_48; |
| |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR); |
| tc->invalid_info |= PNG_INFO_sBIT; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(png_ptr, tc->bit_depth); |
| # undef png_ptr |
| } |
| |
| typedef struct |
| { |
| png_transform tr; |
| png_fixed_point red_coefficient; |
| png_fixed_point green_coefficient; |
| unsigned int coefficients_set :1; |
| unsigned int error_action :2; |
| } png_transform_rgb_to_gray; |
| |
| static void |
| png_update_rgb_status(png_structrp png_ptr, png_transformp *transform) |
| { |
| png_transform_rgb_to_gray *tr = png_transform_cast(png_transform_rgb_to_gray, |
| *transform); |
| |
| png_ptr->rgb_to_gray_status = 1U; |
| tr->tr.fn = NULL; /* one warning/error only */ |
| |
| switch (tr->error_action) |
| { |
| case PNG_ERROR_ACTION_WARN: |
| png_warning(png_ptr, "RGB to gray found nongray pixel"); |
| break; |
| |
| case PNG_ERROR_ACTION_ERROR: |
| png_error(png_ptr, "RGB to gray found nongray pixel"); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| static void |
| png_do_rgb_check24(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue |
| * channels are not equal. |
| */ |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U; |
| |
| debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_FLAG_COLOR); |
| |
| while (sp <= ep) |
| { |
| if ((sp[0] ^ sp[1]) | (sp[2] ^ sp[1])) |
| { |
| png_update_rgb_status(png_ptr, transform); |
| break; |
| } |
| |
| sp += 3U; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_rgb_check32(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue |
| * channels are not equal and alpha is not zero. |
| */ |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 4U; |
| |
| debug(tc->bit_depth == 8U && |
| tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA); |
| |
| while (sp <= ep) |
| { |
| if (((sp[0] ^ sp[1]) | (sp[2] ^ sp[1])) && sp[3] != 0) |
| { |
| png_update_rgb_status(png_ptr, transform); |
| break; |
| } |
| |
| sp += 4U; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_rgb_check48(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue |
| * channels are not equal. |
| */ |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 6U; |
| |
| debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_FLAG_COLOR); |
| |
| while (sp <= ep) |
| { |
| if ((sp[0] ^ sp[2]) | (sp[4] ^ sp[2]) | |
| (sp[1] ^ sp[3]) | (sp[5] ^ sp[3])) |
| { |
| png_update_rgb_status(png_ptr, transform); |
| break; |
| } |
| |
| sp += 6U; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_rgb_check64(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* Sets 'rgb_to_gray' status if a pixel is found where the red green and blue |
| * channels are not equal and alpha is not zero. |
| */ |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 8U; |
| |
| debug(tc->bit_depth == 16U && |
| tc->format == PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA); |
| |
| while (sp <= ep) |
| { |
| if (((sp[0] ^ sp[2]) | (sp[4] ^ sp[2]) | |
| (sp[1] ^ sp[3]) | (sp[5] ^ sp[3])) && |
| (sp[6] | sp[7]) != 0) |
| { |
| png_update_rgb_status(png_ptr, transform); |
| break; |
| } |
| |
| sp += 8U; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_rgb_to_gray(png_transformp *transform, png_transform_controlp tc) |
| { |
| png_structrp png_ptr = tc->png_ptr; |
| |
| /* Basic checks: if there is no color in the format this transform is not |
| * applicable. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0) |
| { |
| png_transform_rgb_to_gray *tr = png_transform_cast( |
| png_transform_rgb_to_gray, *transform); |
| |
| /* no colormap allowed: */ |
| affirm(tc->init && !(tc->format & PNG_FORMAT_FLAG_COLORMAP)); |
| /* no extra flags yet: */ |
| debug(!(tc->format & |
| PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA))); |
| /* at present no non-palette caching: */ |
| implies(tc->caching, tc->palette); |
| |
| if (tc->init == PNG_TC_INIT_FORMAT) |
| { |
| /* The convertion should just remove the 'COLOR' flag and do nothing |
| * else, but if a tRNS chunk is present this would invalidate it. |
| * Handle this by expanding it now. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette && |
| png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS)) |
| { |
| /* Only if expand was requested and not cancelled: */ |
| if (tc->expand_tRNS && !tc->strip_alpha) |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| |
| tc->invalid_info |= PNG_INFO_tRNS; /* prevent expansion later */ |
| } |
| |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR); |
| } |
| |
| else /* PNG_TC_INIT_FINAL */ |
| { |
| unsigned int index; /* channel to select (invalid) */ |
| png_byte sBIT_color; /* sBIT of that channel if valid */ |
| png_fixed_point r, g; /* Coefficients in range 0..65536 */ |
| |
| /* Push a tRNS transform if required. Because this is a push the |
| * transform the init needs to be run now. This needs to go in |
| * before the check on r==g==b because a color key might be used. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) == 0 && !tc->palette && |
| png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS)) |
| { |
| if (tc->expand_tRNS && !tc->strip_alpha) |
| { |
| png_transformp tr_expand = png_push_transform(png_ptr, |
| sizeof (png_expand), png_init_expand, transform, NULL); |
| |
| debug(*transform == tr_expand); |
| tr_expand->args |= PNG_EXPAND_tRNS; |
| png_init_expand(transform, tc); |
| /* Check for the infinite loop possibility: */ |
| affirm((tc->invalid_info & PNG_INFO_tRNS) != 0); |
| return; |
| } |
| |
| else |
| tc->invalid_info |= PNG_INFO_tRNS; |
| } |
| |
| { |
| png_fixed_point red, green; |
| |
| if (tr->coefficients_set) |
| { |
| red = tr->red_coefficient; |
| green = tr->green_coefficient; |
| } |
| |
| # ifdef PNG_COLORSPACE_SUPPORTED |
| else if ((png_ptr->colorspace.flags & |
| (PNG_COLORSPACE_HAVE_ENDPOINTS+PNG_COLORSPACE_INVALID)) |
| == PNG_COLORSPACE_HAVE_ENDPOINTS) |
| { |
| red = png_ptr->colorspace.end_points_XYZ.red_Y; |
| green = png_ptr->colorspace.end_points_XYZ.green_Y; |
| } |
| # endif |
| |
| else /* no colorspace support, assume sRGB */ |
| { |
| /* From IEC 61966-2-1:1999, the reverse transformation from sRGB |
| * RGB values to XYZ D65 values (not CIEXYZ!). These are not |
| * exact inverses of the forward transformation; they only have |
| * four (decimal) digits of precision. |
| * |
| * API CHANGE: in 1.7.0 the sRGB values from the official IEC |
| * specification are used, previously libpng used values from |
| * Charles Poynton's ColorFAQ of 1998-01-04. The original page |
| * is gone, however up to date information can be found below: |
| * |
| * http://www.poynton.com/ColorFAQ.html |
| * |
| * At the time of reading (20150628) this web site quotes the |
| * same values as below and cites ITU Rec 709 as the source. |
| */ |
| red = 21260; |
| green = 71520; |
| } |
| |
| /* Prior to 1.7 this calculation was done with 15-bit precision, |
| * this is because the code was written pre-muldiv and tried to |
| * work round the problems caused by the signs in integer |
| * calculations. |
| */ |
| (void)png_muldiv(&r, red, 65536, PNG_FP_1); |
| (void)png_muldiv(&g, green, 65536, PNG_FP_1); |
| } |
| |
| /* If the convertion can be deduced to select a single channel do so. |
| * If the error action is set to error just copy the red channel, if |
| * the coefficients select just one channel use that. |
| */ |
| if (tr->error_action == PNG_ERROR_ACTION_ERROR || r >= 65536) |
| index = 0U, sBIT_color = tc->sBIT_R; /* select red */ |
| |
| else if (g >= 65536) |
| index = 1U, sBIT_color = tc->sBIT_G; /* select green */ |
| |
| else if (r + g == 0) |
| index = 2U, sBIT_color = tc->sBIT_B; /* select blue */ |
| |
| else |
| index = 3U, sBIT_color = 0U/*UNUSED*/; |
| |
| if (index == 3U) |
| { |
| /* Arithmetic will have to be done. For this we need linear 16-bit |
| * data which must then be converted back to the required bit depth, |
| * png_init_gamma handles this. It may push other expand operations |
| * (it shouldn't but it can), so give it some space. |
| * |
| * The gamma must be restored to the original value, 0U for the bit |
| * depth means use the output bit depth. |
| */ |
| (void)add_gamma_transform(png_ptr, PNG_TR_GAMMA_ENCODE, tc->gamma, |
| 0U/*bit depth*/, 0/*default*/); |
| |
| /* If png_init_gamma is called with tc->gamma 0 it does the right |
| * thing in PNG_TC_INIT_FINAL; it just does any required bit depth |
| * adjustment. |
| */ |
| (void)add_gamma_transform(png_ptr, tr->tr.order + 0x10U, PNG_FP_1, |
| 16U, 1/*force: doesn't matter*/); |
| |
| { |
| /* This init routine will update the sBIT information |
| * appropriately. |
| */ |
| png_transformp tr_rtog = png_add_transform(png_ptr, 0/*size*/, |
| png_init_rgb_to_gray_arithmetic, tr->tr.order + 0x20U); |
| |
| /* r and g are known to be in the range 0..65535, so pack them |
| * into the 'args' argument of a new transform. |
| */ |
| tr_rtog->args = (((png_uint_32)r) << 16) + g; |
| } |
| } |
| |
| else /* index < 3 */ |
| { |
| /* TODO: does this need to select the correct sBIT value too? */ |
| png_add_rgb_to_gray_byte_ops(png_ptr, tc, index, |
| tr->tr.order + 0x10U); |
| tc->sBIT_G = sBIT_color; |
| } |
| |
| /* Prior to 1.7 libpng would always check for r!=g!=b. In 1.7 an extra |
| * error_action setting is added to prevent this overhead. |
| */ |
| if (tr->error_action) |
| tr->tr.fn = tc->bit_depth == 8 ? |
| ((tc->format & PNG_FORMAT_FLAG_ALPHA) ? |
| png_do_rgb_check32 : png_do_rgb_check24) : |
| ((tc->format & PNG_FORMAT_FLAG_ALPHA) ? |
| png_do_rgb_check64 : png_do_rgb_check48); |
| |
| else |
| tr->tr.fn = NULL; /* PNG_ERROR_ACTION_NO_CHECK */ |
| } |
| } |
| |
| else /* not color: transform not applicable */ |
| (*transform)->fn = NULL; |
| } |
| |
| void PNGFAPI |
| png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, |
| png_fixed_point red, png_fixed_point green) |
| /* API CHANGE: in 1.7 calling this on a palette PNG no longer causes the |
| * palette to be expanded (unless explicitly requested), rather it converts |
| * the palette to grayscale. |
| */ |
| { |
| /* The coefficients must be reasonable, the error handling is to warn (pre |
| * 1.7) or app error (1.7) and drop back to the cHRM definition of Y. The |
| * drop back is done in the init routine if relevant flag is unset. Passing |
| * negative values causes this default to be used without a warning. |
| */ |
| int pset = 0; |
| |
| if (red >= 0 && green >= 0) |
| { |
| if (red <= PNG_FP_1 && green <= PNG_FP_1 && red + green <= PNG_FP_1) |
| pset = 1; |
| |
| else /* overflow */ |
| png_app_error(png_ptr, "rgb_to_gray coefficients too large (ignored)"); |
| } |
| |
| { |
| png_transform_rgb_to_gray *tr = |
| png_transform_cast(png_transform_rgb_to_gray, |
| png_add_transform(png_ptr, sizeof (png_transform_rgb_to_gray), |
| png_init_rgb_to_gray, PNG_TR_RGB_TO_GRAY)); |
| |
| tr->error_action = 0x3U & error_action; |
| |
| if (red < 0 || green < 0) /* use cHRM default */ |
| tr->coefficients_set = 0U; |
| |
| else if (pset) /* else bad coefficients which get ignored */ |
| { |
| tr->coefficients_set = 1U; |
| tr->red_coefficient = red; |
| tr->green_coefficient = green; |
| } |
| } |
| } |
| |
| #ifdef PNG_FLOATING_POINT_SUPPORTED |
| /* Convert a RGB image to a grayscale of the same width. This allows us, |
| * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. |
| */ |
| |
| void PNGAPI |
| png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, |
| double green) |
| { |
| png_set_rgb_to_gray_fixed(png_ptr, error_action, |
| png_fixed(png_ptr, red, "rgb to gray red coefficient"), |
| png_fixed(png_ptr, green, "rgb to gray green coefficient")); |
| } |
| #endif /* FLOATING POINT */ |
| #endif /* RGB_TO_GRAY */ |
| |
| #ifdef PNG_READ_BACKGROUND_SUPPORTED |
| typedef struct |
| { |
| png_transform tr; |
| struct |
| { |
| png_color_16 background; |
| unsigned int need_expand :1; /* Background matches format of PNG */ |
| unsigned int rgb_to_gray :1; /* RGB-to-gray transform found */ |
| unsigned int compose_background :1; /* png_set_background */ |
| unsigned int associate_alpha :1; |
| unsigned int encode_alpha :1; |
| unsigned int optimize_alpha :1; |
| unsigned int background_is_gray :1; /* Background color is gray */ |
| unsigned int background_bit_depth :5; /* bit depth, 1..16 */ |
| unsigned int ntrans :3; /* 1..6 bytes */ |
| png_byte transparent_pixel[6]; |
| png_byte background_pixel[6]; |
| png_fixed_point background_gamma; |
| } st; /* to allow the whole state to be copied reliably */ |
| } png_transform_background; |
| |
| static void |
| resolve_background_color(png_transform_background *tr, |
| png_transform_controlp tc) |
| { |
| png_const_structp png_ptr = tc->png_ptr; |
| |
| /* Deduce the bit depth and color information for the background, the |
| * special case is when need_expand is set and the PNG has palette format, |
| * then (and only then) the background value is a palette index. |
| */ |
| if (tr->st.need_expand && tc->palette) |
| { |
| unsigned int i = tr->st.background.index; |
| png_byte r, g, b; |
| |
| if (i >= png_ptr->num_palette) |
| { |
| png_app_error(png_ptr, "background index out of range"); |
| tr->tr.fn = NULL; |
| return; |
| } |
| |
| tr->st.background_bit_depth = 8U; |
| r = png_ptr->palette[i].red; |
| g = png_ptr->palette[i].green; |
| b = png_ptr->palette[i].blue; |
| |
| if (r == g && g == b) |
| { |
| tr->st.background_is_gray = 1U; |
| tr->st.background.gray = g; |
| UNTESTED |
| } |
| |
| else |
| { |
| tr->st.background_is_gray = 0U; |
| tr->st.background.red = r; |
| tr->st.background.green = g; |
| tr->st.background.blue = b; |
| UNTESTED |
| } |
| } |
| |
| else /* background is not a palette index */ |
| { |
| int use_rgb; |
| png_uint_16 mask; |
| |
| /* First work out the bit depth and whether or not to use the RGB |
| * fields of the background. |
| */ |
| if (tr->st.need_expand) |
| { |
| affirm(!(tc->format & PNG_FORMAT_FLAG_COLORMAP)); |
| tr->st.background_bit_depth = |
| png_check_bits(png_ptr, png_ptr->bit_depth, 5U); |
| use_rgb = (png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0; |
| } |
| |
| else /* screen format background */ |
| { |
| /* If the final output is in palette format assume the background |
| * is in a matching format. This covers two cases, an original |
| * COLORMAP PNG and png_set_quantize. |
| */ |
| if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0) |
| tr->st.background_bit_depth = 8U; |
| |
| else |
| tr->st.background_bit_depth = |
| png_check_bits(png_ptr, png_ptr->row_bit_depth, 5U); |
| |
| use_rgb = (png_ptr->row_format & PNG_FORMAT_FLAG_COLOR) != 0; |
| } |
| |
| /* The PNG spec says to use the low bits of the values, so we mask out |
| * the high bits here (at present no warning is produced if they are |
| * set.) |
| */ |
| mask = png_check_u16(png_ptr, (1U << tr->st.background_bit_depth)-1U); |
| |
| if (use_rgb) |
| { |
| png_uint_16 r, g, b; |
| |
| r = tr->st.background.red & mask; |
| g = tr->st.background.green & mask; |
| b = tr->st.background.blue & mask; |
| |
| if (r == g && g == b) |
| { |
| tr->st.background_is_gray = 1U; |
| tr->st.background.gray = g; |
| } |
| |
| else |
| { |
| tr->st.background_is_gray = 0U; |
| tr->st.background.red = r; |
| tr->st.background.green = g; |
| tr->st.background.blue = b; |
| } |
| } |
| |
| else /* gray */ |
| { |
| tr->st.background_is_gray = 1U; |
| tr->st.background.gray = tr->st.background.gray & mask; |
| } |
| } |
| } |
| |
| static void |
| gamma_correct_background_component(png_const_structrp png_ptr, png_uint_16p cp, |
| unsigned int bdc, png_fixed_point correction, unsigned int bdout) |
| /* Utility function for gamma_correct_background. */ |
| { |
| unsigned int c = *cp; |
| |
| /* 0.0 and 1.0 are unchanged (and common): */ |
| if (c > 0U && c < (1U<<bdc)-1U) |
| { |
| if (correction != 0) |
| c = png_check_bits(png_ptr, |
| png_gamma_nxmbit_correct(c, correction, bdc, bdout), bdout); |
| |
| else if (bdc != bdout) |
| { |
| /* Scale the value from bdc to bdout bits. */ |
| png_int_32 i; |
| affirm(png_muldiv(&i, c, (1U<<bdout)-1U, (1U<<bdc)-1U)); |
| c = png_check_bits(png_ptr, i, bdout); |
| } |
| } |
| |
| else if (c != 0U) |
| c = (1U << bdout) - 1U; |
| |
| *cp = PNG_UINT_16(c); |
| PNG_UNUSED(png_ptr) /* if checking disabled */ |
| } |
| |
| static void |
| gamma_correct_background(png_transform_background *tr, |
| png_const_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_fixed_point correction = tc->gamma; |
| const unsigned int bdback = tr->st.background_bit_depth; |
| const unsigned int bdrow = tc->bit_depth; |
| |
| /* This is harmless if it fails but it will damage the output pixels - they |
| * won't have the requested color depth accuracy where the background is |
| * used. |
| */ |
| debug(bdback <= bdrow); |
| debug(tr->st.background_is_gray || (bdrow >= 8U && bdback >= 8U)); |
| |
| /* The background is assumed to be full precision; there is no sBIT |
| * information for it. The convertion converts from the current depth and |
| * gamma of the background to that in the transform control. It uses the |
| * full 16-bit precision when considering the gamma values even though this |
| * is probably spurious. |
| */ |
| if (correction != 0 && (tr->st.background_gamma == 0 || |
| png_gamma_equal(png_ptr, tr->st.background_gamma, correction, |
| &correction, 16U))) |
| correction = 0; /* no correction! */ |
| |
| if (tr->st.background_is_gray) |
| gamma_correct_background_component(png_ptr, &tr->st.background.gray, |
| bdback, correction, bdrow); |
| |
| else |
| { |
| gamma_correct_background_component(png_ptr, &tr->st.background.red, |
| bdback, correction, bdrow); |
| gamma_correct_background_component(png_ptr, &tr->st.background.green, |
| bdback, correction, bdrow); |
| gamma_correct_background_component(png_ptr, &tr->st.background.blue, |
| bdback, correction, bdrow); |
| } |
| |
| /* Regardless of whether there was a correction set the background gamma: */ |
| tr->st.background_gamma = tc->gamma; |
| tr->st.background_bit_depth = png_check_bits(png_ptr, bdrow, 5U); |
| # undef png_ptr |
| } |
| |
| static void |
| fill_background_pixel(png_transform_background *tr, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| /* Fill in 'background_pixel' if the appropriate sequence of bytes for the |
| * format given in the transform control. |
| */ |
| unsigned int bdtc = tc->bit_depth; |
| |
| /* If necessary adjust the background pixel to the current row format (it is |
| * important to do this as late as possible to avoid spurious |
| * interconvertions). |
| */ |
| gamma_correct_background(tr, tc); |
| |
| if (tr->st.background_is_gray) |
| { |
| unsigned int g = tr->st.background.gray; |
| |
| /* 'g' now has enough bits for the destination, note that in the case of |
| * low bit depth gray this causes the pixel to be replicated through the |
| * written byte. Fill all six bytes with the replicated background: |
| */ |
| while (bdtc < 8U) |
| { |
| g &= (1U << bdtc) - 1U; /* use only the low bits */ |
| g |= g << bdtc; |
| bdtc <<= 1; |
| } |
| |
| memset(tr->st.background_pixel, PNG_BYTE(g), 6U); |
| if (bdtc == 16U) |
| tr->st.background_pixel[0] = tr->st.background_pixel[2] = |
| tr->st.background_pixel[4] = PNG_BYTE(g >> 8); |
| /* Must not include the alpha channel here: */ |
| tr->st.ntrans = png_check_bits(png_ptr, |
| ((tc->format & PNG_FORMAT_FLAG_COLOR)+1U) << (bdtc == 16U), 3U); |
| } |
| |
| else |
| { |
| unsigned int r = tr->st.background.red; |
| unsigned int g = tr->st.background.green; |
| unsigned int b = tr->st.background.blue; |
| |
| debug((tc->format & PNG_FORMAT_FLAG_COLOR) != 0); |
| |
| switch (bdtc) |
| { |
| case 8U: |
| tr->st.background_pixel[0] = PNG_BYTE(r); |
| tr->st.background_pixel[1] = PNG_BYTE(g); |
| tr->st.background_pixel[2] = PNG_BYTE(b); |
| tr->st.ntrans = 3U; |
| break; |
| |
| case 16U: |
| tr->st.background_pixel[0] = PNG_BYTE(r>>8); |
| tr->st.background_pixel[1] = PNG_BYTE(r); |
| tr->st.background_pixel[2] = PNG_BYTE(g>>8); |
| tr->st.background_pixel[3] = PNG_BYTE(g); |
| tr->st.background_pixel[4] = PNG_BYTE(b>>8); |
| tr->st.background_pixel[5] = PNG_BYTE(b); |
| tr->st.ntrans = 6U; |
| break; |
| |
| default: |
| NOT_REACHED; |
| } |
| } |
| # undef png_ptr |
| } |
| |
| /* Look for colors matching the trans_color in png_ptr and replace them. This |
| * must handle all the non-alpha formats. |
| */ |
| static void |
| png_do_replace_tRNS_multi(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| const unsigned int cbytes = tr->st.ntrans; |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - cbytes/*safety*/; |
| const int copy = dp != sp; |
| |
| /* We expect opaque and transparent pixels to be interleaved but with long |
| * sequences of each. |
| */ |
| debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) && |
| PNG_TC_PIXEL_DEPTH(*tc) == cbytes << 3); |
| tc->invalid_info |= PNG_INFO_tRNS; |
| tc->sp = dp; |
| |
| /* Look for pixels that match the transparent value, copying opaque ones as |
| * required. |
| */ |
| do |
| { |
| const png_const_bytep opaque_start = sp; |
| size_t cb; |
| |
| /* Find a transparent pixel, or the end: */ |
| do |
| { |
| if (memcmp(sp, tr->st.transparent_pixel, cbytes) == 0) /*transparent*/ |
| break; |
| sp += cbytes; |
| } |
| while (sp <= ep); |
| |
| cb = sp - opaque_start; |
| |
| /* Copy any opaque pixels: */ |
| if (cb > 0) |
| { |
| if (copy) |
| memcpy(dp, opaque_start, cb); |
| dp += cb; |
| } |
| |
| /* Set transparent pixels to the background (this has to be done one-by |
| * one; the case where all the bytes in the background are equal is not |
| * optimized.) |
| */ |
| if (sp <= ep) do |
| { |
| memcpy(dp, tr->st.background_pixel, cbytes); |
| sp += cbytes; |
| dp += cbytes; |
| } |
| while (sp <= ep && memcmp(sp, tr->st.transparent_pixel, cbytes) == 0); |
| } while (sp <= ep); |
| |
| debug(sp == ep+cbytes); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_replace_tRNS_8(png_transformp *transform, png_transform_controlp tc) |
| /* The single byte version: 8-bit gray */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_alloc_size_t row_bytes = tc->width; |
| const int copy = dp != sp; |
| const int transparent_pixel = tr->st.transparent_pixel[0]; |
| const int background_pixel = tr->st.background_pixel[0]; |
| |
| /* We expect opaque and transparent pixels to be interleaved but with long |
| * sequences of each. |
| */ |
| debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) && |
| PNG_TC_PIXEL_DEPTH(*tc) == 8 && tr->st.ntrans == 1); |
| tc->invalid_info |= PNG_INFO_tRNS; |
| tc->sp = dp; |
| |
| /* Now search for a byte that matches the transparent pixel. */ |
| do |
| { |
| const png_const_bytep tp = png_voidcast(png_const_bytep, |
| memchr(sp, transparent_pixel, row_bytes)); |
| png_alloc_size_t cb; |
| |
| if (tp == NULL) /* all remaining pixels are opaque */ |
| { |
| if (copy) |
| memcpy(dp, sp, row_bytes); |
| return; |
| } |
| |
| cb = tp - sp; |
| if (cb > 0) /* some opaque pixels found */ |
| { |
| if (copy) |
| memcpy(dp, sp, cb); |
| sp = tp; |
| dp += cb; |
| debug(row_bytes > cb); |
| row_bytes -= cb; |
| } |
| |
| /* Now count the transparent pixels, this could use strspn but for the |
| * moment does not. |
| */ |
| debug(row_bytes > 0); |
| ++sp; /* next to check, may be beyond the last */ |
| while (--row_bytes > 0 && *sp == transparent_pixel) ++sp; |
| |
| cb = sp - tp; |
| memset(dp, background_pixel, cb); |
| dp += cb; |
| } while (row_bytes > 0); |
| UNTESTED |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_set_row(png_transformp *transform, png_transform_controlp tc) |
| /* This is a no-op transform that both invalidates INFO from args and sets |
| * the entire row to the byte given in the top bits. |
| */ |
| { |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| |
| tc->sp = dp; |
| memset(dp, (*transform)->args >> 24, PNG_TC_ROWBYTES(*tc)); |
| } |
| |
| static void |
| png_do_replace_tRNS_lbd(png_transformp *transform, png_transform_controlp tc) |
| { |
| /* This is the 2 or 4 bit depth grayscale case; the 1 bit case is handled by |
| * the two routines above and the 8-bit and 16-bit cases by the two before |
| * that. |
| * |
| * The transform contains pixel values that have been expanded to one byte, |
| * the code needs to match the tRNS pixel and substitute the background one |
| * in each byte. |
| */ |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| const unsigned int copy = sp != dp; |
| const png_byte transparent_pixel = tr->st.transparent_pixel[0]; |
| const png_byte background_pixel = tr->st.background_pixel[0]; |
| |
| /* We expect opaque and transparent pixels to be interleaved but with long |
| * sequences of each. |
| */ |
| debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) && |
| PNG_TC_PIXEL_DEPTH(*tc) < 8 && tr->st.ntrans == 1); |
| tc->sp = dp; |
| |
| /* Now search for a byte that contains the transparent pixel |
| * |
| * NOTE: this is the "strlen" algorithm, I first saw a variant implemented in |
| * Acorn RISC iX (strlen) around 1991, almost certainly derived from a |
| * suggestion by Alan Mycroft dating from April 27, 1987 (Mycroft was one of |
| * the authors of the 'Norcroft' compiler used for RISC iX, and well known to |
| * the RISC iX implementors.) See, e.g.: |
| * |
| * http://bits.stephan-brumme.com/null.html. |
| * |
| * The exact form used here is the one reported by Brumme; I haven't been |
| * able to find the original Mycroft posting, it was probably on comp.arch. |
| * |
| * The 4-bit and 2-bit versions (probably slower in the 4-bit case than the |
| * do-it-by-pixel version, but definately faster once 32-bit handling is |
| * implemented): |
| * |
| * 4 bit: (byte - 0x11) & ~byte & 0x88 |
| * 2 bit: (byte - 0x55) & ~byte & 0xcc |
| * |
| * The generalizations to 32 bits (8 and 16 pixels per step) should be |
| * obvious. |
| * |
| * This algorithm reads pixels within a byte beyond the end of the row and, |
| * potentially, changes the non-existent pixels. This is harmless and not |
| * a security risk. |
| */ |
| if (tc->bit_depth == 4U) |
| { |
| /* For the moment the algorithm isn't used; there are only two pixels in |
| * each byte so it is likely to be quicker to check as below: |
| */ |
| do |
| { |
| const png_byte b = *sp++; |
| const unsigned int m = b ^ transparent_pixel; |
| |
| if (m == 0U) /* both transparent */ |
| *dp = background_pixel; |
| |
| else if ((m & 0xF0U) == 0U) /* first transparent */ |
| *dp = PNG_BYTE((background_pixel & 0xF0U) | (b & 0x0FU)); |
| |
| else if ((m & 0x0FU) == 0U) /* second transparent */ |
| *dp = PNG_BYTE((background_pixel & 0x0FU) | (b & 0xF0U)); |
| |
| else if (copy) /* neither transparent */ |
| *dp = b; |
| |
| ++dp; |
| } while (sp < ep); |
| } |
| |
| else |
| { |
| affirm(tc->bit_depth == 2U); |
| |
| do |
| { |
| const png_byte b = *sp++; |
| const unsigned int m = b ^ transparent_pixel; |
| |
| if (m == 0U) /* transparent */ |
| *dp = background_pixel; |
| |
| else if (0xAAU & ((m - 0x55U) & ~m)) |
| { |
| /* One or more pixels transparent */ |
| const unsigned int mask = |
| (m & 0xC0U ? 0xC0U : 0U) | |
| (m & 0x30U ? 0x30U : 0U) | |
| (m & 0x0CU ? 0x0CU : 0U) | |
| (m & 0x03U ? 0x03U : 0U); |
| |
| *dp = PNG_BYTE((b & mask) | (background_pixel & ~mask)); |
| } |
| |
| else if (copy) /* no transparent pixels */ |
| *dp = b; |
| |
| ++dp; |
| } while (sp < ep); |
| } |
| |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_with_transparent_GA8(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/; |
| const png_byte background_pixel = tr->st.background_pixel[0]; |
| |
| /* Because this is an alpha format and we are removing the alpha channel we |
| * can copy up. |
| */ |
| debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_GA && |
| tr->st.ntrans == 1U); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->sp = dp; |
| |
| /* Look for pixels that have alpha 0; all others should have alpha 1.0, |
| * however they are simply treated as opaque regardless. |
| */ |
| do |
| { |
| *dp++ = (sp[1] == 0U) ? background_pixel : sp[0]; |
| sp += 2U; |
| } while (sp < ep); |
| |
| debug(sp == ep+1U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_with_transparent_GA16(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; |
| |
| debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA && |
| tr->st.ntrans == 2U); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->sp = dp; |
| |
| do |
| { |
| if (sp[2] == 0U && sp[3] == 0U) /* transparent */ |
| dp[0] = tr->st.background_pixel[0], dp[1] = tr->st.background_pixel[1]; |
| |
| else |
| dp[0] = sp[0], dp[1] = sp[1]; |
| |
| dp += 2U; |
| sp += 4U; |
| } while (sp < ep); |
| |
| debug(sp == ep+3U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_with_transparent_GAlbd(png_transformp *transform, |
| png_transform_controlp tc) |
| /* This is the low-bit-depth gray case, the input is 1, 2 or 4-bit per |
| * channel gray-alpha. |
| */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); |
| const unsigned int bit_depth = tc->bit_depth; |
| const unsigned int mask = (1U << bit_depth) - 1U; |
| const unsigned int back = tr->st.background_pixel[0] & mask; |
| unsigned int opos, ob, inb; |
| |
| debug(bit_depth < 8U && tc->format == PNG_FORMAT_GA && tr->st.ntrans == 1U); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->sp = dp; |
| |
| ob = 0U; /* output byte */ |
| opos = 0U; /* bit index of previous output pixel (counts down) */ |
| inb = 0U; /* quiet a GCC 4.8.5 warning */ |
| |
| for (;;) |
| { |
| /* The output is half the size of the input, so we need a new input byte |
| * for every 4 bits of output: |
| */ |
| if (opos == 0U || opos == 4U) |
| { |
| if (sp >= ep) |
| break; |
| |
| inb = *sp++; |
| } |
| |
| /* Move to the next *output* pixel, this wraps when bits is 0U: */ |
| opos = (opos - bit_depth) & 0x7U; |
| |
| /* Extract the whole input pixel to the low bits of a temporary: */ |
| { |
| unsigned int pixel = inb >> ((opos*2U) & 0x7U); |
| |
| /* The alpha channel is second, check for a value of 0: */ |
| if ((pixel & mask)/* A component*/ == 0U) |
| pixel = back; |
| |
| else |
| { |
| debug((pixel & mask) == mask); |
| pixel = (pixel >> bit_depth) & mask; /* G component */ |
| } |
| |
| ob |= pixel << opos; |
| } |
| |
| if (opos == 0U) |
| *dp++ = PNG_BYTE(ob), ob = 0U; |
| } |
| |
| if (opos != 0U) |
| *dp++ = PNG_BYTE(ob); |
| |
| debug(sp == ep); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_with_transparent_RGBA8(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; |
| |
| debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_RGBA && |
| tr->st.ntrans == 3U); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->sp = dp; |
| |
| do |
| { |
| if (sp[3] == 0U) /* transparent */ |
| memcpy(dp, tr->st.background_pixel, 3U); |
| |
| else |
| memmove(dp, sp, 3U); |
| |
| dp += 3U; |
| sp += 4U; |
| } while (sp < ep); |
| |
| debug(sp == ep+3U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_with_transparent_RGBA16(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/; |
| |
| debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA && |
| tr->st.ntrans == 6U); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->sp = dp; |
| |
| do |
| { |
| if (sp[6] == 0U && sp[7] == 0U) /* transparent */ |
| memcpy(dp, tr->st.background_pixel, 6U); |
| |
| else |
| memmove(dp, sp, 6U); |
| |
| dp += 6U; |
| sp += 8U; |
| } while (sp < ep); |
| |
| debug(sp == ep+7U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_background_transparent(png_transformp *transform, |
| png_transform_controlp tc) |
| /* Select the correct version of the above routines. */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| |
| debug(tc->init == PNG_TC_INIT_FINAL /* never called in 'FORMAT' */ && |
| (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0); |
| |
| /* Now we know the format on which processing will happen so it is possible |
| * to generate the correct fill pixel value to use. |
| */ |
| fill_background_pixel(tr, tc); |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| tc->invalid_info |= PNG_INFO_sBIT; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(png_ptr, tc->bit_depth); |
| |
| if (!(tc->format & PNG_FORMAT_FLAG_COLOR)) |
| { |
| if (tc->bit_depth == 8U) |
| tr->tr.fn = png_do_background_with_transparent_GA8; |
| |
| else if (tc->bit_depth == 16U) |
| tr->tr.fn = png_do_background_with_transparent_GA16; |
| |
| else /* low-bit-depth gray with alpha (not a PNG format!) */ |
| tr->tr.fn = png_do_background_with_transparent_GAlbd; |
| } |
| |
| else /* color */ |
| { |
| if (tc->bit_depth == 8U) |
| tr->tr.fn = png_do_background_with_transparent_RGBA8; |
| |
| else |
| { |
| debug(tc->bit_depth == 16U); |
| tr->tr.fn = png_do_background_with_transparent_RGBA16; |
| } |
| } |
| # undef png_ptr |
| } |
| |
| /* The calculated values below have the range 0..65535*65535, the output has the |
| * range 0..65535, so divide by 65535. Two approaches are given here, one |
| * modifies the value in place, the other uses a more complex expression. With |
| * gcc on an AMD64 system the in-place approach is very slightly faster. |
| * |
| * The two expressions are slightly different in what they calculate but both |
| * give the exact answer (verified by exhaustive testing.) |
| * |
| * The macro must be given a png_uint_32 variable (lvalue), normally an auto |
| * variable. |
| */ |
| #ifndef PNG_COMPOSE_DIV_65535 |
| # ifdef PNG_COMPOSE_DIV_EXPRESSION_SUPPORTED |
| # define PNG_COMPOSE_DIV_65535(v)\ |
| (v = ((v + (v>>16) + (v>>31) + 32768U) >> 16)) |
| # else |
| # define PNG_COMPOSE_DIV_65535(v)\ |
| (v += v >> 16, v += v >> 31, v += 32768U, v >>= 16) |
| # endif |
| #endif |
| |
| static void |
| png_do_background_alpha_GA(png_transformp *transform, png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; |
| const unsigned int background = tr->st.background.gray; |
| const int copy = (sp != dp); |
| const int compose = tr->st.compose_background; |
| |
| affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA && |
| tr->st.background_bit_depth == 16U); |
| |
| /* If gamma transforms are eliminated this might fail: */ |
| debug(tr->st.background_gamma == tc->gamma || |
| tr->st.background_gamma == 0 || |
| tc->sBIT_G == 1); |
| |
| tc->sp = tc->dp; /* nothing else changes */ |
| |
| do |
| { |
| const png_uint_32 alpha = (sp[2] << 8) + sp[3]; |
| |
| switch (alpha) |
| { |
| case 0U: /* transparent */ |
| memset(dp, 0U, 4U); |
| break; |
| |
| default: |
| { |
| png_uint_32 v = ((sp[0] << 8) + sp[1]) * alpha + |
| background * (65535U - alpha); |
| |
| PNG_COMPOSE_DIV_65535(v); |
| debug(v <= 65535U); |
| dp[0] = PNG_BYTE(v >> 8); |
| dp[1] = PNG_BYTE(v); |
| } |
| |
| if (compose) |
| dp[3] = dp[2] = 0xFFU; /* alpha; set to 1.0 */ |
| |
| else if (copy) |
| { |
| dp[2] = PNG_BYTE(alpha >> 8); |
| dp[3] = PNG_BYTE(alpha); |
| } |
| break; |
| |
| case 65535U: /* opaque */ |
| if (copy) |
| memcpy(dp, sp, 4U); |
| break; |
| } |
| |
| sp += 4U; |
| dp += 4U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+3U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_do_background_alpha_RGBA(png_transformp *transform, |
| png_transform_controlp tc) |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/; |
| const unsigned int bred = tr->st.background.red; |
| const unsigned int bgreen = tr->st.background.green; |
| const unsigned int bblue = tr->st.background.blue; |
| const int copy = (sp != dp); |
| const int compose = tr->st.compose_background; |
| |
| affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA && |
| tr->st.background_bit_depth == 16U); |
| |
| debug(tr->st.background_gamma == tc->gamma || |
| tr->st.background_gamma == 0 || |
| (tc->sBIT_R == 1 && tc->sBIT_G == 1 && tc->sBIT_B == 1)); |
| |
| tc->sp = tc->dp; /* nothing else changes */ |
| |
| do |
| { |
| const png_uint_32 alpha = (sp[6] << 8) + sp[7]; |
| |
| switch (alpha) |
| { |
| case 0U: /* transparent */ |
| memset(dp, 0U, 8U); |
| break; |
| |
| default: |
| { |
| const png_uint_32 balpha = (65535U - alpha); |
| png_uint_32 r = ((sp[0] << 8) + sp[1]) * alpha + bred * balpha; |
| png_uint_32 g = ((sp[2] << 8) + sp[3]) * alpha + bgreen * balpha; |
| png_uint_32 b = ((sp[4] << 8) + sp[5]) * alpha + bblue * balpha; |
| |
| PNG_COMPOSE_DIV_65535(r); |
| PNG_COMPOSE_DIV_65535(g); |
| PNG_COMPOSE_DIV_65535(b); |
| debug(r <= 65535U && g <= 65535U && b <= 65535U); |
| dp[0] = PNG_BYTE(r >> 8); |
| dp[1] = PNG_BYTE(r); |
| dp[2] = PNG_BYTE(g >> 8); |
| dp[3] = PNG_BYTE(g); |
| dp[4] = PNG_BYTE(b >> 8); |
| dp[5] = PNG_BYTE(b); |
| } |
| |
| if (compose) |
| dp[7] = dp[6] = 0xFFU; |
| |
| else if (copy) |
| { |
| dp[6] = PNG_BYTE(alpha >> 8); |
| dp[7] = PNG_BYTE(alpha); |
| } |
| break; |
| |
| case 65535U: /* opaque */ |
| if (copy) |
| memcpy(dp, sp, 8U); |
| break; |
| } |
| |
| sp += 8U; |
| dp += 8U; |
| } |
| while (sp < ep); |
| |
| debug(sp == ep+7U); |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_background_alpha_end(png_transformp *transform, |
| png_transform_controlp tc) |
| /* This is just the last part of png_init_background_alpha (below) */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| |
| debug(tc->init == PNG_TC_INIT_FINAL); |
| |
| /* Repeat the tests at the end of png_init_background_alpha: */ |
| affirm(tc->bit_depth == 16U && (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0); |
| debug(tc->gamma == 0 || |
| !png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc))); |
| |
| /* tr->st.background_is_gray was filled in by resolve_background_color and |
| * records if either the background was a gray value or it was a color |
| * value with all the channels equal. |
| */ |
| if (!tr->st.background_is_gray && !(tc->format & PNG_FORMAT_FLAG_COLOR)) |
| { |
| # ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED |
| /* Color background with gray data: this happens when there is a |
| * gray to RGB transform in the pipeline but it hasn't happened |
| * yet. Unfortunately it has to happen now to be able to do the |
| * compose against the colored background. |
| */ |
| png_push_gray_to_rgb_byte_ops(transform, tc); |
| affirm((tc->format & PNG_FORMAT_FLAG_COLOR) != 0); |
| return; |
| # else /* !GRAY_TO_RGB */ |
| impossible("gray to RGB"); /* how can this happen? */ |
| # endif /* !GRAY_TO_RGB */ |
| } |
| |
| /* The transform happens in two parts, a part to do the arithmetic on |
| * pixels where it is required followed by a part to replace transparent |
| * pixels. These two parts require different versions of the background |
| * pixel. Set up the second part first. |
| * |
| * This only happens with background composition, otherwise the |
| * transparent pixels are already 0 and nothing needs to be done. |
| */ |
| if (tr->st.compose_background) |
| { |
| /* The transparent pixel handling happens *after* the data has been |
| * re-encoded to the output gamma: |
| */ |
| png_transform_background *tr_alpha = |
| png_transform_cast(png_transform_background, |
| png_add_transform(png_ptr, sizeof (png_transform_background), |
| png_init_background_transparent, PNG_TR_GAMMA_ENCODE+0xF0U)); |
| |
| /* Copy the current state into the new png_transform_background: */ |
| tr_alpha->st = tr->st; |
| tr_alpha->tr.args = tr->tr.args; |
| } |
| |
| /* Now it is possible to overwrite tr->st.background with the linear version. |
| */ |
| gamma_correct_background(tr, tc); |
| |
| /* sBIT informationmust also be invalidated here, because a gamma |
| * transform may run before the transparent pixel handling. |
| */ |
| tc->invalid_info |= PNG_INFO_sBIT; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(png_ptr, tc->bit_depth); |
| |
| /* And select an appropriate function; there are only two choices: */ |
| switch (tc->format) |
| { |
| case PNG_FORMAT_GA: |
| /* If the background format is color this indicates that there is a |
| * gray to RGB transform missing and we need it to happen before |
| * this point! |
| */ |
| affirm(tr->st.background_is_gray); |
| tr->tr.fn = png_do_background_alpha_GA; |
| break; |
| |
| case PNG_FORMAT_RGBA: |
| if (tr->st.background_is_gray) |
| tr->st.background.blue = tr->st.background.green = |
| tr->st.background.red = tr->st.background.gray; |
| tr->tr.fn = png_do_background_alpha_RGBA; |
| break; |
| |
| default: |
| NOT_REACHED; |
| } |
| # undef png_ptr |
| } |
| |
| static void |
| png_init_background_alpha(png_transformp *transform, png_transform_controlp tc) |
| /* This is used when alpha composition is required because the alpha channel |
| * may contain values that are between 0 and 1. Because doing alpha |
| * composition requires linear arithmetic the data is converted to 16-bit |
| * linear, however this means that the background pixel gets converted too |
| * and, for 16-bit output, this tends to smash the value. Consequently the |
| * algorithm used here is to skip those pixels and use the 'transparent |
| * alpha' routines to replace them after the gamma correction step. |
| */ |
| { |
| # define png_ptr (tc->png_ptr) |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| |
| debug(tc->init == PNG_TC_INIT_FINAL); |
| /* png_init_background ensures this is true: */ |
| debug((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0); |
| |
| /* Always push gamma transforms; don't try to optimize the case when they |
| * aren't needed because that would be an attempt to duplicate the tests in |
| * png_init_gamma and it might now work reliably. |
| * |
| * Need to push the to-linear transform *before* this transform and add gamma |
| * correction afterward to get back to the screen format. Do the afterward |
| * bit first to avoid complexity over *transform: |
| */ |
| { |
| png_transform_gamma *tr_end = add_gamma_transform(png_ptr, |
| PNG_TR_GAMMA_ENCODE, tc->gamma, 0U/*bit depth*/, 0/*default*/); |
| |
| /* Encoding the alpha channel happens in the last step, so this needs to |
| * be set here. Notice that in C++ terms we are very friendly with |
| * png_transform_gamma. |
| */ |
| tr_end->encode_alpha = tr->st.encode_alpha; |
| tr_end->optimize_alpha = tr->st.optimize_alpha; |
| } |
| |
| { |
| /* Now add tr_gamma before this transform, expect it to go in at |
| * *transform or the whole thing won't work: |
| */ |
| png_transform_gamma *tr_gamma = png_transform_cast(png_transform_gamma, |
| png_push_transform(png_ptr, sizeof (png_transform_gamma), |
| png_init_gamma, transform, NULL/*don't run init*/)); |
| |
| /* This must happen before we run png_gamma_init: */ |
| tr_gamma->to_gamma = PNG_FP_1; |
| tr_gamma->to_bit_depth = 16U; |
| |
| /* Now run the this transform; it was pushed before this one, so it gets |
| * to do its init first and this function must return as the caller will |
| * immediately call here again. |
| */ |
| debug(*transform == &tr_gamma->tr); |
| png_init_gamma(transform, tc); |
| affirm(tc->bit_depth == 16U && |
| (tc->format & PNG_FORMAT_FLAG_ALPHA) != 0); |
| /* This is only a 'debug' because it needs to replicate the test in |
| * png_init_gamma and that is easy to get wrong (a harmless mistake). |
| */ |
| debug(tc->gamma == 0 || |
| !png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc))); |
| } |
| |
| /* A transform was pushed, so this transform init will be run again: */ |
| tr->tr.fn = png_init_background_alpha_end; |
| # undef png_ptr |
| } |
| |
| /* Handle alpha and tRNS via a background color */ |
| static void |
| png_init_background(png_transformp *transform, png_transform_controlp tc) |
| { |
| /* This init function is called right at the start, this means it can get at |
| * the tRNS values if appropriate. If not the RGB to gray transform comes |
| * next followed by PNG_TR_COMPOSE_ALPHA, which actually does the non-tRNS |
| * work. |
| */ |
| png_structp png_ptr = tc->png_ptr; |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, *transform); |
| |
| if (tc->init == PNG_TC_INIT_FORMAT) |
| { |
| /* Background composition removes the alpha channel, so the other |
| * operations become irrelevant: |
| */ |
| if (tr->st.compose_background) |
| tr->st.associate_alpha = tr->st.encode_alpha = tr->st.optimize_alpha = |
| 0U; |
| |
| else if (!tr->st.associate_alpha) |
| { |
| /* There is nothing to do, delete the whole transform. */ |
| tr->tr.fn = NULL; |
| return; |
| } |
| |
| /* Else alpha association ('pre-multiplication') which is achieved by |
| * composing on a 0 background. The background color will be black (all |
| * zeros) and the background gamma will be zero. |
| */ |
| |
| /* Because we are in PNG_TC_INIT_FORMAT no other transforms will have been |
| * inserted between this one and an rgb-to-gray transform, so we can find |
| * out if rgb-to-gray has been requested: |
| */ |
| tr->st.rgb_to_gray = tr->tr.next != NULL && |
| tr->tr.next->order == PNG_TR_RGB_TO_GRAY; |
| |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0) |
| { |
| /* Associated alpha does not strip the alpha channel! */ |
| if (tr->st.compose_background) |
| tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); |
| } |
| |
| else if (!tc->palette && |
| png_ptr->num_trans == 1 && !(tc->invalid_info & PNG_INFO_tRNS)) |
| { |
| /* tRNS will be expanded, or handled */ |
| tc->invalid_info |= PNG_INFO_tRNS; |
| if (!tr->st.compose_background) |
| { |
| tc->format |= PNG_FORMAT_FLAG_ALPHA; |
| /* And in this case, only, because we are adding an alpha channel we |
| * need to have a channel depth of at least 8: |
| */ |
| if (tc->bit_depth < 8U) |
| tc->bit_depth = 8U; |
| } |
| } |
| |
| else /* no transparent pixels to change */ |
| tr->tr.fn = NULL; |
| } |
| |
| else /* PNG_TC_INIT_FINAL */ |
| { |
| png_fixed_point correction; |
| |
| debug(tc->init == PNG_TC_INIT_FINAL && |
| ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 || |
| (!tc->palette && png_ptr->num_trans == 1 && |
| !(tc->invalid_info & PNG_INFO_tRNS)))); |
| |
| /* The screen gamma is known, so the background gamma can be found, note |
| * that both the gamma values used below will be 0 if no gamma information |
| * was in the PNG and no gamma information has been provided by |
| * png_set_gamma or png_set_alpha_mode. |
| */ |
| switch (tr->st.background_gamma) |
| { |
| case PNG_BACKGROUND_GAMMA_FILE: |
| /* png_init_transform_control has already found the file gamma, |
| * and because this is the first arithmetic transformation |
| * nothing has changed it. |
| */ |
| tr->st.background_gamma = tc->gamma; |
| break; |
| |
| case PNG_BACKGROUND_GAMMA_SCREEN: |
| tr->st.background_gamma = png_ptr->row_gamma; |
| break; |
| |
| default: |
| /* already set */ |
| break; |
| } |
| |
| /* Work out what the background color is, this only depends on 'tc' for |
| * palette information, so it can be done now before we know the actual |
| * bit_depth/format that will be required: |
| */ |
| resolve_background_color(tr, tc); |
| |
| /* Is this format compatible with the current row data? If it is then it |
| * is possible to avoid the arithmetic if no alpha processing is required. |
| * This is a useful optimization because PNG files with just transparent |
| * pixels and no alpha are common. |
| * |
| * NOTE: if an RGB-to-gray transform is present this is fine so long as |
| * the background is gray, otherwise (non-gray background) there is a |
| * following gray-to-RGB transform and the now gray image must be |
| * composited on a color background. |
| */ |
| if (tr->st.compose_background /* alpha channel stripped */ && |
| (tr->st.background_is_gray || |
| ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0 && !tr->st.rgb_to_gray)) |
| /* color compatible */ && |
| tc->bit_depth >= tr->st.background_bit_depth |
| /* bit depth compatible */ && |
| (tc->transparent_alpha || |
| (!tc->palette && png_ptr->num_trans == 1 && |
| !(tc->invalid_info & PNG_INFO_tRNS))) |
| /* no alpha processing */ && |
| png_gamma_equal(png_ptr, tc->gamma, png_ptr->row_gamma, &correction, |
| tc->bit_depth) /* gamma compatible (so no gamma processing) */) |
| { |
| /* How the operation gets performed depends on whether the current data |
| * has an alpha channel or not. |
| */ |
| if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0) |
| { |
| affirm(tc->transparent_alpha); |
| /* This init routine does the sBIT handling: */ |
| png_init_background_transparent(transform, tc); |
| } |
| |
| else if (!tc->palette && png_ptr->num_trans == 1 && |
| !(tc->invalid_info & PNG_INFO_tRNS)) |
| { |
| /* The background pixel needs to be filled in now; no more init |
| * routines are called in this case. It is important to delay this |
| * as late as possible because it needs to know the actual tc format |
| * that must be used. |
| */ |
| fill_background_pixel(tr, tc); |
| |
| debug(!(png_ptr->color_type & PNG_COLOR_MASK_PALETTE)); |
| |
| /* The pixel depth should not have been changed yet: */ |
| debug(PNG_PIXEL_DEPTH(*png_ptr) == PNG_TC_PIXEL_DEPTH(*tc)); |
| |
| /* The transparent_pixel value needs to be filled in. */ |
| affirm(tr->st.ntrans == |
| fill_transparent_pixel(png_ptr, tr->st.transparent_pixel)); |
| |
| /* The whole operation is a no-op if the transparent pixel and the |
| * background pixel match, even in the associated alpha case where |
| * both will be 0 throughout. |
| * |
| * NOTE: for palette images this test happens in the caching |
| * operation, so the answer is still correct. |
| * |
| * NOTE: for low bit depth gray both 'transparent_pixel' and |
| * 'background_pixel' have been expanded to fill a byte, so this |
| * works. |
| */ |
| if (memcmp(tr->st.transparent_pixel, tr->st.background_pixel, |
| tr->st.ntrans) == 0) |
| tr->tr.fn = NULL; |
| |
| /* Then the processing function depends on the pixel size: */ |
| else if (tr->st.ntrans > 1U) |
| tr->tr.fn = png_do_replace_tRNS_multi; |
| |
| else if (tc->bit_depth == 8U) |
| tr->tr.fn = png_do_replace_tRNS_8; |
| |
| else if (tc->bit_depth == 1U) |
| { |
| /* This is the silly case: the replacement pixel does not match |
| * the transparent pixel (handled above) so either all the '0' |
| * bits are replaced by '1' or all the '1' bits are replaced by |
| * '0': |
| */ |
| png_uint_32 args = tr->st.background_pixel[0]; |
| |
| args <<= 24; |
| args |= PNG_INFO_tRNS | PNG_INFO_sRGB; |
| tr->tr.args = args; |
| tr->tr.fn = png_do_set_row; |
| } |
| |
| else |
| tr->tr.fn = png_do_replace_tRNS_lbd; |
| |
| tc->invalid_info |= PNG_INFO_tRNS | PNG_INFO_sBIT; |
| tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = |
| png_check_byte(png_ptr, tc->bit_depth); |
| } |
| |
| else |
| { |
| /* Nothing to do; should have been eliminated before! */ |
| tr->tr.fn = NULL; |
| NOT_REACHED; |
| } |
| } |
| |
| else /* alpha, or maybe gamma, processing required */ |
| { |
| /* Alpha case, add an appropriate transform; this has to be done |
| * *after* the RGB-to-gray case so move the transform info there: |
| */ |
| png_transform_background *tr_alpha = |
| png_transform_cast(png_transform_background, |
| png_add_transform(png_ptr, sizeof (png_transform_background), |
| png_init_background_alpha, PNG_TR_COMPOSE_ALPHA)); |
| |
| /* Copy the current state into the new png_transform_background: */ |
| tr_alpha->st = tr->st; |
| tr_alpha->tr.args = tr->tr.args; |
| |
| /* The rest of the init occurs later; this transform is no longer |
| * needed. |
| */ |
| tr->tr.fn = NULL; |
| |
| /* Ensure that png_init_background_alpha gets an alpha channel, this |
| * needs to happen here because otherwise intervening transforms can |
| * invalidate tRNS. |
| */ |
| tc->expand_tRNS = 1U; |
| if (tr->st.compose_background) |
| tc->strip_alpha = 0U; |
| |
| /* And push the expand: */ |
| (void)push_gamma_expand(transform, tc, 1/*need alpha*/); |
| |
| /* Regardless of whether anything got pushed the following should now |
| * be true: |
| */ |
| affirm((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 && |
| tc->bit_depth >= 8U); |
| } |
| } |
| } |
| |
| void PNGFAPI |
| png_set_background_fixed(png_structrp png_ptr, |
| png_const_color_16p background_color, int background_gamma_code, |
| int need_expand, png_fixed_point background_gamma) |
| { |
| if (png_ptr != NULL) |
| { |
| if (background_color != NULL) |
| { |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, |
| png_add_transform(png_ptr, sizeof (png_transform_background), |
| png_init_background, PNG_TR_COMPOSE)); |
| |
| /* This silently overwrites the information if png_set_background is |
| * called more than once. |
| */ |
| tr->st.background = *background_color; |
| tr->st.need_expand = need_expand != 0; |
| tr->st.compose_background = 1U; /* png_set_background called */ |
| switch (background_gamma_code) |
| { |
| case PNG_BACKGROUND_GAMMA_SCREEN: |
| case PNG_BACKGROUND_GAMMA_FILE: |
| tr->st.background_gamma = background_gamma_code; |
| break; |
| |
| case PNG_BACKGROUND_GAMMA_UNIQUE: |
| if (background_gamma >= 16 && background_gamma <= 625000000) |
| { |
| tr->st.background_gamma = background_gamma; |
| break; |
| } |
| |
| png_app_error(png_ptr, "gamma value out of range"); |
| /* FALL THROUGH */ |
| default: |
| png_app_error(png_ptr, "invalid gamma information"); |
| tr->st.background_gamma = (need_expand ? |
| PNG_BACKGROUND_GAMMA_FILE : PNG_BACKGROUND_GAMMA_SCREEN); |
| break; |
| } |
| } |
| |
| else |
| png_app_error(png_ptr, "missing background color"); |
| } |
| } |
| |
| # ifdef PNG_FLOATING_POINT_SUPPORTED |
| void PNGAPI |
| png_set_background(png_structrp png_ptr, |
| png_const_color_16p background_color, int background_gamma_code, |
| int need_expand, double background_gamma) |
| { |
| png_set_background_fixed(png_ptr, background_color, background_gamma_code, |
| need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); |
| } |
| # endif /* FLOATING_POINT */ |
| #endif /* READ_BACKGROUND */ |
| |
| #ifdef PNG_READ_ALPHA_MODE_SUPPORTED |
| void PNGFAPI |
| png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, |
| png_fixed_point output_gamma) |
| { |
| if (png_ptr != NULL) |
| { |
| /* Check the passed in output_gamma value; it must be valid and it must be |
| * converted to the reciprocal for use below: |
| */ |
| output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); |
| |
| if (output_gamma > 0) /* Else an app_error has been signalled. */ |
| { |
| /* Only set the colorspace gamma if it has not already been set (this |
| * has the side effect that the gamma in a second call to |
| * png_set_alpha_mode will be ignored.) |
| */ |
| if ((png_ptr->colorspace.flags & |
| (PNG_COLORSPACE_INVALID | PNG_COLORSPACE_HAVE_GAMMA)) != |
| PNG_COLORSPACE_HAVE_GAMMA) |
| { |
| /* The default file gamma is the output gamma encoding: */ |
| png_ptr->colorspace.gamma = output_gamma; |
| if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) |
| png_ptr->colorspace.flags = PNG_COLORSPACE_HAVE_GAMMA; |
| else |
| png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; |
| } |
| |
| /* Always set the output gamma, note that it may be changed to PNG_FP_1 |
| * for the associated alpha support. This means that the last call to |
| * png_set_gamma[_fixed] or png_set_alpha_mode sets the output gamma, |
| * which is probably what is expected. |
| */ |
| { |
| png_transform_gamma *tr_gamma = add_gamma_transform(png_ptr, |
| PNG_TR_GAMMA_ENCODE, |
| mode == PNG_ALPHA_ASSOCIATED ? PNG_FP_1 : output_gamma, 0U, |
| 1/*force*/); |
| |
| /* Get a background transform and set the appropriate fields. |
| * |
| * png_set_background removes the alpha channel so it effectively |
| * disbles png_set_alpha_mode however png_set_alpha_mode is still |
| * useful to set a default gamma value. |
| */ |
| png_transform_background *tr = |
| png_transform_cast(png_transform_background, |
| png_add_transform(png_ptr, sizeof (png_transform_background), |
| png_init_background, PNG_TR_COMPOSE)); |
| |
| /* There are really 8 possibilities here, composed of any |
| * combination of: |
| * |
| * premultiply the color channels |
| * do not encode non-opaque pixels (leave as linear) |
| * encode the alpha as well as the color channels |
| * |
| * The differences disappear if the input/output ('screen') gamma is |
| * 1.0, because then the encoding is a no-op and there is only the |
| * choice of premultiplying the color channels or not. |
| */ |
| switch (mode) |
| { |
| case PNG_ALPHA_PNG: /* default: png standard */ |
| /* No compose, but it may be set by png_set_background! This |
| * is the only mode that doesn't interfere with what |
| * png_set_background does. |
| */ |
| tr->st.associate_alpha = 0U; |
| tr_gamma->encode_alpha = tr->st.encode_alpha = 0U; |
| tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U; |
| break; |
| |
| case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ |
| tr->st.associate_alpha = 1U; |
| tr_gamma->encode_alpha = tr->st.encode_alpha = 0U; |
| tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U; |
| break; |
| |
| case PNG_ALPHA_OPTIMIZED: |
| /* associated with opaque pixels having the given gamma and |
| * non-opaque pixels being linear. |
| */ |
| tr->st.associate_alpha = 1U; |
| tr_gamma->encode_alpha = tr->st.encode_alpha = 0U; |
| tr_gamma->optimize_alpha = tr->st.optimize_alpha = 1U; |
| /* output_gamma records the encoding of opaque pixels! */ |
| break; |
| |
| case PNG_ALPHA_BROKEN: |
| /* associated+non-linear+alpha encoded */ |
| tr->st.associate_alpha = 1U; |
| tr_gamma->encode_alpha = tr->st.encode_alpha = 1U; |
| tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U; |
| break; |
| |
| default: |
| png_app_error(png_ptr, "invalid alpha mode"); |
| /* A return at this point is safe; if a background transform |
| * was created the init routine will remove it because |
| * nothing is set. |
| */ |
| break; |
| } /* alpha mode switch */ |
| } /* add gamma and background transforms */ |
| } /* valid output gamma */ |
| } /* png_ptr != NULL */ |
| } |
| |
| #ifdef PNG_FLOATING_POINT_SUPPORTED |
| void PNGAPI |
| png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) |
| { |
| png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, |
| output_gamma)); |
| } |
| #endif /* FLOATING_POINT */ |
| #endif /* READ_ALPHA_MODE */ |
| |
| #ifdef PNG_READ_TRANSFORMS_SUPPORTED |
| typedef struct |
| { |
| png_transform tr; |
| png_transform_control tc; |
| union |
| { |
| png_uint_32 u32[1]; /* ensure alignment */ |
| png_uint_16 u16[1]; |
| png_byte b8[1]; |
| } cache; |
| } png_transform_cache; |
| |
| #define png_transform_cache_size(size)\ |
| (offsetof(png_transform_cache, cache)+(size)) |
| #define png_transform_cache_cast(pointer,size)\ |
| png_voidcast(png_transform_cache*,\ |
| png_transform_cast_check(png_ptr, PNG_SRC_LINE, (pointer),\ |
| png_transform_cache_size(size))) |
| /* This is like png_transform_cast except that 'size' is the size of the |
| * cache part in the above structure and the type returned is always |
| * 'png_transform_cache*'. |
| */ |
| |
| /* Functions to handle the cache operation. These don't do any initialization; |
| * that happens below when PNG_TC_INIT_FINAL is being run on the whole list. |
| * These functions are only implemented for read so the transform control |
| * source and destination are always aligned. |
| * |
| * First some utility functions: |
| */ |
| static void |
| png_transform_control_cp(png_transform_controlp tcDest, |
| png_const_transform_controlp tcSrc) |
| { |
| /* Copy tcSrc over tcDest without overwriting the information specific to the |
| * row being transformed. |
| */ |
| png_structp png_ptr = tcDest->png_ptr; |
| png_const_voidp sp = tcDest->sp; |
| png_voidp dp = tcDest->dp; |
| png_uint_32 width = tcDest->width; |
| unsigned int init = tcDest->init; |
| |
| *tcDest = *tcSrc; |
| |
| tcDest->png_ptr = png_ptr; |
| tcDest->sp = sp; |
| tcDest->dp = dp; |
| tcDest->width = width; |
| tcDest->init = png_check_bits(tcDest->png_ptr, init, 2); |
| } |
| |
| #if !PNG_RELEASE_BUILD |
| static int |
| png_transform_control_eq(png_const_transform_controlp tc1, |
| png_const_transform_controlp tc2) |
| { |
| /* Say if *tc1 == *tc2, ignoring differences in uncopied fields and 'cost': |
| */ |
| return |
| # ifdef PNG_READ_GAMMA_SUPPORTED |
| tc1->gamma == tc2->gamma && |
| # endif |
| tc1->format == tc2->format && |
| tc1->range == tc2->range && |
| tc1->bit_depth == tc2->bit_depth && |
| tc1->caching == tc2->caching && |
| tc1->palette == tc2->palette; |
| /* invalid_info, cost, interchannel and channel_add are only set during |
| * init, so don't do the compare. |
| */ |
| } |
| #endif /* !RELEASE_BUILD */ |
| |
| /* Now the routines that actually perform the transform. There are two basic |
| * cases: |
| * |
| * 1) A cached transform that does not change the pixel size and where the pixel |
| * size 8 bits or less. This can be done by a 256-entry single byte lookup |
| * table, regardless of the bit depth. Two versions of the code exist, one |
| * which just transforms the row, the other which transforms and records the |
| * maximum pixel depth. |
| * |
| * 2) A cached transform that increases pixel depth. The destination pixel |
| * depth will always be a multiple of 8 bits, the source pixel will be less |
| * than or equal to 8 bits and will be in the PNG native (big endian) layout. |
| */ |
| #define png_ptr (tc->png_ptr) /* Used in all functions below */ |
| /* (1): single-byte cached transforms: */ |
| static void |
| do_transform_cache_byte(png_transformp *trIn, png_transform_controlp tc) |
| { |
| png_transform_cache *tr = png_transform_cache_cast(*trIn, 256U); |
| |
| /* Copy the bytes through the 256-byte LUT: */ |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp + PNG_TC_ROWBYTES(*tc); |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| |
| tc->sp = dp; |
| |
| do |
| *dp++ = tr->cache.b8[*sp++]; |
| while (dp < ep); |
| |
| png_transform_control_cp(tc, &tr->tc); |
| } |
| |
| /* (2) A cached transform that increases pixel depth. |
| * |
| * There are six output depth possibilites, all a whole number of bytes: |
| * |
| * 1 byte, 8 bits: palette or grayscale |
| * 2 bytes, 16 bits: 16-bit grayscale or 8-bit gray+alpa |
| * 3 bytes, 24 bits: 8-bit RGB |
| * 4 bytes, 32 bits: 16-bit gray+alpha or 8-bit RGBA |
| * 6 bytes, 48 bits: 16-bit RGB |
| * 8 bytes, 64 bits: 16-bit RGBA |
| * |
| * The input must be 1, 2, 4 or 8-bit gray or palette. The first 1-byte case is |
| * handled for 8-bit gray/palette above, so there are 22 possibilities. The |
| * function names below are: |
| * |
| * do_transform_cache_<input-bits>_<output-bits> |
| */ |
| #define transform_cache_size(ipd,opd) ((((1U << (ipd)) * (opd))+7U) >> 3) |
| static void |
| do_transform_cache_(png_transformp *trIn, png_transform_controlp tc, |
| unsigned int ipd, unsigned int opd) |
| /* This is the implementation for unknown ipd, opd, below it is called with |
| * fixed values. The purpose of this is to allow the compiler/system builder |
| * to decide how to optimize for size vs space vs speed. Note that this |
| * implementation, while it would work for 8 bit ipd, is not used in that |
| * case. |
| */ |
| { |
| png_transform_cache *tr = |
| png_transform_cache_cast(*trIn, transform_cache_size(ipd, opd)); |
| |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp; |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| unsigned int s, shift, mask; |
| |
| sp += PNG_TC_ROWBYTES(*tc); /* One byte beyond the end */ |
| |
| png_transform_control_cp(tc, &tr->tc); |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| shift = 7U & -(tc->width * ipd); |
| /* MSB: shift right required to get last pixel */ |
| mask = (1U << ipd) - 1U; |
| /* Mask to extract a single pixel from the low bits of a byte */ |
| opd >>= 3; |
| /* Output pixel size in bytes */ |
| s = *--sp; |
| /* The first byte; the last byte of the input row */ |
| |
| for (;;) |
| { |
| png_const_bytep opixel = (((s >> shift) & mask)+1U) * opd + tr->cache.b8; |
| /* Points to the byte after last byte of the output value */ |
| unsigned int i; |
| |
| for (i=0; i<opd; ++i) |
| *--dp = *--opixel; |
| |
| if (dp <= ep) |
| break; |
| |
| shift += ipd; /* To find shift for *previous* pixel */ |
| |
| if (shift == 8U) |
| s = *--sp, shift = 0U/*right-most pixel*/; |
| } |
| |
| debug(dp == ep && shift == 8U-ipd && sp == tc->sp); |
| tc->sp = ep; /* start of row, safe even if the above fails */ |
| } |
| |
| #define do_transform_cache(ipd,opd)\ |
| static void \ |
| do_transform_cache_##ipd##_##opd(png_transformp *tr, png_transform_controlp tc)\ |
| {\ |
| do_transform_cache_(tr, tc, ipd, opd);\ |
| } |
| |
| #define TCLOW(opd)\ |
| do_transform_cache(1,opd)\ |
| do_transform_cache(2,opd)\ |
| do_transform_cache(4,opd) |
| |
| TCLOW(8) |
| TCLOW(16) |
| TCLOW(24) |
| TCLOW(32) |
| TCLOW(48) |
| TCLOW(64) |
| |
| #undef TCLOW |
| #undef do_transform_cache |
| |
| static void |
| do_transform_cache_8_(png_transformp *trIn, png_transform_controlp tc, |
| unsigned int opd) |
| /* This is the 8-bit input implementation. */ |
| { |
| png_transform_cache *tr = |
| png_transform_cache_cast(*trIn, transform_cache_size(8, opd)); |
| |
| png_bytep dp = png_voidcast(png_bytep, tc->dp); |
| png_const_bytep ep = dp; |
| png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); |
| |
| sp += PNG_TC_ROWBYTES(*tc); /* One byte beyond the end */ |
| |
| png_transform_control_cp(tc, &tr->tc); |
| dp += PNG_TC_ROWBYTES(*tc); |
| |
| opd >>= 3; /* Output pixel size in bytes */ |
| do |
| { |
| png_const_bytep opixel = (*--sp + 1U) * opd + tr->cache.b8; |
| /* Points to the byte after last byte of the output value */ |
| unsigned int i; |
| |
| for (i=0; i<opd; ++i) |
| *--dp = *--opixel; |
| } |
| while (dp > ep); |
| |
| debug(dp == ep && sp == tc->sp); |
| tc->sp = ep; /* start of row, safe even if the above fails */ |
| } |
| |
| #define do_transform_cache(opd)\ |
| static void \ |
| do_transform_cache_8_##opd(png_transformp *tr, png_transform_controlp tc)\ |
| {\ |
| do_transform_cache_8_(tr, tc, opd);\ |
| } |
| |
| /* The 8-bit to 8-bit case uses the byte transform code */ |
| do_transform_cache(16) |
| do_transform_cache(24) |
| do_transform_cache(32) |
| do_transform_cache(48) |
| do_transform_cache(64) |
| |
| #undef do_transform_cache |
| |
| #define do_transform_cache(ipd,opd) do_transform_cache_##ipd##_##opd |
| |
| #undef png_ptr |
| |
| typedef struct |
| { |
| png_transformp *start; |
| /* This is a pointer to the pointer to the start of the list being cached, |
| * i.e. *start is the first transform in the list. |
| */ |
| png_transform_control tstart; |
| /* This is the transform control at the start; i.e. before (*start)->fn is |
| * called. Note that for palette data it will contain the original |
| * palette format/bit-depth, not that passed to (*start)->fn which will |
| * represent the palette. |
| */ |
| png_transformp *end; |
| png_transform_control tend; |
| /* The same data from the end of the run to be cached, i.e. after the |
| * function of the transform which *contains* '*end' (end points to |
| * tr->next). |
| */ |
| } png_cache_params, *png_cache_paramsp; |
| |
| static void |
| init_caching(png_structp png_ptr, png_cache_paramsp cp) |
| /* Given an already initialized cp->tend turn on caching if appropriate. */ |
| { |
| /* Handle the colormap case, where a cache is always required: */ |
| if (cp->tend.format & PNG_FORMAT_FLAG_COLORMAP) |
| { |
| /* This turns starts the palette caching with the next transform: */ |
| cp->tend.palette = cp->tend.caching = 1U; |
| cp->tend.transparent_alpha = png_ptr->transparent_palette; |
| cp->tend.format = PNG_FORMAT_FLAG_COLOR; |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (png_ptr->num_trans > 0 && !(cp->tend.invalid_info & PNG_INFO_tRNS)) |
| { |
| cp->tend.format |= PNG_FORMAT_FLAG_ALPHA; |
| } |
| # endif /* READ_tRNS */ |
| cp->tend.bit_depth = 8U; |
| } |
| |
| else if (PNG_TC_PIXEL_DEPTH(cp->tend) <= 8) |
| { |
| /* Cacheable pixel transforms; the pixel is less than 8 bits in size so |
| * the cache makes sense. |
| * |
| * TODO: check the cost estimate and the image size to avoid expensive |
| * caches of very small images. |
| */ |
| cp->tend.caching = 1U; |
| } |
| |
| /* TODO: handle handle 8-bit GA/RGB/RGBA */ |
| } |
| |
| static void |
| add_cache_transform(png_structp png_ptr, unsigned int order, |
| png_transform_fn fn, png_cache_paramsp cp, |
| png_const_bytep cache, unsigned int size) |
| /* Add a transform from the input format cp->tstart to the output format |
| * stored in cp->tend. |
| */ |
| { |
| affirm(size <= 2048U); /* 256 8-byte pixels at most */ |
| { |
| png_transform_cache *tr = png_transform_cache_cast( |
| png_add_transform(png_ptr, png_transform_cache_size(size), fn, order), |
| size); |
| |
| /* This must have replaced the transform in *cp->start: */ |
| affirm(&tr->tr == *cp->start); |
| |
| /* Fill in the respective members: */ |
| tr->tc = cp->tend; |
| memcpy(tr->cache.b8, cache, size); |
| |
| /* Skip this transform, because the calling routine has already executed |
| * the cache (it could be executed again, just to verify that it works; |
| * cp->tstart should be correct.) |
| */ |
| cp->start = &tr->tr.next; |
| } |
| } |
| |
| static unsigned int |
| setup_palette_cache(png_structp png_ptr, png_byte cache[8*256]) |
| /* This returns the number of entries in the cache; the width */ |
| { |
| const unsigned int num_palette = png_ptr->num_palette; |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| unsigned int num_trans = png_ptr->num_trans; |
| # endif /* READ_tRNS */ |
| const png_colorp palette = png_ptr->palette; |
| png_bytep p; |
| unsigned int i; |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| const png_bytep trans_alpha = png_ptr->trans_alpha; |
| # endif /* READ_tRNS */ |
| |
| for (i=0, p=cache; i<num_palette; ++i) |
| { |
| *p++ = palette[i].red; |
| *p++ = palette[i].green; |
| *p++ = palette[i].blue; |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (num_trans > 0) |
| { |
| if (i < num_trans) |
| *p++ = trans_alpha[i]; |
| |
| else |
| *p++ = 0xFFU; |
| } |
| # endif /* READ_tRNS */ |
| } |
| |
| return num_palette; |
| } |
| |
| static void |
| png_remove_PLTE_and_tRNS(png_structrp png_ptr) |
| { |
| if (png_ptr->palette != NULL) |
| png_free(png_ptr, png_ptr->palette); |
| |
| png_ptr->palette = NULL; |
| png_ptr->num_palette = 0; |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (png_ptr->trans_alpha != NULL) |
| png_free(png_ptr, png_ptr->trans_alpha); |
| |
| png_ptr->trans_alpha = NULL; |
| png_ptr->num_trans = 0; |
| # endif /* READ_tRNS */ |
| } |
| |
| static void |
| update_palette(png_structp png_ptr, png_cache_paramsp cp, |
| unsigned int max_depth) |
| { |
| union |
| { |
| png_uint_32 u32[1]; |
| png_uint_16 u16[1]; /* For alignment */ |
| png_byte b8[8*256]; /* For 16-bit RGBA intermediate */ |
| } cache; |
| |
| /* The caller only calls this function if the initial transform control had |
| * the palette flag set, implying that the original 'format' was a COLORMAP |
| * one. Also this can only happen (at present) when starting the transform |
| * list, so: |
| */ |
| affirm((cp->tstart.format & PNG_FORMAT_FLAG_COLORMAP) != 0); /* required */ |
| debug(cp->start == &png_ptr->transform_list); /* should be harmless */ |
| |
| /* Run the whole of the given list on the palette data. PNG_TC_INIT_FINAL |
| * has already been run; this is a full run (with init == 0). |
| */ |
| { |
| unsigned int check_depth; |
| only_deb(png_transform_control orig = cp->tend;) |
| |
| cp->tend = cp->tstart; |
| init_caching(png_ptr, cp); |
| /* And set up tend to actually work out the palette: */ |
| cp->tend.init = 0U; |
| cp->tend.width = setup_palette_cache(png_ptr, cache.b8); |
| cp->tend.sp = cache.b8; |
| cp->tend.dp = cache.b8; |
| |
| check_depth = |
| png_run_this_transform_list_forwards(&cp->tend, cp->start, *cp->end); |
| |
| /* If we get here these two things must be true or there are been some |
| * buggy difference of opinion between the INIT code and the actual run: |
| */ |
| affirm(check_depth == max_depth && cp->tend.palette); |
| |
| /* This should match the passed in final format obtained before, this |
| * debug statement detects discrepancies between the init code and the |
| * run code: |
| */ |
| debug(png_transform_control_eq(&cp->tend, &orig)); |
| |
| /* Also, expect the palette to still be valid: */ |
| debug((cp->tend.invalid_info & PNG_INFO_PLTE) == 0); |
| } |
| |
| /* The result must be compatible with a PNG palette with respect to bit |
| * depth; specifically the expand-16 transform has no effect on palette data. |
| * |
| * The colormap setting must not have been re-introduced here either; there |
| * may be some quantize interactions here, neither can unexpected flags be |
| * handled; just COLOR and ALPHA. |
| */ |
| affirm(cp->tend.bit_depth == 8 && |
| (cp->tend.format & PNG_FORMAT_FLAG_COLORMAP) == 0); |
| |
| /* Remove all the transforms between start(inclusive) and end(exclusive); |
| * they have been processed. The effect they had on the transform control |
| * is irrelevant because the caller re-instates the settings from tstart. |
| */ |
| { |
| png_transformp list = *cp->start; /* list to free */ |
| |
| *cp->start = *cp->end; /* part of list not to be freed */ |
| *cp->end = NULL; /* terminate the list to be freed */ |
| cp->end = cp->start; /* else cp->end points to the end of the list! */ |
| |
| png_transform_free(png_ptr, &list); |
| } |
| |
| /* Adjust the PNG palette and, if required, the tRNS entries. Note that |
| * if the transforms stripped the alpha channel from the palette num_trans |
| * will get set to 0 here. |
| * |
| * This is the point where the gamma gets frozen too. The alternative |
| * design is to pass palette, tRNS and gamma up the transform chain, but |
| * that doesn't work because the palette change would, apparently, have to |
| * be repeated on each row. This seems simpler at the cost of a little |
| * obscurity; the answer to the question, "Where does the palette get |
| * updated?", is "Here!" |
| * |
| * API CHANGE: (fix): previously the init code would silently overwrite |
| * the palette information shared with png_info, breaking the API for |
| * png_read_update_info, which doesn't update the info if it isn't called, |
| * by changing the palette and maybe tRNS when the first row was read! |
| * |
| * NOTE: PNG_FORMAT_FLAG_RANGE is lost at this point, even if the palette |
| * entries were shifted or inverted. This could be fixed, but it would |
| * complicate the libpng API to expose the information. |
| */ |
| /* Write the transformed palette: */ |
| { |
| png_colorp palette = png_voidcast(png_colorp, png_calloc(png_ptr, |
| sizeof (png_color[PNG_MAX_PALETTE_LENGTH]))); |
| png_const_bytep p; |
| const int is_color = (cp->tend.format & PNG_FORMAT_FLAG_COLOR) != 0; |
| unsigned int i; |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| unsigned int num_trans = 0; |
| const int do_trans = (cp->tend.format & PNG_FORMAT_FLAG_ALPHA) != 0; |
| png_byte trans_alpha[PNG_MAX_PALETTE_LENGTH]; |
| # endif /* READ_tRNS */ |
| |
| memset(palette, 0xFFU, sizeof (png_color[PNG_MAX_PALETTE_LENGTH])); |
| png_free(png_ptr, png_ptr->palette); |
| png_ptr->palette = palette; |
| |
| for (i=0, p=cache.b8; i<cp->tend.width; ++i) |
| { |
| if (is_color) |
| { |
| palette[i].red = *p++; |
| palette[i].green = *p++; |
| palette[i].blue = *p++; |
| } |
| |
| else |
| palette[i].blue = palette[i].green = palette[i].red = *p++; |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (do_trans) |
| { |
| png_byte a = *p++; |
| trans_alpha[i] = a; |
| |
| /* Strip opaque entries from the end: */ |
| if (a < 0xFFU) |
| num_trans = i+1; |
| } |
| # endif /* READ_tRNS */ |
| } |
| |
| png_ptr->num_palette = png_check_bits(png_ptr, cp->tend.width, 9); |
| |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| if (num_trans > 0) |
| { |
| png_bytep tRNS = png_voidcast(png_bytep, png_malloc(png_ptr, |
| PNG_MAX_PALETTE_LENGTH)); |
| |
| memset(tRNS, 0xFFU, PNG_MAX_PALETTE_LENGTH); |
| |
| if (png_ptr->trans_alpha != NULL) |
| png_free(png_ptr, png_ptr->trans_alpha); |
| |
| png_ptr->trans_alpha = tRNS; |
| |
| memcpy(tRNS, trans_alpha, num_trans); |
| png_ptr->num_trans = png_check_bits(png_ptr, num_trans, 9); |
| } |
| # endif /* READ_tRNS */ |
| } |
| |
| /* NOTE: the caller sets cp->start to cp->end and cp->tend to cp->tstart, |
| * this causes processing to continue with the palette format and the |
| * first unprocessed transform. The reset of the transform control loses the |
| * gamma information as well, of course, as any information about the palette |
| * and tRNS changes (such as the RANGE flags). |
| */ |
| } |
| |
| /* These structure and the save/restore routines that follow it exist to save |
| * data from a png_transform_control that is specific to the sample encoding of |
| * the PNG data, rather than the row format itself. |
| */ |
| typedef struct |
| { |
| # ifdef PNG_READ_GAMMA_SUPPORTED |
| png_fixed_point gamma; |
| # endif |
| png_byte sBIT_R; |
| png_byte sBIT_G; |
| png_byte sBIT_B; |
| png_byte sBIT_A; /* Signnificant bits in the row channels. */ |
| unsigned int invalid_info; /* PNG_INFO_* for invalidated chunks */ |
| } png_tc_channel_data; |
| |
| static void |
| save_cp_channel_data(png_tc_channel_data *save, png_const_transform_controlp tc) |
| { |
| # ifdef PNG_READ_GAMMA_SUPPORTED |
| save->gamma = tc->gamma; |
| # endif /* READ_GAMMA */ |
| |
| /* The sBIT information and the list of invalidated chunks must also be |
| * preserved: |
| */ |
| save->sBIT_R = tc->sBIT_R; |
| save->sBIT_G = tc->sBIT_G; |
| save->sBIT_B = tc->sBIT_B; |
| save->sBIT_A = tc->sBIT_A; |
| save->invalid_info = tc->invalid_info; |
| } |
| |
| static void |
| restore_cp_channel_data(png_transform_controlp tc, |
| const png_tc_channel_data *save) |
| /* Reverse the above */ |
| { |
| # ifdef PNG_READ_GAMMA_SUPPORTED |
| tc->gamma = save->gamma; |
| # endif /* READ_GAMMA */ |
| |
| tc->sBIT_R = save->sBIT_R; |
| tc->sBIT_G = save->sBIT_G; |
| tc->sBIT_B = save->sBIT_B; |
| tc->sBIT_A = save->sBIT_A; |
| tc->invalid_info = save->invalid_info; |
| } |
| |
| static void |
| make_cache(png_structp png_ptr, png_cache_paramsp cp, unsigned int max_depth) |
| { |
| /* At present the cache is just a byte lookup table. We need the original |
| * pixel depth to work out how big the working buffer needs to be. |
| */ |
| const unsigned int ipd = PNG_TC_PIXEL_DEPTH(cp->tstart); |
| const unsigned int opd = PNG_TC_PIXEL_DEPTH(cp->tend); |
| unsigned int order; /* records position of start transform */ |
| unsigned int width; /* width of cache in pixels */ |
| png_tc_channel_data save; /* Record of the final channel info */ |
| union |
| { |
| png_uint_32 u32[1]; |
| png_uint_16 u16[1]; /* For alignment */ |
| png_byte b8[8*256]; /* For 16-bit RGBA */ |
| } cache; |
| |
| debug(cp->tend.init == PNG_TC_INIT_FINAL); |
| affirm(opd <= 64 && max_depth <= 64); /* or the cache is not big enough */ |
| affirm(ipd == opd || (opd & 0x7U) == 0); |
| |
| if ((cp->tstart.format & PNG_FORMAT_FLAG_COLORMAP) != 0) |
| width = setup_palette_cache(png_ptr, cache.b8); |
| |
| else switch (ipd) |
| { |
| /* The input to the cache is the full range of possible pixel values: */ |
| case 1: |
| /* 2 1-bit pixels, MSB first */ |
| cache.b8[0] = 0x40U; |
| width = 2; |
| break; |
| |
| case 2: |
| /* 4 2-bit pixels, MSB first */ |
| cache.b8[0] = 0x1BU; |
| width = 4; |
| break; |
| |
| case 4: |
| /* 16 4-bit pixels, MSB first */ |
| cache.b8[0] = 0x01U; |
| cache.b8[1] = 0x23U; |
| cache.b8[2] = 0x45U; |
| cache.b8[3] = 0x67U; |
| cache.b8[4] = 0x89U; |
| cache.b8[5] = 0xABU; |
| cache.b8[6] = 0xCDU; |
| cache.b8[7] = 0xEFU; |
| width = 16; |
| break; |
| |
| case 8: |
| /* 256 8-bit pixels */ |
| { |
| unsigned int i; |
| |
| for (i=0; i<256; ++i) |
| cache.b8[i] = PNG_BYTE(i); |
| } |
| width = 256; |
| break; |
| |
| default: |
| impossible("cache input bit depth"); |
| } |
| |
| /* Reset the transform control to run the transforms on this data, but save |
| * the channel info because the row processing functions do not always |
| * write it. |
| */ |
| save_cp_channel_data(&save, &cp->tend); |
| cp->tend = cp->tstart; |
| init_caching(png_ptr, cp); |
| /* And set tend to work out the result of transforming each possible pixel |
| * value: |
| */ |
| cp->tend.init = 0U; |
| cp->tend.width = width; |
| cp->tend.sp = cache.b8; |
| cp->tend.dp = cache.b8; |
| |
| { |
| unsigned int check_depth = |
| png_run_this_transform_list_forwards(&cp->tend, cp->start, *cp->end); |
| |
| /* This must not change: */ |
| affirm(PNG_TC_PIXEL_DEPTH(cp->tend) == opd && check_depth == max_depth); |
| } |
| |
| /* Restore the potentially lost channel data. */ |
| restore_cp_channel_data(&cp->tend, &save); |
| |
| /* This is all the information required to cache the set of transforms |
| * between 'start' and 'end'. We take the transformed pixels and make a |
| * cache transform of them. The cache transform skips the work, transforms |
| * the row, and sets the tranform_control to (a copy of) cp->tend. |
| * |
| * Remove all the transforms between start(inclusive) and end(exclusive); |
| * they have been processed. The effect they had on the transform control |
| * is irrelevant because the caller re-instates the settings from tstart. |
| */ |
| { |
| png_transformp list = *cp->start; /* list to free */ |
| |
| *cp->start = *cp->end; /* part of list not to be freed */ |
| *cp->end = NULL; /* terminate the list to be freed */ |
| cp->end = NULL; /* reset below */ |
| |
| order = list->order; /* used below when adding the cache transform */ |
| png_transform_free(png_ptr, &list); |
| } |
| |
| /* Make the required cache, as enumerated above there are 22 possibilities, |
| * this selects between them, fixes up the cache for the 'byte' cases (where |
| * multiple pixels can be handled byte-by-byte) and selects the correct |
| * transform function. |
| */ |
| if (ipd == opd) |
| { |
| /* We already know that ipd is <= 8 bits, so we can expand this case to |
| * the byte transform. The complexity is that for ipd < 8 bits we only |
| * have information for individual pixel values and these may be |
| * pixel-swapped within the byte. |
| */ |
| if (ipd < 8) |
| { |
| const int lsb = (cp->tend.format & PNG_FORMAT_FLAG_SWAPPED) != 0; |
| unsigned int ishift, b; |
| png_byte bcache[256]; |
| |
| switch (ipd) |
| { |
| case 1: ishift = 3U; break; |
| case 2: ishift = 2U; break; |
| case 4: ishift = 1U; break; |
| default: impossible("ipd"); |
| } |
| |
| /* Work out the right answer for each byte of pixels: */ |
| for (b=0U; b<256U; ++b) |
| { |
| unsigned int o = 0U; /* output byte */ |
| unsigned int p = 8U; /* right shift to find input pixel */ |
| |
| do |
| { |
| unsigned int q = ((1U<<ipd)-1U) & (b >> (p-=ipd)); |
| /* The input pixel. For a palette this value might be outside |
| * the range of palette indices, in which case simply insert |
| * '0': |
| */ |
| if (q < width) |
| { |
| unsigned int r = cache.b8[q >> ishift]; |
| r >>= ((lsb ? q : ~q) & ((1U<<ishift)-1U)) << (3U-ishift); |
| r &= ((1U<<ipd)-1U); |
| o |= r << (lsb ? (8U-ipd)-p : p); |
| } |
| |
| else |
| { |
| UNTESTED |
| } |
| } |
| while (p != 0U); |
| |
| bcache[b] = png_check_byte(png_ptr, o); |
| } |
| |
| /* This is a byte transform, with the optional check-for-invalid-index |
| * functionality. |
| */ |
| add_cache_transform(png_ptr, order, do_transform_cache_byte, cp, |
| bcache, 256U); |
| } |
| |
| else /* ipd == 8 */ |
| add_cache_transform(png_ptr, order, do_transform_cache_byte, cp, |
| cache.b8, 256U); |
| } |
| |
| else |
| { |
| /* opd is a whole number of bytes, ipd is 1, 2, 4 or 8 and not equal to |
| * opd. |
| */ |
| png_transform_fn fn; |
| |
| # define C(ipd,opd) ((ipd) + 8*(opd)) |
| switch (C(ipd,opd)) |
| { |
| # define CASE(ipd,opd)\ |
| case C(ipd,opd): fn = do_transform_cache(ipd,opd); break |
| |
| CASE(1,8); |
| CASE(2,8); |
| CASE(4,8); |
| /* No 8,8 */ |
| |
| # define CASES(opd)\ |
| CASE(1,opd);\ |
| CASE(2,opd);\ |
| CASE(4,opd);\ |
| CASE(8,opd) |
| |
| CASES(16); |
| CASES(24); |
| CASES(32); |
| CASES(48); |
| CASES(64); |
| # undef CASES |
| # undef CASE |
| |
| default: |
| impossible("cache bit depths"); |
| } |
| # undef C |
| |
| /* In the event that the cache is not the full width implied by ipd zero |
| * the remaining bytes for security; otherwise they get copied into the |
| * cache transform and might get used. (Specifically if there is an |
| * out-of-range palette index they do get used!) |
| */ |
| { |
| unsigned int size = transform_cache_size(ipd, opd); |
| png_alloc_size_t cachebytes = PNG_TC_ROWBYTES(cp->tend); |
| |
| affirm(cachebytes <= sizeof cache.b8); |
| |
| if (cachebytes < size) |
| memset(cache.b8+cachebytes, 0, size - cachebytes); |
| |
| add_cache_transform(png_ptr, order, fn, cp, cache.b8, size); |
| } |
| } |
| |
| /* Because a transform was inserted cp->end needs to be set to the new |
| * pointer to the original end. add_cache_transform sets cp->start to this, |
| * so: |
| */ |
| cp->end = cp->start; |
| |
| /* This invalidates the palette if that is what was cached because the |
| * palette and, if present, tRNS chunk did not get updated above. |
| */ |
| if (cp->tstart.palette) |
| png_remove_PLTE_and_tRNS(png_ptr); |
| } |
| |
| static void restore_cp(png_cache_paramsp cp) |
| { |
| /* A utility to restore cp->tstart by copying it into cp->tend. This is used |
| * both in the palette case when restoring the transform control for the |
| * indexed data and in the case where no transforms were cached. It |
| * preserves the color-channel-specific data from cp->tend because in either |
| * case it is possible for this data to be modified without preserving any |
| * transforms, e.g. if only the gamma is changed but no gamma transform is |
| * retained because the change was not significant. |
| */ |
| png_tc_channel_data save; |
| |
| save_cp_channel_data(&save, &cp->tend); |
| cp->tend = cp->tstart; |
| restore_cp_channel_data(&cp->tend, &save); |
| } |
| |
| static void |
| handle_cache(png_structp png_ptr, png_cache_paramsp cp, unsigned int max_depth) |
| { |
| /* There is nothing to do if there are no transforms between 'start' and |
| * 'end': |
| */ |
| if (cp->start != cp->end) |
| { |
| only_deb(png_transformp tr_check = *cp->end;) |
| |
| /* libpng doesn't currently implement any pixel size of more than 64 bits |
| * so: |
| */ |
| affirm(max_depth <= 64); |
| |
| if (cp->tend.palette) |
| { |
| /* The transforms being cached apply to the palette, the following |
| * transforms will apply to the original index data and the transformed |
| * data must be used to update the palette: |
| */ |
| if (cp->tend.init == PNG_TC_INIT_FINAL) |
| update_palette(png_ptr, cp, max_depth); |
| |
| cp->start = cp->end; |
| restore_cp(cp); /* reset to palette data */ |
| } |
| |
| else |
| { |
| /* Continue with the transform control in cp.tend; even if there was |
| * palette data in cp.tstart it has been expanded. |
| */ |
| if (cp->tend.init == PNG_TC_INIT_FINAL) |
| make_cache(png_ptr, cp, max_depth); |
| |
| cp->tstart = cp->tend; /* keep current context */ |
| } |
| |
| debug(tr_check == *cp->end); |
| } |
| |
| else /* no transforms cached */ |
| restore_cp(cp); /* removes any palette caching info */ |
| } |
| |
| #ifdef PNG_READ_tRNS_SUPPORTED |
| static void |
| check_tRNS_for_alpha(png_structrp png_ptr) |
| { |
| unsigned int num_trans = png_ptr->num_trans; |
| |
| debug(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE); |
| |
| while (num_trans > 0) |
| { |
| { |
| const png_byte trans = png_ptr->trans_alpha[--num_trans]; |
| |
| if (trans == 0xFFU) |
| continue; |
| |
| if (trans > 0U) |
| return; /* Palette has at least one entry >0, <0xff */ |
| } |
| |
| /* There is some point to the tRNS chunk; it has a non-opaque entry, this |
| * code could truncate it but there is no obvious performance advantage to |
| * doing this. |
| */ |
| while (num_trans > 0) |
| { |
| const png_byte trans = png_ptr->trans_alpha[--num_trans]; |
| |
| if (trans > 0U && trans < 0xFFU) |
| return; |
| } |
| |
| /* Here if the above did not find an entry >0 && <0xFFU but did find a |
| * transparent entry (0u). Record this. |
| */ |
| png_ptr->transparent_palette = 1U; |
| return; |
| } |
| |
| /* All entries opaque; remove the tRNS data: */ |
| png_ptr->num_trans = 0U; |
| } |
| #endif /* READ_tRNS */ |
| |
| unsigned int /* PRIVATE */ |
| png_read_init_transform_mech(png_structp png_ptr, png_transform_controlp tc) |
| /* This is called once for each init stage (PNG_TC_INIT_FORMAT and |
| * PNG_TC_INIT_FINAL) to run the transform list forwards, returning the |
| * maximum depth required to process the row. It handles caching of the |
| * transforms and the processing of the palette for color-mapped PNG data. |
| */ |
| { |
| png_transformp *list = &png_ptr->transform_list; |
| unsigned int max_depth; |
| png_cache_params cp; |
| |
| /* PNG color-mapped data must be handled here so that the palette is updated |
| * correctly. png_set_palette_to_rgb causes the palette flag to be removed |
| * from the transform control but does no other change. png_set_quantize |
| * causes 8-bit RGB, RGBA or palette data to be converted into palette |
| * indices, setting the palette flag. |
| */ |
| # ifdef PNG_READ_tRNS_SUPPORTED |
| /* This happens once at the start to find out if the tRNS chunk consisted |
| * entirely of opaque (255) and/or transparent (0) entries. |
| */ |
| if (tc->init == PNG_TC_INIT_FORMAT && |
| png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) |
| check_tRNS_for_alpha(png_ptr); |
| # endif /* READ_tRNS */ |
| cp.end = cp.start = list; |
| cp.tend = cp.tstart = *tc; |
| init_caching(png_ptr, &cp); |
| max_depth = PNG_TC_PIXEL_DEPTH(cp.tend); |
| |
| while (*cp.end != NULL) |
| { |
| png_transformp tr = *cp.end; |
| |
| /* The user transform cannot be cached. */ |
| if (tr->order >= PNG_TR_USER) |
| break; |
| |
| /* If the 'palette' flag is set and the next transform has order |
| * PNG_TR_ENCODING or later cache the results so far and continue with the |
| * original palette data (cp.tstart). |
| */ |
| if (cp.tend.palette && tr->order >= PNG_TR_ENCODING) |
| { |
| handle_cache(png_ptr, &cp, max_depth); |
| |
| /* The cache handling function must maintain cp.end; */ |
| affirm(tr == *cp.end); |
| max_depth = PNG_TC_PIXEL_DEPTH(cp.tend); |
| } |
| |
| /* Now run the transform list entry: */ |
| if (tr->fn != NULL) |
| { |
| tr->fn(cp.end, &cp.tend); |
| tr = *cp.end; /* in case something was inserted */ |
| } |
| |
| if (tr->fn == NULL) /* delete this transform */ |
| png_remove_transform(png_ptr, cp.end); |
| |
| else |
| { |
| /* Handle the initialization of the maximum pixel depth. */ |
| unsigned int tc_depth = PNG_TC_PIXEL_DEPTH(cp.tend); |
| |
| if (tc_depth > max_depth) |
| max_depth = tc_depth; |
| |
| /* Advance to the next transform. */ |
| cp.end = &tr->next; |
| } |
| } |
| |
| /* At the end if still caching record the cache information (this is common; |
| * this is generally the case for an expanded palette.) |
| */ |
| if (cp.tend.caching) |
| { |
| png_transformp tr = *cp.end; |
| handle_cache(png_ptr, &cp, max_depth); |
| affirm(tr == *cp.end); |
| max_depth = PNG_TC_PIXEL_DEPTH(cp.tend); |
| } |
| |
| /* At the end run the init on the user transform: */ |
| if (*cp.end != NULL) |
| { |
| png_transformp tr = *cp.end; |
| affirm(tr->order == PNG_TR_USER); |
| if (tr->fn != NULL) |
| tr->fn(cp.end, &cp.tend); |
| /* This cannot insert anything, so: */ |
| affirm(tr == *cp.end && tr->next == NULL); |
| |
| if (tr->fn == NULL) /* delete this transform */ |
| png_remove_transform(png_ptr, cp.end); |
| |
| else |
| { |
| unsigned int tc_depth = PNG_TC_PIXEL_DEPTH(cp.tend); |
| |
| if (tc_depth > max_depth) |
| max_depth = tc_depth; |
| } |
| } |
| |
| /* And write the input transform control: */ |
| *tc = cp.tend; |
| |
| return max_depth; |
| } |
| |
| /* Modify the info structure to reflect the transformations. The |
| * info should be updated so a PNG file could be written with it, |
| * assuming the transformations result in valid PNG data. |
| */ |
| void /* PRIVATE */ |
| png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) |
| { |
| png_debug(1, "in png_read_transform_info"); |
| |
| /* WARNING: this is very basic at present. It just updates the format |
| * information. It should update the palette (and will eventually) as well |
| * as invalidating chunks that the transforms break. |
| */ |
| # ifdef PNG_TRANSFORM_MECH_SUPPORTED |
| info_ptr->format = png_ptr->row_format; |
| info_ptr->bit_depth = png_ptr->row_bit_depth; |
| # ifdef PNG_READ_GAMMA_SUPPORTED |
| /* If an info struct is used with a different png_ptr in a call to |
| * png_set_gAMA then the png_struct information won't be updated, this |
| * doesn't matter on write, but don't zap the value in the info on read |
| * unless it is known: |
| * |
| * TODO: review this whole mess. |
| */ |
| if (png_ptr->row_gamma > 0) |
| info_ptr->colorspace.gamma = png_ptr->row_gamma; |
| # endif |
| |
| /* Invalidate chunks marked as invalid: */ |
| # ifdef PNG_READ_TRANSFORMS_SUPPORTED |
| info_ptr->valid &= ~png_ptr->invalid_info; |
| |
| /* If the palette or tRNS chunk was changed copy them over to the info |
| * structure; this may actually re-validate the PLTE or tRNS chunks, |
| * but only if png_ptr has a new version, otherwise the invalid_info |
| * settings from above can still invalidate the chunk. |
| */ |
| if (png_ptr->palette != info_ptr->palette) |
| { |
| png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); |
| info_ptr->palette = png_ptr->palette; |
| info_ptr->num_palette = png_ptr->num_palette; |
| if (info_ptr->palette != NULL && info_ptr->num_palette > 0) |
| info_ptr->valid |= PNG_INFO_PLTE; |
| |
| # ifdef PNG_READ_tRNS |
| /* ONLY do this if the palette was changed above because, in |
| * fact, the tRNS data is not shared (yes, this is inconsistent, |
| * perhaps fix it?) |
| */ |
| if ((info_ptr->format & PNG_FORMAT_FLAG_COLORMAP) != 0 && |
| png_ptr->trans_alpha != info_ptr->trans_alpha) |
| { |
| png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); |
| /* NOTE: it is shared now! */ |
| info_ptr->trans_alpha = png_ptr->trans_alpha; |
| info_ptr->num_trans = png_ptr->num_trans; |
| if (info_ptr->trans_alpha != NULL && info_ptr->num_trans > 0) |
| info_ptr->valid |= PNG_INFO_tRNS; |
| } |
| # endif /* READ_tRNS */ |
| } |
| # endif /* READ_TRANSFORMS */ |
| # else /* !TRANSFORM_MECH */ |
| PNG_UNUSED(png_ptr) |
| PNG_UNUSED(info_ptr) |
| # endif /* !TRANSFORM_MECH */ |
| } |
| #endif /* READ_TRANSFORMS */ |