static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, float screen_gamma=0.0) { if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma(png_ptr, screen_gamma, file_gamma); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_bytep trans_alpha = 0; png_color_16p trans_color_p = 0; int num_trans; png_colorp palette = 0; int num_palette; int interlace_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0); png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { image = QImage(width, height, QImage::Format_Mono); if (image.isNull()) return; } image.setColorCount(2); image.setColor(1, qRgb(0,0,0)); image.setColor(0, qRgb(255,255,255)); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { image = QImage(width, height, QImage::Format_ARGB32); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) { image = QImage(width, height, QImage::Format_Indexed8); if (image.isNull()) return; } image.setColorCount(ncols); for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); image.setColorCount(num_palette); int i = 0; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { while (i < num_trans) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, trans_alpha[i] ) ); i++; } } while (i < num_palette) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); QImage::Format format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } QSize outSize(width,height); if (!scaledSize.isEmpty() && quint32(scaledSize.width()) <= width && quint32(scaledSize.height()) <= height && interlace_method == PNG_INTERLACE_NONE) { // Do inline downscaling outSize = scaledSize; if (doScaledRead) *doScaledRead = true; } if (image.size() != outSize || image.format() != format) { image = QImage(outSize, format); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { png_set_bgr(png_ptr); } }
static HPDF_STATUS LoadPngData (HPDF_Dict image, HPDF_Xref xref, HPDF_Stream png_data, HPDF_BOOL delayed_loading) { HPDF_STATUS ret = HPDF_OK; png_uint_32 width, height; int bit_depth, color_type; png_structp png_ptr = NULL; png_infop info_ptr = NULL; HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n")); /* create read_struct. */ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, image->error, PngErrorFunc, PngErrorFunc); if (png_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); return HPDF_FAILD_TO_ALLOC_MEM; } /* create info-struct */ info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); goto Exit; } png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK); png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc); /* reading info structure. */ png_read_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* 16bit images are not supported. */ if (bit_depth == 16) { png_set_strip_16(png_ptr); } png_read_update_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } /* check palette-based images for transparent areas and load them immediately if found */ if (xref && PNG_COLOR_TYPE_PALETTE & color_type) { png_bytep trans; int num_trans; HPDF_Dict smask; png_bytep smask_data; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { goto no_transparent_color_in_palette; } smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); ret += CreatePallet(image, png_ptr, info_ptr); ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } no_transparent_color_in_palette: /* read images with alpha channel right away we have to do this because image transparent mask must be added to the Xref */ if (xref && PNG_COLOR_MASK_ALPHA & color_type) { HPDF_Dict smask; png_bytep smask_data; smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); } else { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); } ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } /* if the image has color palette, copy the pallet of the image to * create color map. */ if (color_type == PNG_COLOR_TYPE_PALETTE) ret = CreatePallet(image, png_ptr, info_ptr); else if (color_type == PNG_COLOR_TYPE_GRAY) ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); else ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); if (ret != HPDF_OK) goto Exit; /* read image-data * if the image is interlaced, read whole image at once. * if delayed_loading is HPDF_TRUE, the data does not load this phase. */ if (delayed_loading) { image->before_write_fn = PngBeforeWrite; image->after_write_fn = PngAfterWrite; } else { if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE) ret = ReadPngData_Interlaced(image, png_ptr, info_ptr); else ret = ReadPngData(image, png_ptr, info_ptr); if (ret != HPDF_OK) goto Exit; } /* setting the info of the image. */ if (HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth) != HPDF_OK) goto Exit; /* clean up */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; Exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (ret != HPDF_OK) { return ret; } return image->error->error_no; }
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; }
void loadNativePNG(texture_t* tmpTex) { png_structp png_ptr; png_infop info_ptr; unsigned int width; unsigned int height; int i; int bit_depth; int color_type ; png_size_t rowbytes; png_bytep *row_pointers; png_byte header[8]; /* * char realPath[1024]; memset(realPath, 0, 1024); strcat(realPath, FS_Gamedir()); if (tmpTex->path[0] != '/') strcat(realPath, "/"); strcat(realPath, tmpTex->path); */ tmpTex->format = TEXTURE_TYPE_UNKNOWN ; file = FS_OpenFile(tmpTex->path, "rb"); //LOGI("[Android Main] Opening %s", realPath); if ( !file ) abort_textureLoading_("[read_png_file] Could not open file '%s'\n",tmpTex->path); FS_Read(header,1, 8,file); if (png_sig_cmp(header, 0, 8) != 0 ) abort_textureLoading_("[read_png_file] File is not recognized as a PNG file.\n", tmpTex->path); // initialize png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) abort_textureLoading_("[read_png_file] png_create_read_struct failed",""); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) abort_textureLoading_("[read_png_file] png_create_info_struct failed",""); if (setjmp(png_jmpbuf(png_ptr))) abort_textureLoading_("[read_png_file] Error during init_io",""); png_set_read_fn(png_ptr, NULL, png_zip_read); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); //Retrieve metadata and transfer to structure bean tmpTex png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); tmpTex->width = width; tmpTex->height = height; // Set up some transforms. /*if (color_type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(png_ptr); }*/ if (bit_depth > 8) { png_set_strip_16(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Rowsize in bytes. rowbytes = png_get_rowbytes(png_ptr, info_ptr); tmpTex->bpp = rowbytes / width; if (tmpTex->bpp == 4) tmpTex->format = TEXTURE_GL_RGBA; else tmpTex->format = TEXTURE_GL_RGB; Log_Printf("DEBUG: For %s, bpp: %i, color_type: %i, bit_depth: %i", tmpTex->path, tmpTex->bpp, color_type, bit_depth); //Since PNG can only store one image there is only one mipmap, allocated an array of one tmpTex->numMipmaps = 1; tmpTex->data = malloc(sizeof(uchar*)); if ((tmpTex->data[0] = (uchar*)malloc(rowbytes * height))==NULL) { //Oops texture won't be able to hold the result :(, cleanup LIBPNG internal state and return; free(tmpTex->data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return; } //Next we need to send to libpng an array of pointer, let's point to tmpTex->data[0] if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { // Oops looks like we won't have enough RAM to allocate an array of pointer.... png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(tmpTex->data ); tmpTex->data = NULL; return; } //FCS: Hm, it looks like we are flipping the image vertically. // Since iOS did not do it, we may have to not to that. If result is // messed up, just swap to: row_pointers[ i] = .... for (i = 0; i < height; ++i) //row_pointers[height - 1 - i] = tmpTex->data[0] + i * rowbytes; row_pointers[ i] = tmpTex->data[0] + i*rowbytes; //Decompressing PNG to RAW where row_pointers are pointing (tmpTex->data[0]) png_read_image(png_ptr, row_pointers); //Last but not least: // Free LIBPNG internal state. png_destroy_read_struct(&png_ptr, &info_ptr, NULL); //Free the decompression buffer free(row_pointers); FS_CloseFile(file); }
bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool-proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; png_uint_32 i, width, height = 0; int bit_depth, color_type, interlace_type; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, (voidp) NULL, wx_png_error, wx_png_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->Ok()) goto error; lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) ); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) { for ( unsigned int n = 0; n < i; n++ ) free( lines[n] ); goto error; } } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { const size_t ncolors = info_ptr->num_palette; unsigned char* r = new unsigned char[ncolors]; unsigned char* g = new unsigned char[ncolors]; unsigned char* b = new unsigned char[ncolors]; for (size_t j = 0; j < ncolors; j++) { r[j] = info_ptr->palette[j].red; g[j] = info_ptr->palette[j].green; b[j] = info_ptr->palette[j].blue; } image->SetPalette(wxPalette(ncolors, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); if ( image->Ok() ) { image->Destroy(); } if ( lines ) { for ( unsigned int n = 0; n < height; n++ ) free( lines[n] ); free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }
pictw_t * spng_read(session_t *ps, const char *path) { assert(path); char sig[SPNG_SIGBYTES] = ""; pictw_t *pictw = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE *fp = fopen(path, "rb"); bool need_premultiply = false; if (unlikely(!fp)) { printfef("(\"%s\"): Failed to open file.", path); goto spng_read_end; } if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) { printfef("(\"%s\"): Failed to read %d-byte signature.", path, SPNG_SIGBYTES); goto spng_read_end; } if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) { printfef("(\"%s\"): PNG signature invalid.", path); goto spng_read_end; } png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); info_ptr = allocchk(png_create_info_struct(png_ptr)); if (setjmp(png_jmpbuf(png_ptr))) goto spng_read_end; png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, SPNG_SIGBYTES); png_read_info(png_ptr, info_ptr); png_uint_32 width = 0, height = 0; // Set transformations int bit_depth = 0, color_type = 0; { int interlace_type = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Scale or strip 16-bit colors if (bit_depth == 16) { printfdf("(\"%s\"): Scaling 16-bit colors.", path); #if PNG_LIBPNG_VER >= 10504 png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif bit_depth = 8; } /* if (bit_depth < 8) png_set_packing(png_ptr); */ // No idea why this is needed... png_set_bgr(png_ptr); // Convert palette to RGB if (color_type == PNG_COLOR_TYPE_PALETTE) { printfdf("(\"%s\"): Converting palette PNG to RGB.", path); png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { printfdf("(\"%s\"): Converting rDNS to full alpha.", path); png_set_tRNS_to_alpha(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { printfdf("(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); png_set_gray_to_rgb(png_ptr); if (PNG_COLOR_TYPE_GRAY == color_type) color_type = PNG_COLOR_TYPE_RGB; else color_type = PNG_COLOR_TYPE_RGB_ALPHA; } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { printfdf("(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8(png_ptr); #else png_set_gray_1_2_4_to_8(png_ptr); #endif bit_depth = 8; } */ // Somehow XImage requires 24-bit visual to use 32 bits per pixel if (color_type == PNG_COLOR_TYPE_RGB) { printfdf("(\"%s\"): Appending filler alpha values.", path); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // Premultiply alpha if (PNG_COLOR_TYPE_RGB_ALPHA == color_type) { #if PNG_LIBPNG_VER >= 10504 png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, 1.0); #else need_premultiply = true; #endif } /* int number_passes = 1; #ifdef PNG_READ_INTERLACING_SUPPORTED number_passes = png_set_interlace_handling(png_ptr); #endif */ if (PNG_INTERLACE_NONE != interlace_type) png_set_interlace_handling(png_ptr); } png_read_update_info(png_ptr, info_ptr); int depth = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); switch (color_type) { case PNG_COLOR_TYPE_GRAY: depth = 1 * bit_depth; break; case PNG_COLOR_TYPE_RGB: depth = 3 * bit_depth; break; case PNG_COLOR_TYPE_RGB_ALPHA: depth = 4 * bit_depth; break; default: assert(0); break; } // Read data and fill to Picture { int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_bytep row_pointers[height]; memset(row_pointers, 0, sizeof(row_pointers)); row_pointers[0] = png_malloc(png_ptr, rowbytes * height); for (int row = 1; row < height; row++) row_pointers[row] = row_pointers[row - 1] + rowbytes; png_read_image(png_ptr, row_pointers); if (need_premultiply) for (int row = 0; row < height; row++) simg_data32_premultiply(row_pointers[row], width); if (unlikely(!(pictw = simg_data_to_pictw(ps, width, height, depth, row_pointers[0], rowbytes)))) { printfef("(\"%s\"): Failed to create Picture.", path); goto spng_read_end; } } spng_read_end: if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp) fclose(fp); return pictw; }
Load_SBit_Png( FT_GlyphSlot slot, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len, FT_Bool populate_map_and_metrics, FT_Bool metrics_only ) { FT_Bitmap *map = &slot->bitmap; FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows = NULL; /* pacify compiler */ if ( x_offset < 0 || y_offset < 0 ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( !populate_map_and_metrics && ( x_offset + metrics->width > map->width || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error || ( !populate_map_and_metrics && ( (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) ) ) goto DestroyExit; if ( populate_map_and_metrics ) { metrics->width = (FT_UShort)imgWidth; metrics->height = (FT_UShort)imgHeight; map->width = metrics->width; map->rows = metrics->height; map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = (int)( map->width * 4 ); map->num_grays = 256; /* reject too large bitmaps similarly to the rasterizer */ if ( map->rows > 0x4FFF || map->width > 0x4FFF ) { error = FT_THROW( Array_Too_Large ); goto DestroyExit; } } /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } if ( metrics_only ) goto DestroyExit; switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( populate_map_and_metrics ) { /* this doesn't overflow: 0x4FFF * 0x4FFF * 4 < 2^31 */ FT_ULong size = map->rows * (FT_ULong)map->pitch; error = ft_glyphslot_alloc_bitmap( slot, size ); if ( error ) goto DestroyExit; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
void PngReader::read(unsigned x0, unsigned y0,ImageData32& image) { FILE *fp=fopen(fileName_.c_str(),"r"); if (!fp) throw ImageReaderException("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw ImageReaderException("failed to allocate png_ptr"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw ImageReaderException("failed to create info_ptr"); } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth_ == 16) png_set_strip_16(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY || color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,1,1); double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); png_read_update_info(png_ptr, info_ptr); //START read image rows unsigned w=std::min((unsigned)image.width(),width_); unsigned h=std::min((unsigned)image.height(),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); unsigned char* row= new unsigned char[rowbytes]; for (unsigned i=0; i<height_; ++i) { png_read_row(png_ptr,row,0); if (i>=y0 && i<h) { image.setRow(i-y0,(unsigned*) &row[x0],w); } } //END delete [] row; png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } // catch errors in a custom way to avoid the need for setjmp png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); png_infop info_ptr; try { info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } } catch (std::exception const& ex) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw; } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth_ == 16) png_set_strip_16(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY || color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_) { if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) { png_set_interlace_handling(png_ptr); // FIXME: libpng bug? // according to docs png_read_image // "..automatically handles interlacing, // so you don't need to call png_set_interlace_handling()" } png_read_update_info(png_ptr, info_ptr); // we can read whole image at once // alloc row pointers boost::scoped_array<png_byte*> rows(new png_bytep[height_]); for (unsigned i=0; i<height_; ++i) rows[i] = (png_bytep)image.getRow(i); png_read_image(png_ptr, rows.get()); } else { png_read_update_info(png_ptr, info_ptr); unsigned w=std::min(unsigned(image.width()),width_); unsigned h=std::min(unsigned(image.height()),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); boost::scoped_array<png_byte> row(new png_byte[rowbytes]); //START read image rows for (unsigned i=0;i<height_;++i) { png_read_row(png_ptr,row.get(),0); if (i>=y0 && i<h) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w); } } //END } png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
char* Model::load_png(std::string fileName, int *width, int *height) { fileName = "Resources/" + fileName; FILE *png_file = fopen(fileName.c_str(), "rb"); //assert(png_file.open); uint8_t header[PNG_SIG_BYTES]; fread(header, 1, PNG_SIG_BYTES, png_file); assert(!png_sig_cmp(header, 0, PNG_SIG_BYTES)); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); assert(png_ptr); png_infop info_ptr = png_create_info_struct(png_ptr); assert(info_ptr); png_infop end_info = png_create_info_struct(png_ptr); assert(end_info); assert(!setjmp(png_jmpbuf(png_ptr))); png_init_io(png_ptr, png_file); png_set_sig_bytes(png_ptr, PNG_SIG_BYTES); png_read_info(png_ptr, info_ptr); *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); png_uint_32 bit_depth, color_type; bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); // if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) // png_set_gray_1_2_4_to_8(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); else if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_uint_32 numbytes = rowbytes * (*height); png_byte* pixels = (png_byte*) malloc(numbytes); png_byte** row_ptrs = (png_byte**) malloc((*height) * sizeof (png_byte*)); int i; for (i = 0; i < (*height); i++) row_ptrs[i] = pixels + ((*height) - 1 - i) * rowbytes; png_read_image(png_ptr, row_ptrs); free(row_ptrs); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(png_file); return (char *) pixels; }
/* Read a PNG file. You may want to return an error code if the read * fails (depending upon the failure). There are two "prototypes" given * here - one where we are given the filename, and we need to open the * file, and the other where we are given an open file (possibly with * some or all of the magic bytes read - see comments above). */ #ifdef open_file /* prototype 1 */ void read_png(char *file_name) /* We need to open the file */ { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); #else no_open_file /* prototype 2 */ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; #endif no_open_file /* Only use one prototype! */ /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return (ERROR); } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (ERROR); } /* One of the following I/O initialization methods is REQUIRED */ #ifdef streams /* PNG file I/O method 1 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); #else no_streams /* PNG file I/O method 2 */ /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ #endif no_streams /* Use only one I/O method! */ /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); #ifdef hilevel /* * If you have enough memory to read in the entire image at once, * and you need to specify only transforms that can be controlled * with one of the PNG_TRANSFORM_* bits (this presently excludes * quantizing, filling, setting background, and doing gamma * adjustment), then you can read the entire image (including * pixels) into the info structure with this call: */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); #else /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* Tell libpng to strip 16 bit/color files down to 8 bits/color. * Use accurate scaling if it's available, otherwise just chop off the * low byte. */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ png_set_strip_alpha(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0) png_set_tRNS_to_alpha(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background) != 0) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* Some suggestions as to how to get a screen gamma value * * Note that screen gamma is the display_exponent, which includes * the CRT_exponent and any correction for viewing conditions */ if (/* We have a user-defined screen gamma value */) { screen_gamma = user-defined screen_gamma; } /* This is one way that applications share the same screen gamma value */ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
uint8_t* ImageDecoder::decodePNGImpl(png_structp pngPtr, uint32_t* width, uint32_t* height, bool* hasAlpha) { png_bytep* rowPtrs = NULL; uint8_t* outData = NULL; png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { LOG(LOG_ERROR,"Couldn't initialize png info struct"); png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); return NULL; } if (setjmp(png_jmpbuf(pngPtr))) { png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); if (rowPtrs != NULL) delete [] rowPtrs; if (outData != NULL) delete [] outData; LOG(LOG_ERROR,"error during reading of the png file"); return NULL; } png_read_info(pngPtr, infoPtr); *width = png_get_image_width(pngPtr, infoPtr); *height = png_get_image_height(pngPtr, infoPtr); //bits per CHANNEL! note: not per pixel! png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr); //Number of channels png_uint_32 channels = png_get_channels(pngPtr, infoPtr); //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr); // Transform everything into 24 bit RGB switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) png_set_gray_to_rgb(pngPtr); break; } if (bitdepth == 16) { png_set_strip_16(pngPtr); } *hasAlpha = (channels > 3); // Update the infoPtr to reflect the transformations set // above. Read new values by calling png_get_* again. png_read_update_info(pngPtr, infoPtr); //bitdepth = png_get_bit_depth(pngPtr, infoPtr); //color_type = png_get_color_type(pngPtr, infoPtr); const unsigned int stride = png_get_rowbytes(pngPtr, infoPtr); outData = new uint8_t[(*height) * stride]; rowPtrs = new png_bytep[(*height)]; for (size_t i = 0; i < (*height); i++) { rowPtrs[i] = (png_bytep)outData + i* stride; } png_read_image(pngPtr, rowPtrs); png_read_end(pngPtr, NULL); png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); delete[] (png_bytep)rowPtrs; return outData; }
unsigned char* LoadPNGJPGFromMemory(const unsigned char* buffer, int len, int* width, int* height) { const int number=8; // проверяем сигнатуру файла (первые number байт) if ( !png_check_sig((png_bytep)buffer, number) ) { // неизвестный формат return LoadJPGWithAlphaFromMemory(buffer, len, width, height); } // создаем внутреннюю структуру png для работы с файлом // последние параметры - структура, для функции обработки ошибок и варнинга (последн. 2 параметра) png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); // создаем структуру с информацией о файле png_infop info_ptr = png_create_info_struct(png_ptr); PNGBuffer pngBuffer; pngBuffer.data = (png_bytep)buffer; pngBuffer.position = 8; png_set_read_fn(png_ptr, (void*)&pngBuffer, PNGRead); // говорим библиотеке, что мы уже прочли number байт, когда проверяли сигнатуру png_set_sig_bytes(png_ptr, number); // читаем всю информацию о файле png_read_info(png_ptr, info_ptr); // Эта функция возвращает инфу из info_ptr png_uint_32 w = 0, h = 0; // размер картинки в пикселях int bit_depth = 0; // глубина цвета (одного из каналов, может быть 1, 2, 4, 8, 16) int color_type = 0; // описывает какие каналы присутствуют: // PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, // PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGB_ALPHA... // последние 3 параметра могут быть нулями и обозначают: тип фильтра, тип компрессии и тип смещения png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0); // png формат может содержать 16 бит на канал, но нам нужно только 8, поэтому сужаем канал if (bit_depth == 16) png_set_strip_16(png_ptr); // преобразуем файл если он содержит палитру в нормальный RGB if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_palette_to_rgb(png_ptr); // если в грэйскейле меньше бит на канал чем 8, то конвертим к нормальному 8-битному //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 (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); double gamma = 0.0f; // если есть информация о гамме в файле, то устанавливаем на 2.2 if ( png_get_gAMA(png_ptr, info_ptr, &gamma) ) png_set_gamma(png_ptr, 2.2, gamma); // иначе ставим дефолтную гамму для файла в 0.45455 (good guess for GIF images on PCs) else png_set_gamma(png_ptr, 2.2, 0.45455); // после всех трансформаций, апдейтим информацию в библиотеке png_read_update_info(png_ptr, info_ptr); // опять получаем все размеры и параметры обновленной картинки png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0); // определяем кол-во байт нужных для того чтобы вместить строку png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr); // теперь, мы можем выделить память чтобы вместить картинку png_byte* data = new png_byte[row_bytes * h]; // выделяем память, для указателей на каждую строку png_byte **row_pointers = new png_byte * [h]; // сопоставляем массив указателей на строчки, с выделенными в памяти (res) // т.к. изображение перевернутое, то указатели идут снизу вверх for (unsigned int i = 0; i < h; i++) row_pointers[i] = data + i * row_bytes; // все, читаем картинку png_read_image(png_ptr, row_pointers); // освобождаем память от указателей на строки delete []row_pointers; // освобождаем память выделенную для библиотеки libpng png_destroy_read_struct(&png_ptr, &info_ptr, 0); *width=w; *height=h; return data; }
/* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
bool Texture::load2DPNG(const char *name, bool genMIPs) { ASSERT(name); png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int32_t bit_depth, color_type, stride; uint8_t *buffer, *data; png_bytep *row_pointers; uint32_t size; GLint internalFormat; GLenum format; if (!VFS::load(name, VFS_BINARY, &buffer, &size)) return false; if (size <= 8) { LOG_ERROR("Too small PNG file '%s'\n", name); delete[] buffer; return false; } if (png_sig_cmp((png_byte *)buffer, 0, 8)) { LOG_ERROR("Wrong PNG format '%s'\n", name); delete[] buffer; return false; } if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNGError, NULL)) == NULL) { LOG_ERROR("Failed to create PNG read struct\n"); delete[] buffer; return false; } if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { LOG_ERROR("Failed to create PNG info struct\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); delete[] buffer; return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete[] buffer; return false; } png_set_read_fn(png_ptr, (void *)(buffer + 8), PNGRead); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_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 (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) // png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: internalFormat = GL_R8; format = GL_RED; break; case PNG_COLOR_TYPE_RGB: internalFormat = GL_RGB8; format = GL_RGB; break; case PNG_COLOR_TYPE_RGBA: internalFormat = GL_RGBA8; format = GL_RGBA; break; default: LOG_ERROR("Unknown PNG color type %d in '%s'\n", color_type, name); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete[] buffer; return false; } stride = png_get_rowbytes(png_ptr, info_ptr); row_pointers = new png_bytep[height]; ASSERT(row_pointers); data = new uint8_t[height * stride]; ASSERT(data); for (uint32_t i = 0; i < height; ++i) row_pointers[i] = (png_bytep)data + i * stride; png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete[] row_pointers; delete[] buffer; image2D(GL_PVOID(data), width, height, internalFormat, format, GL_UNSIGNED_BYTE, genMIPs); delete[] data; return true; }
/** Reads one PNG file. @param process Process the image data (0 for initial parameter determination) @returns -1 on failure, 1 on sucess */ int decode_png(const char *pngname, int process, parameters_t *param) { int num_pass = 1; int bit_depth, color_type; FILE *pngfile; //png_byte hdptr[8]; /* Now open this PNG file, and examine its header to retrieve the YUV4MPEG info that shall be written */ pngfile = fopen(pngname, "rb"); if (!pngfile) { perror("PNG file open failed:"); return -1; } //fread(hdptr, 1, 8, pngfile); #if 0 bool is_png = !png_sig_cmp(hdptr, 0, 8); if (!is_png) { mjpeg_error("%s is _no_ PNG file !\n"); return -1; } #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) mjpeg_error_exit1("%s: Could not allocate PNG read struct !", pngname); png_init_io(png_ptr, pngfile); //png_set_sig_bytes(png_ptr, 8); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG info struct !", pngname); } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG end info struct !", pngname); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); mjpeg_error("%s: Corrupted PNG file !", pngname); return -1; } if (process) png_set_read_user_transform_fn(png_ptr, png_separation); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA, NULL); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); #if 0 mjpeg_info("Reading info struct...\n"); png_read_info(png_ptr, info_ptr); mjpeg_info("Done...\n"); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); if (process) { printf("%d passes needed\n\n", num_pass); if (bit_depth != 8 && bit_depth != 16) { mjpeg_error_exit1("Invalid bit_depth %d, only 8 and 16 bit allowed !!\n", bit_depth); } png_set_strip_16(png_ptr); // always has to strip the 16bit input, MPEG can't handle it png_set_strip_alpha(png_ptr); // Alpha can't be processed until Z/Alpha is integrated printf("\nAllocating row buffer..."); png_set_read_user_transform_fn(png_ptr, png_separation); png_bytep row_buf = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); for (int n=0; n < num_pass; n++) for (int y=0; y < sh_param->height; y++) { printf("Writing row data for pass %d\n", n); png_read_rows(png_ptr, (png_bytepp)&row_buf, NULL, 1); } png_free(png_ptr, row_buf); } png_read_end(png_ptr, info_ptr); #endif if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return 2; } fclose(pngfile); return 1; }
png_bytep readpng_get_image(png_structp* png_ptr, png_infop* info_ptr, png_infop* end_ptr) { //test for if(setjmp(png_jmpbuf(*png_ptr))) { png_destroy_read_struct(png_ptr, info_ptr, NULL); std::cerr << "error during setjmp" << std::endl; return NULL; } png_uint_32 width, height; int bit_depth, color_type; png_uint_32 numrowbytes; png_bytep dataBlock; // gamma correction start (optional) double display_exponent = 2.2; //standard in most systems + standard in imageprocessing int envGamma = 0; if(envGamma) display_exponent = (double)envGamma; double gamma; if(png_get_gAMA(*png_ptr, *info_ptr, &gamma)) png_set_gamma(*png_ptr, display_exponent, gamma); // gamma correction end png_get_IHDR(*png_ptr, *info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); //transform the png to a standard format if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(*png_ptr); if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(*png_ptr); if(png_get_valid(*png_ptr, *info_ptr, PNG_INFO_tRNS)) png_set_expand(*png_ptr); if(bit_depth == 16) png_set_strip_16(*png_ptr); if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(*png_ptr); png_read_update_info(*png_ptr, *info_ptr); //end //proccessing for the dataBlock (pixeldata) numrowbytes = png_get_rowbytes(*png_ptr, *info_ptr); png_bytep row_pointers[height]; dataBlock = (png_bytep)malloc(sizeof(png_byte)*numrowbytes*height); for(png_uint_32 i = 0; i<height; i++) row_pointers[i] = dataBlock + i*numrowbytes; png_read_image(*png_ptr, row_pointers); //end //optional reading of end in end_ptr and test for consistence png_read_end(*png_ptr, NULL); return dataBlock; }
unsigned char *sdlgl_load_png_file(const char *filename, int *image_w, int *image_h) { /* -AJA- all these volatiles here may seem strange. They are needed * because the ANSI C standard (which GCC adheres to) says that when * setjmp/longjmp is being used, only volatile local variables are * guaranteed to keep their state if longjmp() gets called. */ FILE * volatile fp = NULL; unsigned char * volatile image_dat = NULL; png_bytep * volatile row_pointers = NULL; /* we take the address of these two, so we shouldn't need the * volatile. (GCC complains about discarding qualifiers if the * volatile is there). */ png_structp /*volatile*/ png_ptr = NULL; png_infop /*volatile*/ info_ptr = NULL; char sig_buf[CHECK_PNG_BYTES]; png_uint_32 width, height; int bit_depth, color_type, interlace_type; int row, stride; /* open the prospective PNG file */ #ifdef FILE_AREAS fp = fopen_datafile_area(FILE_AREA_SHARE, filename, RDBMODE, FALSE); #else fp = fopen_datafile(filename, RDBMODE, FALSE); #endif if (!fp) { sdlgl_warning("Failed to open file: %s\n", filename); return NULL; } /* read in some of the signature bytes */ if (fread(sig_buf, 1, CHECK_PNG_BYTES, fp) != CHECK_PNG_BYTES) { sdlgl_warning("Failed to read from file: %s\n", filename); goto failed; } /* compare the first CHECK_PNG_BYTES bytes of the signature */ if (png_sig_cmp(sig_buf, (png_size_t)0, CHECK_PNG_BYTES) != 0) { sdlgl_warning("File is not a PNG file: %s\n", filename); goto failed; } /* pass NULLs for the error functions -- thus use the setjump stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { sdlgl_warning("Problem within LibPNG (no memory ?)\n"); goto failed; } /* allocate/initialize the memory for image information */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { sdlgl_warning("Out of memory with LibPNG\n"); goto failed; } /* set error handling since we are using the setjmp/longjmp method * (this is the normal method of doing things with libpng). */ if (setjmp(png_ptr->jmpbuf)) { sdlgl_warning("Problem within LibPNG (unknown)\n"); goto failed; } /* set up the input control since we're using standard C streams */ png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, CHECK_PNG_BYTES); /* the call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk) */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); *image_w = (int)width; *image_h = (int)height; /* tell libpng to strip 16 bit/color down to 8 bits/color */ png_set_strip_16(png_ptr); /* expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); } /* set alpha position and filler value */ png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); /* let all the above calls take effect */ png_read_update_info(png_ptr, info_ptr); /* allocate the memory for the image */ stride = png_get_rowbytes(png_ptr, info_ptr); image_dat = (unsigned char *) alloc(height * stride); row_pointers = (png_bytep *) alloc(height * sizeof(png_bytep)); for (row=0; row < height; row++) { row_pointers[row] = image_dat + row * stride; } /* now read in the image. Yeah baby ! */ png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); /* free stuff & close the file */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(row_pointers); fclose(fp); return image_dat; /* -AJA- Normally I don't like gotos. In this situation where there * are lots of points of possible failure and a growing set of * things to be undone, it makes for nicer code. */ failed: if (image_dat) free(image_dat); if (png_ptr) { /* assume NULLs not allowed (png docs don't say, bad bad) */ if (info_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); else png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); } if (row_pointers) free(row_pointers); if (fp) fclose(fp); return NULL; }
unsigned char* PPGame_LoadPNG(const char* fileName,unsigned long* imageWidth,unsigned long* imageHeight,unsigned long* bytesPerRow) { FILE *PNG_file = fopen(fileName, "rb"); fprintf(stderr, "open PNG file %s\n", fileName); if (PNG_file == NULL) { fprintf(stderr, "Can't open PNG file %s\n", fileName); return NULL; } unsigned char PNG_header[PNG_HEADER_SIZE]; fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file); if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0) { fprintf(stderr, "%s is not a PNG file\n", fileName); fclose(PNG_file); return NULL; } /* { for (int i=0;i<8;i++) { printf("%02X,",PNG_header[i]); } printf("\n"); } */ png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (PNG_reader == NULL) { fprintf(stderr, "Can't start reading PNG file %s\n", fileName); fclose(PNG_file); return NULL; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (PNG_info == NULL) { fprintf(stderr, "Can't get info for PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, NULL, NULL); fclose(PNG_file); return NULL; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { fprintf(stderr, "Can't get end info for PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); fclose(PNG_file); return NULL; } if (setjmp(png_jmpbuf(PNG_reader))) { fprintf(stderr, "Can't load PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return NULL; } png_init_io(PNG_reader, PNG_file); png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE); png_read_info(PNG_reader, PNG_info); if (PNG_reader == NULL) { fclose(PNG_file); return NULL; } png_uint_32 width, height; width = png_get_image_width(PNG_reader, PNG_info); height = png_get_image_height(PNG_reader, PNG_info); //printf("width %d\n",width); //printf("height %d\n",height); png_uint_32 bit_depth, color_type; bit_depth = png_get_bit_depth(PNG_reader, PNG_info); color_type = png_get_color_type(PNG_reader, PNG_info); //printf("bit_depth %d\n",bit_depth); //printf("rowbytes %d\n",png_get_rowbytes(PNG_reader, PNG_info)); if (color_type == PNG_COLOR_TYPE_PALETTE) { //png_set_palette_to_rgb(PNG_reader); png_set_palette_to_rgb(PNG_reader); } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_gray_1_2_4_to_8(PNG_reader); } */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(PNG_reader); } if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PNG_reader); } else { png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER); } if (bit_depth == 16) { png_set_strip_16(PNG_reader); } png_read_update_info(PNG_reader, PNG_info); png_byte* PNG_image_buffer = (png_byte*)malloc(4 * width * height); png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*)); unsigned int row; for (row = 0; row < height; ++row) { //PNG_rows[height - 1 - row] = PNG_image_buffer + (row * 4 * width); PNG_rows[row] = PNG_image_buffer + (row * 4 * width); } png_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); *imageWidth = width; *imageHeight = height; *bytesPerRow = width*4; printf("width %d,height %d\n",width,height); { unsigned long width,height; unsigned char* image; width = *imageWidth; height = *imageHeight; image = PNG_image_buffer; if (image) { unsigned char* pixel = (unsigned char*)malloc(height*width*4); if (pixel) { int i,j; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { #if 0 pixel[j*4+0+i*width*4] = 0xff; pixel[j*4+1+i*width*4] = 0xff; pixel[j*4+2+i*width*4] = 0xff; pixel[j*4+3+i*width*4] = 0xff; #else unsigned char r,g,b,a; r = image[j*4+0+i*width*4]; g = image[j*4+1+i*width*4]; b = image[j*4+2+i*width*4]; a = image[j*4+3+i*width*4]; if (a == 0) { pixel[j*4+0+i*width*4] = 0; pixel[j*4+1+i*width*4] = 0; pixel[j*4+2+i*width*4] = 0; pixel[j*4+3+i*width*4] = 0; } else { pixel[j*4+0+i*width*4] = r; pixel[j*4+1+i*width*4] = g; pixel[j*4+2+i*width*4] = b; pixel[j*4+3+i*width*4] = a; } #endif } } free(image); PNG_image_buffer = pixel; } } } return PNG_image_buffer; }
int fh_png_load(const char *name,unsigned char **buffer,int* /*xp*/,int* /*yp*/) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes,pass; png_byte * fbptr; FILE * fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if(png_ptr == NULL) { fclose(fh); return(FH_ERROR_FORMAT); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } if(setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } /* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least), but the data delivered is with alpha channel anyway, so always strip alpha for now */ #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36 if (color_type & PNG_COLOR_MASK_ALPHA) #endif png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); printf(" width: %lu rowbytes: %lu\n", width, png_get_rowbytes(png_ptr, info_ptr)); fclose(fh); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)(*buffer); for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) return NULL; // Bad signature // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) return NULL; // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = info_ptr->pixel_depth; // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_expand(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw "PNG format not supported"; } // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; } // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) png_set_gamma(png_ptr, screen_gamma, gamma); // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_Allocate(width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette,&palette_entries); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { int num_trans = 0; png_bytep trans = NULL; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); FreeImage_SetTransparencyTable(dib, (BYTE *)trans, num_trans); } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_color_16p trans_values = NULL; png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_values); if(trans_values) { if (trans_values->gray < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_values->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } } break; default: throw "PNG format not supported"; } // store the background color if(image_background) { FreeImage_SetBackgroundColor(dib, &rgbBkColor); } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = 0; png_get_pHYs(png_ptr,info_ptr,&res_x,&res_y,&res_unit_type); if (res_unit_type == 1) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_charp profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_Allocate) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { if (palette) png_free(png_ptr, palette); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table for (png_uint_32 k = 0; k < height; k++) row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) FreeImage_SetTransparent(dib, TRUE); else FreeImage_SetTransparent(dib, FALSE); // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (row_pointers) free(row_pointers); if (dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
// // In order to avoid CRT mismatches, we override all CRT functions libpng uses // with our own. The alternative, using fopen and fread in our code and then // passing a FILE* into libpng, isn't reliable because it crashes if libpng was // compiled with a different CRT than lsapi.dll // HBITMAP LoadFromPNG(LPCSTR pszFilename) { HBITMAP hDibSection = NULL; if (pszFilename != NULL) { FILE * hFile = fopen(pszFilename, "rb"); if (hFile) { const size_t num_sig_bytes = 8; unsigned char sig[num_sig_bytes]; fread(sig, 1, num_sig_bytes, hFile); if (png_check_sig(sig, num_sig_bytes)) { PNGERROR PngError = { 0 }; PngError.Wnd = GetForegroundWindow(); png_structp Read = png_create_read_struct_2( PNG_LIBPNG_VER_STRING, &PngError, PNGErrorHandler, NULL, NULL, ls_png_malloc, ls_png_free); if (Read) { png_infop Info = png_create_info_struct(Read); if (Info) { if (!setjmp(PngError.ErrorJump)) { png_set_read_fn(Read, hFile, ls_png_read_data); png_set_sig_bytes(Read, num_sig_bytes); png_read_info(Read, Info); const unsigned char bit_depth = png_get_bit_depth(Read, Info); const unsigned char color_type = png_get_color_type(Read, Info); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(Read); } if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { if (bit_depth < 8) { png_set_gray_1_2_4_to_8(Read); } png_set_gray_to_rgb(Read); } if (png_get_valid(Read, Info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(Read); } if (color_type & PNG_COLOR_MASK_COLOR) { png_set_bgr(Read); } if (bit_depth == 16) { png_set_strip_16(Read); } double image_gamma = 1 / 2.2; png_get_gAMA(Read, Info, &image_gamma); png_set_gamma(Read, 2.2, image_gamma); const int num_passes = png_set_interlace_handling(Read); png_read_update_info(Read, Info); BITMAPINFO bmi = { {0} }; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = (LONG)png_get_image_width(Read, Info); bmi.bmiHeader.biHeight = -(LONG)png_get_image_height(Read, Info); bmi.bmiHeader.biBitCount = (WORD)(png_get_channels(Read, Info) * png_get_bit_depth(Read, Info)); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; unsigned char* bits; hDibSection = CreateDIBSection(NULL, &bmi, 0, reinterpret_cast<LPVOID*>(&bits), NULL, 0); if (!bits) { longjmp(PngError.ErrorJump, 1); } unsigned int dib_bytes_per_scanline = \ (((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) & ~31) >> 3; for (int Pass = 0; Pass < num_passes; ++Pass) { for (int y = 0; y < -bmi.bmiHeader.biHeight; ++y) { unsigned char* Scanline = \ reinterpret_cast<unsigned char*>(bits + (y * dib_bytes_per_scanline)); png_read_row(Read, Scanline, NULL); } } png_read_end(Read, Info); png_destroy_read_struct(&Read, &Info, NULL); } else { png_destroy_read_struct(&Read, &Info, NULL); } } else { png_destroy_read_struct(&Read, NULL, NULL); } }
static FT_Error Load_SBit_Png( FT_Bitmap* map, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len ) { FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows; if ( x_offset < 0 || x_offset + metrics->width > map->width || y_offset < 0 || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error != FT_Err_Ok || (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) goto DestroyExit; /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
WL_EXPORT uint32_t * weston_load_image(const char *filename, int32_t *width_arg, int32_t *height_arg, uint32_t *stride_arg) { png_struct *png; png_info *info; png_byte *data; png_byte **row_pointers = NULL; png_uint_32 width, height; int depth, color_type, interlace, stride; unsigned int i; FILE *fp; fp = fopen(filename, "rb"); if (fp == NULL) return NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { fclose(fp); return NULL; } info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } png_set_read_fn(png, fp, read_func); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY) png_set_expand_gray_1_2_4_to_8(png); if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); if (depth == 16) png_set_strip_16(png); if (depth < 8) png_set_packing(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling(png); png_set_filler(png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn(png, premultiply_data); png_read_update_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, NULL, NULL); stride = width * 4; data = malloc(stride * height); if (!data) { png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } row_pointers = malloc(height * sizeof row_pointers[0]); if (row_pointers == NULL) { free(data); png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } for (i = 0; i < height; i++) row_pointers[i] = &data[i * stride]; png_read_image(png, row_pointers); png_read_end(png, info); free(row_pointers); png_destroy_read_struct(&png, &info, NULL); fclose(fp); *width_arg = width; *height_arg = height; *stride_arg = stride; return (uint32_t *) data; }
int png_load_img(img I) { unsigned char **p, **q; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int i, j, bit_depth, color_type, interlace_type; png_bytepp row_pointers; img_alloc(I); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { I->err = IE_HDRFORMAT; return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); I->err = IE_HDRFORMAT; return 0; } rewind(I->fp); png_init_io(png_ptr, I->fp); png_read_info(png_ptr, info_ptr); /* Get image specific data */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Convert greyscale images to 8-bit RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { //png_set_gray_1_2_4_to_8(png_ptr); png_set_expand_gray_1_2_4_to_8(png_ptr); } png_set_gray_to_rgb(png_ptr); } /* Change paletted images to RGB */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (bit_depth < 8) png_set_expand(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* The gdk img widget appears to expect 8-bit RGB followed by a * filler byte. */ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); /* Update the info structure after the transforms */ png_read_update_info(png_ptr, info_ptr); /* png_set_rows(png_ptr, info_ptr, row_pointers)*/ /* Allocate space before reading the image */ row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep)); for (i = 0; i < height; i++) { row_pointers[i] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } /* Read in the image and copy it to the gdk img structure */ png_read_image(png_ptr, row_pointers); p = (unsigned char **)I->data; q = (unsigned char **)row_pointers; for (i = 0; i < height; i++) { for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++) { p[i][j] = q[i][j]; } } png_read_end(png_ptr, info_ptr); /* Clean up */ png_free(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 1; }
int image_png_load(MediaScanImage *i) { int bit_depth, color_type, num_passes, x, y; int ofs; volatile unsigned char *ptr = NULL; // volatile = won't be rolled back if longjmp is called PNGData *p = (PNGData *)i->_png; if (setjmp(png_jmpbuf(p->png_ptr))) { if (ptr != NULL) free((void *)ptr); image_png_destroy(i); return 0; } // XXX If reusing the object a second time, we need to completely create a new png struct bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr); color_type = png_get_color_type(p->png_ptr, p->info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(p->png_ptr); // png_set_palette_to_rgb(p->png_ptr); i->channels = 4; } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(p->png_ptr); // png_set_expand_gray_1_2_4_to_8(p->png_ptr); else if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS)) png_set_expand(p->png_ptr); // png_set_tRNS_to_alpha(p->png_ptr); if (bit_depth == 16) png_set_strip_16(p->png_ptr); else if (bit_depth < 8) png_set_packing(p->png_ptr); // Make non-alpha RGB/Palette 32-bit and Gray 16-bit for easier handling if (!(color_type & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(p->png_ptr, 0xFF, PNG_FILLER_AFTER); } num_passes = png_set_interlace_handling(p->png_ptr); LOG_DEBUG("png bit_depth %d, color_type %d, channels %d, num_passes %d\n", bit_depth, color_type, i->channels, num_passes); png_read_update_info(p->png_ptr, p->info_ptr); image_alloc_pixbuf(i, i->width, i->height); ptr = (unsigned char *)malloc(png_get_rowbytes(p->png_ptr, p->info_ptr)); ofs = 0; if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Grayscale (Alpha) if (num_passes == 1) { // Non-interlaced for (y = 0; y < i->height; y++) { png_read_row(p->png_ptr, (unsigned char *)ptr, NULL); for (x = 0; x < i->width; x++) { i->_pixbuf[ofs++] = COL_FULL(ptr[x * 2], ptr[x * 2], ptr[x * 2], ptr[x * 2 + 1]); } } } else if (num_passes == 7) { // Interlaced image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 0, 8); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 4, 8); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 4, 8, 0, 4); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 4, 2, 4); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 2, 4, 0, 2); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 2, 1, 2); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 1, 2, 0, 1); } } else { // RGB(A) if (num_passes == 1) { // Non-interlaced for (y = 0; y < i->height; y++) { png_read_row(p->png_ptr, (unsigned char *)ptr, NULL); for (x = 0; x < i->width; x++) { i->_pixbuf[ofs++] = COL_FULL(ptr[x * 4], ptr[x * 4 + 1], ptr[x * 4 + 2], ptr[x * 4 + 3]); } } } else if (num_passes == 7) { // Interlaced // The first pass will return an image 1/8 as wide as the entire image // (every 8th column starting in column 0) // and 1/8 as high as the original (every 8th row starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 0, 8); // The second will be 1/8 as wide (starting in column 4) // and 1/8 as high (also starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 4, 8); // The third pass will be 1/4 as wide (every 4th pixel starting in column 0) // and 1/8 as high (every 8th row starting in row 4) image_png_interlace_pass(i, (unsigned char *)ptr, 4, 8, 0, 4); // The fourth pass will be 1/4 as wide and 1/4 as high // (every 4th column starting in column 2, and every 4th row starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 4, 2, 4); // The fifth pass will return an image 1/2 as wide, // and 1/4 as high (starting at column 0 and row 2) image_png_interlace_pass(i, (unsigned char *)ptr, 2, 4, 0, 2); // The sixth pass will be 1/2 as wide and 1/2 as high as the original // (starting in column 1 and row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 2, 1, 2); // The seventh pass will be as wide as the original, and 1/2 as high, // containing all of the odd numbered scanlines. image_png_interlace_pass(i, (unsigned char *)ptr, 1, 2, 0, 1); } else { FATAL("Unsupported PNG interlace type (%d passes)\n", num_passes); } } free((void *)ptr); // This is not required, so we can save some time by not reading post-image chunks //png_read_end(p->png_ptr, p->info_ptr); return 1; }
pngquant_error rwpng_read_image24_libpng(FILE *infile, png24_image *mainprog_ptr) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_size_t rowbytes; int color_type, bit_depth; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, rwpng_error_handler, NULL); if (!png_ptr) { return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } /* setjmp() must be called in every function that calls a non-trivial * libpng function */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return LIBPNG_FATAL_ERROR; /* fatal libpng error (via longjmp()) */ } struct rwpng_read_data read_data = {infile, 0}; png_set_read_fn(png_ptr, &read_data, user_read_data); png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ /* GRR TO DO: preserve all safe-to-copy ancillary PNG chunks */ if (!(color_type & PNG_COLOR_MASK_ALPHA)) { #ifdef PNG_READ_FILLER_SUPPORTED png_set_expand(png_ptr); png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER); #else fprintf(stderr, "pngquant readpng: image is neither RGBA nor GA\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 26; return mainprog_ptr->retval; #endif } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); */ if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* get and save the gamma info (if any) for writing */ double gamma; mainprog_ptr->gamma = png_get_gAMA(png_ptr, info_ptr, &gamma) ? gamma : 0.45455; png_set_interlace_handling(png_ptr); /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if ((mainprog_ptr->rgba_data = malloc(rowbytes*mainprog_ptr->height)) == NULL) { fprintf(stderr, "pngquant readpng: unable to allocate image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return PNG_OUT_OF_MEMORY_ERROR; } png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0); /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->file_size = read_data.bytes_read; mainprog_ptr->row_pointers = (unsigned char **)row_pointers; return SUCCESS; }
pdf_obj *start_png_image (FILE *file, char *res_name) { pdf_obj *result = NULL, *dict = NULL; png_structp png_ptr; png_infop info_ptr; unsigned long width, height; unsigned bit_depth, color_type; rewind (file); if (!(png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) || !(info_ptr = png_create_info_struct (png_ptr))) { fprintf (stderr, "\n\nLibpng failed to initialize\n"); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } png_init_io (png_ptr, file); /* png_set_sig_bytes (png_ptr, 0); */ /* Read PNG header */ png_read_info (png_ptr, info_ptr); { png_color_16 default_background; png_color_16p file_background; default_background.red=255; default_background.green=255; default_background.blue=255; default_background.gray=0; default_background.index = 0; width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* Convert paletted images to true color */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } /* Limit image component depth to 8 bits */ if (bit_depth == 16) { png_set_strip_16 (png_ptr); } if (png_get_bKGD(png_ptr, info_ptr, &file_background)) { png_set_background(png_ptr, file_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else { png_set_background(png_ptr, &default_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } } { /* Read the image in raw RGB format */ int i, rowbytes, pdf_bit_depth; png_bytep *rows; png_read_update_info(png_ptr, info_ptr); rows = NEW (height, png_bytep); rowbytes = png_get_rowbytes(png_ptr, info_ptr); rows[0] = NEW (rowbytes*height, png_byte); for (i=1; i<height; i++) { rows[i] = rows[0] + rowbytes * i; } png_read_image(png_ptr, rows); result = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(result); pdf_add_dict (dict, pdf_new_name ("Width"), pdf_new_number(width)); pdf_add_dict (dict, pdf_new_name ("Height"), pdf_new_number(height)); if (color_type == PNG_COLOR_TYPE_GRAY) { pdf_bit_depth = bit_depth; } else { pdf_bit_depth = 8; } pdf_add_dict (dict, pdf_new_name ("BitsPerComponent"), pdf_new_number(pdf_bit_depth)); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceGray")); } else{ pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceRGB")); } pdf_add_stream (result, (char *)rows[0], rowbytes*height); RELEASE (rows[0]); RELEASE (rows); } { /* Cleanup */ if (info_ptr) png_destroy_info_struct(png_ptr, &info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); } return result; }
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth_ == 16) png_set_strip_16(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY || color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); png_read_update_info(png_ptr, info_ptr); //START read image rows unsigned w=std::min(unsigned(image.width()),width_); unsigned h=std::min(unsigned(image.height()),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); boost::scoped_array<png_byte> row(new png_byte[rowbytes]); for (unsigned i=0;i<height_;++i) { png_read_row(png_ptr,row.get(),0); if (i>=y0 && i<h) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w); } } //END png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
int ImageFormatPNG::load(const char *name, int& width, int& height, int& format) { printf("ImageFormatPNG::load\n"); // Open File FILE* file = fopen(name,"rb"); if (file == 0) { printf("ImageFormatPNG::load(): can't open file '%s'\n",name); return 0; } // init width / height / format value to 0 width = 0; height = 0; format = 0; //Allocate a buffer of 8 bytes, where we can put the file signature. png_byte sig[8]; //Read the 8 bytes from the file into the sig buffer. fread((char*)sig, sizeof(png_byte), 8, file); if(!png_check_sig(sig,8)) { fclose(file); return 0; } //Here we create the png read struct. png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if(pngPtr == 0) { fclose(file); return 0; } //Here we create the png info struct. png_infop infoPtr = png_create_info_struct(pngPtr); if(infoPtr == 0) { png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); fclose(file); return 0; } png_set_read_fn(pngPtr,file, file_read_function); //Set the amount signature bytes we've already read: png_set_sig_bytes(pngPtr, 8); //Now call png_read_info with our pngPtr as image handle, and infoPtr to receive the file info. png_read_info(pngPtr, infoPtr); png_uint_32 imgWidth = png_get_image_width(pngPtr, infoPtr); png_uint_32 imgHeight = png_get_image_height(pngPtr, infoPtr); //bits per CHANNEL! note: not per pixel! png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr); //Number of channels png_uint_32 channels = png_get_channels(pngPtr, infoPtr); //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); //Don't forget to update the channel info (thanks Tom!) //It's used later to know how big a buffer we need for the image channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) png_set_expand_gray_1_2_4_to_8(pngPtr); //And the bitdepth info bitdepth = 8; break; } /*if the image has a transperancy set.. convert it to a full Alpha channel..*/ if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); channels+=1; } //We don't support 16 bit precision.. so if the image Has 16 bits per channel //precision... round it down to 8. if (bitdepth == 16) png_set_strip_16(pngPtr); //Array of row pointers. One for every row. png_bytep* rowPtrs = new png_bytep[imgHeight]; width = imgWidth; height = imgHeight; format = bitdepth * channels / 8; int data_decoded_size = width * height * format; // raw data image container unsigned char * img_data_decoded = new unsigned char[data_decoded_size]; memset(img_data_decoded,0x00,data_decoded_size + 1); int stride = width * format; for (size_t i = 0; i < imgHeight; i++) { //Set the pointer to the data pointer + i times the row stride. png_uint_32 q = (imgHeight- i - 1) * stride; rowPtrs[i] = (png_bytep)img_data_decoded + q; } //And here it is! The actuall reading of the image! png_read_image(pngPtr, rowPtrs); //Delete the row pointers array.... delete[] (png_bytep)rowPtrs; //And don't forget to clean up the read and info structs ! png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); // create temporary file for glue code javascript ImageFormat::flip_y((unsigned char *)img_data_decoded,width,height,format); FILE* raw = fopen(kTempararyName,"wb"); if (raw) { fwrite(img_data_decoded,width * height * format ,1 , raw); fclose(raw); } delete img_data_decoded; fclose(file); return 1; }