void set_rgb_to_gray(rgb_to_gray_error_action error_action = rgb_to_gray_silent, double red_weight = -1.0, double green_weight = -1.0) const { TRACE_IO_TRANSFORM("png_set_rgb_to_gray: error_action=%d," " red_weight=%lf, green_weight=%lf\n", error_action, red_weight, green_weight); png_set_rgb_to_gray(m_png, error_action, red_weight, green_weight); }
bool PngDecoder::readData( Mat& img ) { bool result = false; AutoBuffer<uchar*> _buffer(m_height); uchar** buffer = _buffer; int color = img.channels() > 1; uchar* data = img.data; int step = (int)img.step; if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { png_structp png_ptr = (png_structp)m_png_ptr; png_infop info_ptr = (png_infop)m_info_ptr; png_infop end_info = (png_infop)m_end_info; if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { int y; if( img.depth() == CV_8U && m_bit_depth == 16 ) png_set_strip_16( png_ptr ); else if( !isBigEndian() ) png_set_swap( png_ptr ); if(img.channels() < 4) { /* observation: png_read_image() writes 400 bytes beyond * end of data when reading a 400x118 color png * "mpplus_sand.png". OpenCV crashes even with demo * programs. Looking at the loaded image I'd say we get 4 * bytes per pixel instead of 3 bytes per pixel. Test * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ png_set_strip_alpha( png_ptr ); } if( m_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) png_set_expand_gray_1_2_4_to_8( png_ptr ); #else png_set_gray_1_2_4_to_8( png_ptr ); #endif if( CV_MAT_CN(m_type) > 1 && color ) png_set_bgr( png_ptr ); // convert RGB to BGR else if( color ) png_set_gray_to_rgb( png_ptr ); // Gray->RGB else png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray png_read_update_info( png_ptr, info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = data + y*step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } close(); return result; }
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null) { if (cb_control_disp || disp_param) { throw EXCEPTION("Partial image decoding is not supported"); } // Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP; // Possibilities for decoding in different sizes aren't tested, so if anyone finds any of these cases, we'll know about it. if (stream->info.imageWidth != stream->out_param.outputWidth) { throw EXCEPTION("Image width doesn't match output width! (%d/%d)", stream->out_param.outputWidth, stream->info.imageWidth); } if (stream->info.imageHeight != stream->out_param.outputHeight) { throw EXCEPTION("Image width doesn't match output height! (%d/%d)", stream->out_param.outputHeight, stream->info.imageHeight); } // Get the amount of output bytes per line const u32 bytes_per_line = data_control_param->outputBytesPerLine; // Whether to recaculate bytes per row bool recalculate_bytes_per_row = false; // Check if the game is expecting the number of bytes per line to be lower, than the actual bytes per line on the image. (Arkedo Pixel for example) // In such case we strip the bit depth to be lower. if ((bytes_per_line < stream->out_param.outputWidthByte) && stream->out_param.outputBitDepth != 8) { // Check if the packing is really 1 byte per 1 pixel if (stream->packing != CELL_PNGDEC_1BYTE_PER_1PIXEL) { throw EXCEPTION("Unexpected packing value! (%d)", stream->packing); } // Scale 16 bit depth down to 8 bit depth. PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then. png_set_strip_16(stream->png_ptr); recalculate_bytes_per_row = true; } // Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding. else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents)) { // If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255) if (!stream->fixed_alpha) { stream->fixed_alpha_colour = 0xFF; } // We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game. png_set_add_alpha(stream->png_ptr, stream->fixed_alpha_colour, stream->out_param.outputColorSpace == CELL_PNGDEC_RGBA ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE); recalculate_bytes_per_row = true; } // We decode as RGBA, so we need to swap the alpha else if (stream->out_param.outputColorSpace == CELL_PNGDEC_ARGB) { // Swap the alpha channel for the ARGB output format, if the padding isn't needed png_set_swap_alpha(stream->png_ptr); } // Sometimes games pass in a RBG/RGBA image and want it as grayscale else if ((stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA || stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE) && (stream->info.colorSpace == CELL_PNGDEC_RGB || stream->info.colorSpace == CELL_PNGDEC_RGBA)) { // Tell libpng to convert it to grayscale png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); recalculate_bytes_per_row = true; } if (recalculate_bytes_per_row) { // Update the info structure png_read_update_info(stream->png_ptr, stream->info_ptr); // Recalculate the bytes per row stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr); } // Calculate the image size u32 image_size = stream->out_param.outputWidthByte * stream->out_param.outputHeight; // Buffer for storing the image std::vector<u8> png(image_size); // Make an unique pointer for the row pointers std::vector<u8*> row_pointers(stream->out_param.outputHeight); // Allocate memory for rows for (u32 y = 0; y < stream->out_param.outputHeight; y++) { row_pointers[y] = &png[y * stream->out_param.outputWidthByte]; } // Decode the image png_read_image(stream->png_ptr, row_pointers.data()); // Check if the image needs to be flipped const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP; // Copy the result to the output buffer switch (stream->out_param.outputColorSpace) { case CELL_PNGDEC_RGB: case CELL_PNGDEC_RGBA: case CELL_PNGDEC_ARGB: case CELL_PNGDEC_GRAYSCALE_ALPHA: { // Check if we need to flip the image or need to leave empty bytes at the end of a line if ((bytes_per_line > stream->out_param.outputWidthByte) || flip) { // Get how many bytes per line we need to output - bytesPerLine is total amount of bytes per line, rest is unused and the game can do as it pleases. const u32 line_size = std::min(bytes_per_line, stream->out_param.outputWidth * 4); // If the game wants more bytes per line to be output, than the image has, then we simply copy what we have for each line, // and continue on the next line, thus leaving empty bytes at the end of the line. for (u32 i = 0; i < stream->out_param.outputHeight; i++) { const u32 dst = i * bytes_per_line; const u32 src = stream->out_param.outputWidth * 4 * (flip ? stream->out_param.outputHeight - i - 1 : i); memcpy(&data[dst], &png[src], line_size); } } else { // We can simply copy the output to the data pointer specified by the game, since we already do alpha channel transformations in libpng, if needed memcpy(data.get_ptr(), png.data(), image_size); } break; } default: throw EXCEPTION("Unsupported color space (%d)", stream->out_param.outputColorSpace); } // Get the number of iTXt, tEXt and zTXt chunks s32 text_chunks = 0; png_get_text(stream->png_ptr, stream->info_ptr, nullptr, &text_chunks); // Set the chunk information and the previously obtained number of text chunks data_out_info->numText = (u32)text_chunks; data_out_info->chunkInformation = pngDecGetChunkInformation(stream, true); data_out_info->numUnknownChunk = 0; // TODO: Get this somehow. Does anything even use or need this? // Indicate that the decoding succeeded data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH; return CELL_OK; }
GrayMap *ReadGrayMapFile(FILE *file, const char *name) { GrayMap *result = NULL; struct png_struct_def *png = NULL; struct png_info_struct *pngInfo = NULL; struct png_info_struct *pngEndInfo = NULL; png_bytepp rows = NULL; png_uint_32 pngWidth, pngHeight; int depth, colorType; if (file == NULL) return NULL; // Set up PNG decoding. png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { fprintf(stderr, "Error preparing to read %s.\n", name); return NULL; } pngInfo = png_create_info_struct(png); if (pngInfo == NULL) { fprintf(stderr, "Error preparing to read %s.\n", name); return NULL; } pngEndInfo = png_create_info_struct(png); if (pngInfo == NULL) { fprintf(stderr, "Error preparing to read %s.\n", name); return NULL; } if (setjmp(png_jmpbuf(png))) { // libpng will jump here on error. free(rows); return NULL; } png_init_io(png, file); png_read_info(png, pngInfo); if (!png_get_IHDR(png, pngInfo, &pngWidth, &pngHeight, &depth, &colorType, NULL, NULL, NULL)) { fprintf(stderr, "Failed to get metadata from PNG %s", name); return NULL; } // Set to transform to 8-bit greyscale without alpha. if (colorType & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(png); } if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_strip_16(png); png_set_expand(png); } else if (colorType == PNG_COLOR_TYPE_PALETTE || colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_rgb_to_gray(png, 3, -1, -1); } else { fprintf(stderr, "Unknown colour type (0x%.X) in %s.\n", colorType, name); return NULL; } png_read_update_info(png, pngInfo); result = NewGrayMap(pngWidth, pngHeight, png_get_rowbytes(png, pngInfo)); if (result == NULL) { fprintf(stderr, "Could not allocate memory for source image.\n"); return NULL; } // Create array of row pointers. rows = MakeGrayMapRowPointers(result); if (rows == NULL) { fprintf(stderr, "Could not allocate memory for source image.\n"); DisposeGrayMap(result); return NULL; } // Read. png_read_image(png, rows); png_read_end(png, pngEndInfo); free(rows); png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); return result; }
static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) { FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr); if (!p) return; CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr; if (!pModule) return; png_uint_32 width = 0, height = 0; int bpc = 0, color_type = 0, color_type1 = 0, pass = 0; double gamma = 1.0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, nullptr, nullptr, nullptr); color_type1 = color_type; if (bpc > 8) { png_set_strip_16(png_ptr); } else if (bpc < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } bpc = 8; if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } pass = png_set_interlace_handling(png_ptr); if (!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass, &color_type, &gamma)) { png_error(p->png_ptr, "Read Header Callback Error"); } int intent; if (png_get_sRGB(png_ptr, info_ptr, &intent)) { png_set_gamma(png_ptr, gamma, 0.45455); } else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) { png_set_gamma(png_ptr, gamma, image_gamma); } else { png_set_gamma(png_ptr, gamma, 0.45455); } } switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: { if (color_type1 & PNG_COLOR_MASK_COLOR) { png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587); } } break; case PNG_COLOR_TYPE_PALETTE: if (color_type1 != PNG_COLOR_TYPE_PALETTE) { png_error(p->png_ptr, "Not Support Output Palette Now"); } case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: if (!(color_type1 & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(png_ptr); } png_set_bgr(png_ptr); break; } if (!(color_type & PNG_COLOR_MASK_ALPHA)) { png_set_strip_alpha(png_ptr); } if (color_type & PNG_COLOR_MASK_ALPHA && !(color_type1 & PNG_COLOR_MASK_ALPHA)) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } png_read_update_info(png_ptr, info_ptr); }
bool GrFmtPngReader::ReadData( uchar* data, int step, int color ) { bool result = false; uchar** buffer = 0; color = color > 0 || ( m_iscolor && color < 0 ); if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { png_structp png_ptr = (png_structp)m_png_ptr; png_infop info_ptr = (png_infop)m_info_ptr; png_infop end_info = (png_infop)m_end_info; if( setjmp(png_ptr->jmpbuf) == 0 ) { int y; if( m_bit_depth > 8 && !m_native_depth ) png_set_strip_16( png_ptr ); else if( !isBigEndian() ) png_set_swap( png_ptr ); /* observation: png_read_image() writes 400 bytes beyond * end of data when reading a 400x118 color png * "mpplus_sand.png". OpenCV crashes even with demo * programs. Looking at the loaded image I'd say we get 4 * bytes per pixel instead of 3 bytes per pixel. Test * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ png_set_strip_alpha( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) png_set_gray_1_2_4_to_8( png_ptr ); if( m_iscolor && color ) png_set_bgr( png_ptr ); // convert RGB to BGR else if( color ) png_set_gray_to_rgb( png_ptr ); // Gray->RGB else png_set_rgb_to_gray( png_ptr, 1, -1, -1 ); // RGB->Gray png_read_update_info( png_ptr, info_ptr ); buffer = new uchar*[m_height]; for( y = 0; y < m_height; y++ ) buffer[y] = data + y*step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } Close(); delete[] buffer; return result; }
struct IplImage *ipl_readimg(char *path, int mode) { FILE *f; unsigned char head[8]; int numb = 8, w, h, nchans = 3, y; size_t sznumb; struct IplImage *res; png_bytep* rows; png_structp pngp; png_infop infop; if (!(f = fopen(path, "rb"))) { perror("error opening file\n"); return NULL; } sznumb = fread(head, sizeof(char), numb, f); if (png_sig_cmp(head, 0, 8)) { perror("is not png"); fclose(f); return NULL; } if (!(pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) { perror("can't create read struct"); fclose(f); return NULL; } if (!(infop = png_create_info_struct(pngp))) { perror("can't create info"); png_destroy_read_struct(&pngp, NULL, NULL); fclose(f); return NULL; } if (setjmp(png_jmpbuf(pngp))) { perror("error in jumpbuf"); png_destroy_read_struct(&pngp, &infop, NULL); fclose(f); return NULL; } png_init_io(pngp, f); png_set_sig_bytes(pngp, sznumb); png_read_info(pngp, infop); png_set_strip_alpha(pngp); png_set_strip_16(pngp); if (mode) { nchans = 3; png_set_palette_to_rgb(pngp); } else { nchans = 1; png_set_rgb_to_gray(pngp, 1, 0.0f, 0.0f); png_set_expand_gray_1_2_4_to_8(pngp); } png_set_interlace_handling(pngp); png_read_update_info(pngp, infop); w = png_get_image_width(pngp, infop); h = png_get_image_height(pngp, infop); rows = (png_bytep *)malloc(sizeof(png_bytep) * h); for (y = 0; y < h; y++) { rows[y] = (png_byte *)malloc(png_get_rowbytes(pngp, infop)); } png_read_image(pngp, rows); res = (struct IplImage *)malloc(sizeof(struct IplImage)); res->width = w; res->height = h; res->nchans = nchans; res->data = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 3); for (y = 0; y < h; y++) memcpy(&(res->data[nchans * y * w]), rows[y], sizeof(png_byte) * png_get_rowbytes(pngp, infop)); for (y = 0; y < h; y++) free(rows[y]); free(rows); fclose(f); return res; }
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null) { if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL) { fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag); } // flag to keep unknown chunks png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0); // Scale 16 bit depth down to 8 bit depth. if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8) { // PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then. png_set_strip_16(stream->png_ptr); } // This shouldnt ever happen, but not sure what to do if it does, just want it logged for now if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16) cellPngDec.error("Output depth of 16 with non input depth of 16 specified!"); if (in_param->commandPtr != vm::null) cellPngDec.warning("Ignoring CommandPtr."); if (stream->info.colorSpace != in_param->outputColorSpace) { // check if we need to set alpha const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace); const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace); if (outputWantsAlpha && !inputHasAlpha) { if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA) png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); else { // Check if we can steal the alpha from a trns block if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(stream->png_ptr); // if not, just set default of 0xff else png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); } } else if (inputHasAlpha && !outputWantsAlpha) png_set_strip_alpha(stream->png_ptr); else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA) png_set_swap_alpha(stream->png_ptr); // Handle gray<->rgb colorspace conversions // rgb output if (in_param->outputColorSpace == CELL_PNGDEC_ARGB || in_param->outputColorSpace == CELL_PNGDEC_RGBA || in_param->outputColorSpace == CELL_PNGDEC_RGB) { if (stream->info.colorSpace == CELL_PNGDEC_PALETTE) png_set_palette_to_rgb(stream->png_ptr); if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA) && stream->info.bitDepth < 8) png_set_expand_gray_1_2_4_to_8(stream->png_ptr); } // grayscale output else { if (stream->info.colorSpace == CELL_PNGDEC_ARGB || stream->info.colorSpace == CELL_PNGDEC_RGBA || stream->info.colorSpace == CELL_PNGDEC_RGB) { png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); } else { // not sure what to do here cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported."); } } } stream->passes = png_set_interlace_handling(stream->png_ptr); // Update the info structure png_read_update_info(stream->png_ptr, stream->info_ptr); stream->out_param.outputWidth = stream->info.imageWidth; stream->out_param.outputHeight = stream->info.imageHeight; stream->out_param.outputBitDepth = in_param->outputBitDepth; stream->out_param.outputColorSpace = in_param->outputColorSpace; stream->out_param.outputMode = in_param->outputMode; stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr); stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->packing = in_param->outputPackFlag; // Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant. stream->out_param.useMemorySpace = 0; if (extra_in_param) { if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE) { cellPngDec.error("Invalid Buffermode specified."); return CELL_PNGDEC_ERROR_ARG; } if (stream->passes > 1) { stream->outputCounts = 1; } else stream->outputCounts = extra_in_param->outputCounts; if (extra_out_param) { if (stream->outputCounts == 0) extra_out_param->outputHeight = stream->out_param.outputHeight; else extra_out_param->outputHeight = std::min(stream->outputCounts, stream->out_param.outputHeight.value()); extra_out_param->outputWidthByte = stream->out_param.outputWidthByte; } } *out_param = stream->out_param; return CELL_OK; }
BitmapImage * PNGImageIO_loadPNGData(const void * data, size_t length, int pixelFormat, bool flipVertical) { png_byte headerBytes[PNG_HEADER_SIZE]; png_structp pngReadStruct; png_infop pngInfoStruct; struct memreadContext readContext; unsigned int width, height; png_int_32 bitDepth, colorType; png_bytep * rows = NULL; unsigned char * pixels = NULL; unsigned int rowIndex; enum BitmapPixelFormat chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; BitmapImage * image; readContext = memreadContextInit(data, length); if (!memread(&readContext, PNG_HEADER_SIZE, headerBytes) || png_sig_cmp(headerBytes, 0, PNG_HEADER_SIZE)) { return NULL; } pngReadStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); pngInfoStruct = png_create_info_struct(pngReadStruct); if (setjmp(png_jmpbuf(pngReadStruct))) { png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL); free(rows); free(pixels); return NULL; } png_set_read_fn(pngReadStruct, &readContext, pngReadFnMemread); png_set_sig_bytes(pngReadStruct, PNG_HEADER_SIZE); png_read_info(pngReadStruct, pngInfoStruct); width = png_get_image_width(pngReadStruct, pngInfoStruct); height = png_get_image_height(pngReadStruct, pngInfoStruct); bitDepth = png_get_bit_depth(pngReadStruct, pngInfoStruct); colorType = png_get_color_type(pngReadStruct, pngInfoStruct); if (colorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(pngReadStruct); colorType = PNG_COLOR_TYPE_RGB; } if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { png_set_expand_gray_1_2_4_to_8(pngReadStruct); } if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngReadStruct); } if (bitDepth == 16) { png_set_strip_16(pngReadStruct); } switch (pixelFormat) { case PNG_PIXEL_FORMAT_AUTOMATIC: switch (colorType) { case PNG_COLOR_TYPE_GRAY: chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88; break; case PNG_COLOR_TYPE_RGB: chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888; break; case PNG_COLOR_TYPE_RGB_ALPHA: chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; break; } png_read_update_info(pngReadStruct, pngInfoStruct); break; case BITMAP_PIXEL_FORMAT_RGBA_8888: if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER); } png_read_update_info(pngReadStruct, pngInfoStruct); if (!(colorType & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(pngReadStruct); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; break; case BITMAP_PIXEL_FORMAT_RGB_888: if (colorType & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(pngReadStruct); } png_read_update_info(pngReadStruct, pngInfoStruct); if (!(colorType & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(pngReadStruct); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888; break; case BITMAP_PIXEL_FORMAT_GRAYALPHA_88: if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER); } png_read_update_info(pngReadStruct, pngInfoStruct); if (colorType & PNG_COLOR_MASK_COLOR) { png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88; break; case BITMAP_PIXEL_FORMAT_GRAY_8: if (colorType & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(pngReadStruct); } png_read_update_info(pngReadStruct, pngInfoStruct); if (colorType & PNG_COLOR_MASK_COLOR) { png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8; break; } pixels = calloc(width * height, BitmapImage_pixelFormatBytes(chosenPixelFormat)); rows = malloc(sizeof(png_bytep) * height); for (rowIndex = 0; rowIndex < height; rowIndex++) { rows[rowIndex] = pixels + ((flipVertical ? height - rowIndex - 1 : rowIndex) * width * BitmapImage_pixelFormatBytes(chosenPixelFormat)); } png_read_rows(pngReadStruct, rows, NULL, height); png_read_end(pngReadStruct, NULL); png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL); free(rows); image = BitmapImage_createWithPixelsNoCopy(chosenPixelFormat, width, height, width * BitmapImage_pixelFormatBytes(chosenPixelFormat), pixels, true); return image; }
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const { struct s_my_png my_png; my_png.p = (char*)stringData.data(); my_png.size = stringData.length(); png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int *row = NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&my_png, mypng_error_func, mypng_warning_func); if ( !png_ptr ) return; if (setjmp( png_ptr->jmpbuf )) { data.init(0, 0); if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); } if ( row ) delete row; return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) mypng_error_func(png_ptr, "cannot create png info struct"); png_set_read_fn(png_ptr, (voidp)&my_png, mypng_read_func); png_read_info( png_ptr, info_ptr ); png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); data.init(width, height); row = new unsigned int[ width ]; // SET TRANSFORMS if (color_type & PNG_COLOR_MASK_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_invert_alpha(png_ptr); } else { png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff}; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0); png_set_strip_alpha(png_ptr); } if (bit_depth < 8) png_set_packing(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB) //png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // png_set_swap_alpha(png_ptr); if (! (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_rgb_to_gray(png_ptr, 1, -1, -1); int number_passes = png_set_interlace_handling(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || // color_type == PNG_COLOR_TYPE_GRAY_ALPHA) //if (color_type == PNG_COLOR_TYPE_RGB || // color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); char *c; for(int pass = 0; pass < number_passes; pass++) { for(unsigned int y = 0; y < height; y++) { png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1); c = ((ZLEwlImageData&)data).getImageData() + width * y; if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { unsigned char *s = (unsigned char*)row; if(dalgo == 1) for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*(++s)++, i, y); else for(unsigned int i = 0; i < width; i++) *c++ = *(++s)++; } else if(dalgo == 1) { unsigned char *s = (unsigned char*)row; for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*s++, i, y); } else memcpy(c, (char*)row, width); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); }