📄 pngrtran.c
字号:
/* pngrtran.c - transforms the data in a row for PNG readers * * libpng 1.0.2 - June 14, 1998 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger * Copyright (c) 1998, Glenn Randers-Pehrson * * 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. */#define PNG_INTERNAL#include "png.h"#if defined(PNG_READ_BACKGROUND_SUPPORTED)/* handle alpha and tRNS via a background color */voidpng_set_background(png_structp png_ptr, png_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma){ png_debug(1, "in png_set_background\n"); if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) { png_warning(png_ptr, "Application must supply a known background gamma"); return; } png_ptr->transformations |= PNG_BACKGROUND; png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16)); png_ptr->background_gamma = (float)background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA * (in which case need_expand is superfluous anyway), the background color * might actually be gray yet not be flagged as such. This is not a problem * for the current code, which uses PNG_FLAG_BACKGROUND_IS_GRAY only to * decide when to do the png_do_gray_to_rgb() transformation. */ if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) || (!need_expand && background_color->red == background_color->green && background_color->red == background_color->blue)) png_ptr->flags |= PNG_FLAG_BACKGROUND_IS_GRAY;}#endif#if defined(PNG_READ_16_TO_8_SUPPORTED)/* strip 16 bit depth files to 8 bit depth */voidpng_set_strip_16(png_structp png_ptr){ png_debug(1, "in png_set_strip_16\n"); png_ptr->transformations |= PNG_16_TO_8;}#endif#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)voidpng_set_strip_alpha(png_structp png_ptr){ png_debug(1, "in png_set_strip_alpha\n"); png_ptr->transformations |= PNG_STRIP_ALPHA;}#endif#if defined(PNG_READ_DITHER_SUPPORTED)/* 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_dither" indicates * whether we need a dithering 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 FAR * next; png_byte left; png_byte right;} png_dsort;typedef png_dsort FAR * png_dsortp;typedef png_dsort FAR * FAR * png_dsortpp;voidpng_set_dither(png_structp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_uint_16p histogram, int full_dither){ png_debug(1, "in png_set_dither\n"); png_ptr->transformations |= PNG_DITHER; if (!full_dither) { int i; png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette * sizeof (png_byte))); for (i = 0; i < num_palette; i++) png_ptr->dither_index[i] = (png_byte)i; } if (num_palette > maximum_colors) { 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_bytep sort; /* initialize an array to sort colors */ sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette * sizeof (png_byte))); /* initialize the sort array */ for (i = 0; i < num_palette; i++) sort[i] = (png_byte)i; /* 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[sort[j]] < histogram[sort[j + 1]]) { png_byte t; t = sort[j]; sort[j] = sort[j + 1]; sort[j + 1] = t; done = 0; } } if (done) break; } /* swap the palette around, and set up a table, if necessary */ if (full_dither) { int j = num_palette; /* put all the useful colors within the max, but don't move the others */ for (i = 0; i < maximum_colors; i++) { if ((int)sort[i] >= maximum_colors) { do j--; while ((int)sort[j] >= maximum_colors); palette[i] = palette[j]; } } } else { 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 ((int)sort[i] >= maximum_colors) { png_color tmp_color; do j--; while ((int)sort[j] >= maximum_colors); tmp_color = palette[j]; palette[j] = palette[i]; palette[i] = tmp_color; /* indicate where the color went */ png_ptr->dither_index[j] = (png_byte)i; png_ptr->dither_index[i] = (png_byte)j; } } /* find closest color for those colors we are not using */ for (i = 0; i < num_palette; i++) { if ((int)png_ptr->dither_index[i] >= maximum_colors) { int min_d, k, min_k, d_index; /* find the closest color to one we threw out */ d_index = png_ptr->dither_index[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 */ png_ptr->dither_index[i] = (png_byte)min_k; } } } png_free(png_ptr, sort); } else { /* 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). [I don't understand this at all, so if someone wants to work on improving it, be my guest - AED] */ int i; int max_d; int num_new_palette; png_dsortpp hash; png_bytep index_to_palette; /* where the original index currently is in the palette */ png_bytep palette_to_index; /* which original index points to this palette color */ /* initialize palette index arrays */ index_to_palette = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette * sizeof (png_byte))); palette_to_index = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette * sizeof (png_byte))); /* initialize the sort array */ for (i = 0; i < num_palette; i++) { index_to_palette[i] = (png_byte)i; palette_to_index[i] = (png_byte)i; } hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * sizeof (png_dsortp))); for (i = 0; i < 769; i++) hash[i] = NULL;/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */ 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) { for (i = 0; i < num_new_palette - 1; i++) { int j; for (j = i + 1; j < num_new_palette; j++) { int d; d = PNG_COLOR_DIST(palette[i], palette[j]); if (d <= max_d) { png_dsortp t; t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof (png_dsort))); t->next = hash[d]; t->left = (png_byte)i; t->right = (png_byte)j; hash[d] = t; } } } for (i = 0; i <= max_d; i++) { if (hash[i] != NULL) { png_dsortp p; for (p = hash[i]; p; p = p->next) { if ((int)index_to_palette[p->left] < num_new_palette && (int)index_to_palette[p->right] < num_new_palette) { int j, next_j; if (num_new_palette & 1) { j = p->left; next_j = p->right; } else { j = p->right; next_j = p->left; } num_new_palette--; palette[index_to_palette[j]] = palette[num_new_palette]; if (!full_dither) { int k; for (k = 0; k < num_palette; k++) { if (png_ptr->dither_index[k] == index_to_palette[j]) png_ptr->dither_index[k] = index_to_palette[next_j]; if ((int)png_ptr->dither_index[k] == num_new_palette) png_ptr->dither_index[k] = index_to_palette[j]; } } 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_byte)num_new_palette; palette_to_index[num_new_palette] = (png_byte)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) { png_dsortp t; t = p->next; png_free(png_ptr, p); p = t; } } hash[i] = 0; } max_d += 96; } png_free(png_ptr, hash); png_free(png_ptr, palette_to_index); png_free(png_ptr, index_to_palette); } num_palette = maximum_colors; } if (png_ptr->palette == NULL) { png_ptr->palette = palette; } png_ptr->num_palette = (png_uint_16)num_palette; if (full_dither) { int i; png_bytep distance; int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS; int num_red = (1 << PNG_DITHER_RED_BITS); int num_green = (1 << PNG_DITHER_GREEN_BITS); int num_blue = (1 << PNG_DITHER_BLUE_BITS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -