📄 gd_png.c
字号:
} break; default: /* Palette image, or something coerced to be one */ for (h = 0; h < height; ++h) { for (w = 0; w < width; ++w) { register png_byte idx = row_pointers[h][w]; im->pixels[h][w] = idx; open[idx] = 0; } } }#ifdef DEBUG if (!im->trueColor) { for (i = num_palette; i < gdMaxColors; ++i) { if (!open[i]) { php_gd_error("gd-png warning: image data references out-of-range color index (%d)\n", i); } } }#endif if (palette_allocated) { gdFree(palette); } gdFree(image_data); gdFree(row_pointers); return im;}void gdImagePngEx (gdImagePtr im, FILE * outFile, int level){ gdIOCtx *out = gdNewFileCtx(outFile); gdImagePngCtxEx(im, out, level); out->gd_free(out);}void gdImagePng (gdImagePtr im, FILE * outFile){ gdIOCtx *out = gdNewFileCtx(outFile); gdImagePngCtxEx(im, out, -1); out->gd_free(out);}void * gdImagePngPtr (gdImagePtr im, int *size){ void *rv; gdIOCtx *out = gdNewDynamicCtx(2048, NULL); gdImagePngCtxEx(im, out, -1); rv = gdDPExtractData(out, size); out->gd_free(out); return rv;}void * gdImagePngPtrEx (gdImagePtr im, int *size, int level){ void *rv; gdIOCtx *out = gdNewDynamicCtx(2048, NULL); gdImagePngCtxEx(im, out, level); rv = gdDPExtractData(out, size); out->gd_free(out); return rv;}void gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile){ gdImagePngCtxEx(im, outfile, -1);}/* This routine is based in part on code from Dale Lutz (Safe Software Inc.) * and in part on demo code from Chapter 15 of "PNG: The Definitive Guide" * (http://www.cdrom.com/pub/png/pngbook.html). */void gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level){ int i, j, bit_depth = 0, interlace_type; int width = im->sx; int height = im->sy; int colors = im->colorsTotal; int *open = im->open; int mapping[gdMaxColors]; /* mapping[gd_index] == png_index */ png_byte trans_values[256]; png_color_16 trans_rgb_value; png_color palette[gdMaxColors]; png_structp png_ptr; png_infop info_ptr; volatile int transparent = im->transparent; volatile int remap = FALSE;#ifndef PNG_SETJMP_NOT_SUPPORTED png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct, gdPngErrorHandler, NULL);#else png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);#endif if (png_ptr == NULL) { php_gd_error("gd-png error: cannot allocate libpng main struct\n"); return; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { php_gd_error("gd-png error: cannot allocate libpng info struct\n"); png_destroy_write_struct (&png_ptr, (png_infopp) NULL); return; }#ifndef PNG_SETJMP_NOT_SUPPORTED if (setjmp (gdPngJmpbufStruct.jmpbuf)) { php_gd_error("gd-png error: setjmp returns error condition\n"); png_destroy_write_struct (&png_ptr, &info_ptr); return; }#endif png_set_write_fn(png_ptr, (void *) outfile, gdPngWriteData, gdPngFlushData); /* This is best for palette images, and libpng defaults to it for * palette images anyway, so we don't need to do it explicitly. * What to ideally do for truecolor images depends, alas, on the image. * gd is intentionally imperfect and doesn't spend a lot of time * fussing with such things. */ /* png_set_filter(png_ptr, 0, PNG_FILTER_NONE); */ /* 2.0.12: this is finally a parameter */ png_set_compression_level(png_ptr, level); /* can set this to a smaller value without compromising compression if all * image data is 16K or less; will save some decoder memory [min == 8] */ /* png_set_compression_window_bits(png_ptr, 15); */ if (!im->trueColor) { if (transparent >= im->colorsTotal || (transparent >= 0 && open[transparent])) { transparent = -1; } for (i = 0; i < gdMaxColors; ++i) { mapping[i] = -1; } /* count actual number of colors used (colorsTotal == high-water mark) */ colors = 0; for (i = 0; i < im->colorsTotal; ++i) { if (!open[i]) { mapping[i] = colors; ++colors; } } if (colors < im->colorsTotal) { remap = TRUE; } if (colors <= 2) { bit_depth = 1; } else if (colors <= 4) { bit_depth = 2; } else if (colors <= 16) { bit_depth = 4; } else { bit_depth = 8; } } interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; if (im->trueColor) { if (im->saveAlphaFlag) { png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } else { png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } } else { png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } if (im->trueColor && !im->saveAlphaFlag && (transparent >= 0)) { /* 2.0.9: fixed by Thomas Winzig */ trans_rgb_value.red = gdTrueColorGetRed (im->transparent); trans_rgb_value.green = gdTrueColorGetGreen (im->transparent); trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent); png_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value); } if (!im->trueColor) { /* Oy veh. Remap the PNG palette to put the entries with interesting alpha channel * values first. This minimizes the size of the tRNS chunk and thus the size * of the PNG file as a whole. */ int tc = 0; int i; int j; int k; for (i = 0; (i < im->colorsTotal); i++) { if ((!im->open[i]) && (im->alpha[i] != gdAlphaOpaque)) { tc++; } } if (tc) {#if 0 for (i = 0; (i < im->colorsTotal); i++) { trans_values[i] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6)); } png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);#endif if (!remap) { remap = TRUE; } /* (Semi-)transparent indexes come up from the bottom of the list of real colors; opaque * indexes come down from the top */ j = 0; k = colors - 1; for (i = 0; i < im->colorsTotal; i++) { if (!im->open[i]) { if (im->alpha[i] != gdAlphaOpaque) { /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ trans_values[j] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6)); mapping[i] = j++; } else { mapping[i] = k--; } } } png_set_tRNS(png_ptr, info_ptr, trans_values, tc, NULL); } } /* convert palette to libpng layout */ if (!im->trueColor) { if (remap) { for (i = 0; i < im->colorsTotal; ++i) { if (mapping[i] < 0) { continue; } palette[mapping[i]].red = im->red[i]; palette[mapping[i]].green = im->green[i]; palette[mapping[i]].blue = im->blue[i]; } } else { for (i = 0; i < colors; ++i) { palette[i].red = im->red[i]; palette[i].green = im->green[i]; palette[i].blue = im->blue[i]; } } png_set_PLTE(png_ptr, info_ptr, palette, colors); } /* write out the PNG header info (everything up to first IDAT) */ png_write_info(png_ptr, info_ptr); /* make sure < 8-bit images are packed into pixels as tightly as possible */ png_set_packing(png_ptr); /* This code allocates a set of row buffers and copies the gd image data * into them only in the case that remapping is necessary; in gd 1.3 and * later, the im->pixels array is laid out identically to libpng's row * pointers and can be passed to png_write_image() function directly. * The remapping case could be accomplished with less memory for non- * interlaced images, but interlacing causes some serious complications. */ if (im->trueColor) { /* performance optimizations by Phong Tran */ int channels = im->saveAlphaFlag ? 4 : 3; /* Our little 7-bit alpha channel trick costs us a bit here. */ png_bytep *row_pointers; unsigned char* pOutputRow; int **ptpixels = im->tpixels; int *pThisRow; unsigned char a; int thisPixel; png_bytep *prow_pointers; int saveAlphaFlag = im->saveAlphaFlag; row_pointers = safe_emalloc(sizeof(png_bytep), height, 0); prow_pointers = row_pointers; for (j = 0; j < height; ++j) { *prow_pointers = (png_bytep) safe_emalloc(width, channels, 0); pOutputRow = *prow_pointers++; pThisRow = *ptpixels++; for (i = 0; i < width; ++i) { thisPixel = *pThisRow++; *pOutputRow++ = gdTrueColorGetRed(thisPixel); *pOutputRow++ = gdTrueColorGetGreen(thisPixel); *pOutputRow++ = gdTrueColorGetBlue(thisPixel); if (saveAlphaFlag) { /* convert the 7-bit alpha channel to an 8-bit alpha channel. * We do a little bit-flipping magic, repeating the MSB * as the LSB, to ensure that 0 maps to 0 and * 127 maps to 255. We also have to invert to match * PNG's convention in which 255 is opaque. */ a = gdTrueColorGetAlpha(thisPixel); /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ *pOutputRow++ = 255 - ((a << 1) + (a >> 6)); } } } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); for (j = 0; j < height; ++j) { gdFree(row_pointers[j]); } gdFree(row_pointers); } else { if (remap) { png_bytep *row_pointers; row_pointers = safe_emalloc(sizeof(png_bytep), height, 0); for (j = 0; j < height; ++j) { row_pointers[j] = (png_bytep) gdMalloc(width); for (i = 0; i < width; ++i) { row_pointers[j][i] = mapping[im->pixels[j][i]]; } } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); for (j = 0; j < height; ++j) { gdFree(row_pointers[j]); } gdFree(row_pointers); } else { png_write_image(png_ptr, im->pixels); png_write_end(png_ptr, info_ptr); } } /* 1.6.3: maybe we should give that memory BACK! TBB */ png_destroy_write_struct(&png_ptr, &info_ptr);}#endif /* HAVE_LIBPNG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -