static int lload(lua_State *L) { int top = lua_gettop(L); FILE *fp; struct png_source source; if (top == 1) { const char *filename = luaL_checkstring(L,1); fp = fopen(filename, "rb"); if (fp == NULL) { return luaL_error(L, strerror(errno)); } unsigned char header[PNGSIGSIZE]; if (fread(header, 1, PNGSIGSIZE, fp) != PNGSIGSIZE) { return luaL_error(L, "png invalid"); } if (png_sig_cmp(header, 0, PNGSIGSIZE)) { return luaL_error(L, "png sig invalid"); } fseek(fp, 0, SEEK_SET); } else if (top == 2) { luaL_checktype(L,1,LUA_TLIGHTUSERDATA); void *data = lua_touserdata(L,1); size_t size = luaL_checkinteger(L,2); if (size < PNGSIGSIZE) { return luaL_error(L, "png invalid"); } if (png_sig_cmp(data, 0, PNGSIGSIZE)) { return luaL_error(L, "png sig invalid"); } source.data = data; source.size = size; source.offset = 0; } else { return luaL_error(L, "invalid argument number"); } png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; int step;//, type; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } if (top == 1) png_init_io(png_ptr, fp); else png_set_read_fn(png_ptr, (void *)&source, png_read_cb); //png_set_sig_bytes(png_ptr, PNGSIGSIZE); 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); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 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) != 0) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_GRAY: // type = TEXTURE_DEPTH; step = 1; break; case PNG_COLOR_TYPE_RGB: //type = TEXTURE_RGB; step = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: //type = TEXTURE_RGBA; step = 4; break; default: return luaL_error(L, "png color type %d not support", color_type); } png_bytep *row_pointers = (png_bytep *)malloc(height * sizeof(png_bytep)); png_size_t rowbytes = png_get_rowbytes(png_ptr,info_ptr); size_t bytes = rowbytes * height; uint8_t *buffer = (uint8_t *)malloc(bytes); int i; for (i=0; i<height; ++i) { row_pointers[i] = buffer + i*rowbytes; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(row_pointers); switch (color_type) { case PNG_COLOR_TYPE_GRAY: lua_pushliteral(L,"GRAY"); break; case PNG_COLOR_TYPE_RGB: lua_pushliteral(L,"RGB8"); break; case PNG_COLOR_TYPE_RGBA: lua_pushliteral(L,"RGBA8"); break; } lua_pushinteger(L,width); lua_pushinteger(L,height); int n = width * height * step; lua_createtable(L,n,0); for (i=0; i<n; ++i) { lua_pushinteger(L, buffer[i]); lua_rawseti(L, -2, i+1); } free(buffer); return 4; }
CDibSection* InformApp::GetImage(const char* path) { // Check if it's a PNG file CStdioFile imageFile; if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary)) return 0; png_byte fileHeader[8]; imageFile.Read(fileHeader,8); bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0); if (isPNG) { // Prepare to read the PNG file png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL); if (png_ptr == NULL) return 0; png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); return 0; } // Set up the point to return to in case of error png_bytep* rowPointers = NULL; if (setjmp(png_jmpbuf(png_ptr))) { if (rowPointers) delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return 0; } png_init_io(png_ptr,imageFile.m_pStream); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); // Get details of the image png_uint_32 width = png_get_image_width(png_ptr,info_ptr); png_uint_32 height = png_get_image_height(png_ptr,info_ptr); int bit_depth = png_get_bit_depth(png_ptr,info_ptr); int color_type = png_get_color_type(png_ptr,info_ptr); // Set up transforms to the required format if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 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); double gamma; if (png_get_gAMA(png_ptr,info_ptr,&gamma)) png_set_gamma(png_ptr,2.2,gamma); if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); png_set_filler(png_ptr,0xFF,PNG_FILLER_AFTER); // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return NULL; } // Read in the image rowPointers = new png_bytep[height]; for (int i = 0; i < (int)height; i++) rowPointers[i] = ((png_bytep)dib->GetBits())+(width*i*4); png_read_image(png_ptr,rowPointers); png_read_end(png_ptr,end_info); delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return dib; } else { imageFile.SeekToBegin(); struct jpeg_decompress_struct info; struct JPEGErrorInfo error; // Initialize the error handling info.err = jpeg_std_error(&(error.base)); error.base.error_exit = errorJPEGExit; error.base.output_message = outputJPEGMessage; if (setjmp(error.errorJump)) { jpeg_destroy_decompress(&info); return NULL; } // Set up the decompression jpeg_create_decompress(&info); jpeg_stdio_src(&info,imageFile.m_pStream); // Read the image attributes jpeg_read_header(&info,TRUE); jpeg_calc_output_dimensions(&info); int width = info.output_width; int height = info.output_height; // Force RGB output info.out_color_space = JCS_RGB; // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { jpeg_destroy_decompress(&info); return NULL; } // Get an output buffer JSAMPARRAY buffer = (*info.mem->alloc_sarray) ((j_common_ptr)&info,JPOOL_IMAGE,width*3,1); // Read in the image jpeg_start_decompress(&info); while ((int)info.output_scanline < height) { jpeg_read_scanlines(&info,buffer,1); BYTE* pixelRow = ((BYTE*)dib->GetBits())+(width*(info.output_scanline-1)*4); for (int i = 0; i < width; i++) { pixelRow[(i*4)+0] = (*buffer)[(i*3)+2]; pixelRow[(i*4)+1] = (*buffer)[(i*3)+1]; pixelRow[(i*4)+2] = (*buffer)[(i*3)+0]; pixelRow[(i*4)+3] = 0xFF; } } jpeg_finish_decompress(&info); jpeg_destroy_decompress(&info); return dib; } }
// PNG 형식의 로드 void CDIB::LoadPNGFile(wstring file_name) { unsigned int sig_read=0; int bit_depth, color_type, interlace_type; // 파일 열기 FILE* fp=_wfopen(file_name.c_str(), L"rb"); if (!fp) return; // png_struct 초기화 png_structp png_ptr=png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return; } png_init_io(png_ptr, fp); // png_info 초기화 png_infop info_ptr=png_create_info_struct(png_ptr); if (!info_ptr) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return; } // 화상정보 취득 png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (unsigned long*)&W, (unsigned long*)&H, &bit_depth, &color_type, &interlace_type, NULL, NULL); // DIB 초기화 InitDIB(); // 변환방법 설정 // Palette를 RGB로 if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); // 투명색을 Alpha로 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // Bit depth를 8bit로 if (bit_depth<8) png_set_packing(png_ptr); else if (bit_depth==16) png_set_strip_16(png_ptr); // 24bit(RGB)를 32bit(RGB0)로 if (color_type==PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); // RGB를 BGR로 if (color_type==PNG_COLOR_TYPE_PALETTE || color_type==PNG_COLOR_TYPE_RGB || color_type==PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // 화상 읽기 png_bytep *row_pointers=new png_bytep[H]; for (int row=0; row<H; row++) row_pointers[row]=(png_bytep)(Pixel+row*W); png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); delete [] row_pointers; // 뒷처리 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); // Alpha 값을 얻는다 DWORD* p=Pixel; BYTE* a=Alpha; for (int y=0; y<H; y++) { for (int x=0; x<W; x++, p++, a++) { *a=(BYTE)(*p>>24); *p&=0x00ffffff; } } // Region 초기화 InitRgn(); }
int res_create_surface(const char* name, gr_surface* pSurface) { char resPath[256]; GGLSurface* surface = NULL; int result = 0; unsigned char header[8]; png_structp png_ptr = NULL; png_infop info_ptr = NULL; *pSurface = NULL; snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; FILE* fp = fopen(resPath, "rb"); if (fp == NULL) { result = -1; goto exit; } size_t bytesRead = fread(header, 1, sizeof(header), fp); if (bytesRead != sizeof(header)) { result = -2; goto exit; } if (png_sig_cmp(header, 0, sizeof(header))) { result = -3; goto exit; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { result = -4; goto exit; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { result = -5; goto exit; } if (setjmp(png_jmpbuf(png_ptr))) { result = -6; goto exit; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, sizeof(header)); png_read_info(png_ptr, info_ptr); int color_type, bit_depth; size_t width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); png_byte channels = png_get_channels(png_ptr, info_ptr); if (!(bit_depth == 8 && ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY))))) { return -7; goto exit; } size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; size_t pixelSize = stride * height; surface = malloc(sizeof(GGLSurface) + pixelSize); if (surface == NULL) { result = -8; goto exit; } unsigned char* pData = (unsigned char*) (surface + 1); surface->version = sizeof(GGLSurface); surface->width = width; surface->height = height; surface->stride = width; /* Yes, pixels, not bytes */ surface->data = pData; surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8)); int alpha = 0; if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); alpha = 1; } if (color_type == PNG_COLOR_TYPE_GRAY) { alpha = 1; } unsigned int y; if (channels == 3 || (channels == 1 && !alpha)) { for (y = 0; y < height; ++y) { unsigned char* pRow = pData + y * stride; png_read_row(png_ptr, pRow, NULL); int x; for(x = width - 1; x >= 0; x--) { int sx = x * 3; int dx = x * 4; unsigned char r = pRow[sx]; unsigned char g = pRow[sx + 1]; unsigned char b = pRow[sx + 2]; unsigned char a = 0xff; pRow[dx ] = r; // r pRow[dx + 1] = g; // g pRow[dx + 2] = b; // b pRow[dx + 3] = a; } } } else { for (y = 0; y < height; ++y) { unsigned char* pRow = pData + y * stride; png_read_row(png_ptr, pRow, NULL); } } *pSurface = (gr_surface) surface; exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp != NULL) { fclose(fp); } if (result < 0) { if (surface) { free(surface); } } return result; }
int simpl_gray_load_png(SimplGrayImage **image, SimplInStream istream, const SimplColorToGrayMethods method, const SimplPixel bk_value) { png_structp png_ptr; png_infop info_ptr; png_byte color_type, bitdepth, *row_data=NULL; png_bytep* row_ptrs=NULL; png_uint_32 i, j, x, width, height, row_size; SimplColorPixel *pixels=NULL; SimplPixel *iptr, *alpha=NULL; int value, out = SIMPL_INTERNAL; /* Create a read struct. */ if (!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) { return SIMPL_INTERNAL; } /* Create an info struct. */ if (!(info_ptr = png_create_info_struct(png_ptr))) { goto error; } /* Handle libpng errors with a magic setjmp. */ if (setjmp(png_jmpbuf(png_ptr))) { goto error; } /* Set the stream-based data source. */ png_set_read_fn(png_ptr, istream, StreamReadData); /* Read the info chunk. */ png_read_info(png_ptr, info_ptr); /* Get the dimensions and color information. */ width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); bitdepth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); /* If palette, low bit depth gray, transparent w/o alpha, or 16 bit, fix it. */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } else if (color_type == PNG_COLOR_TYPE_GRAY) { if (bitdepth<8) png_set_expand_gray_1_2_4_to_8(png_ptr); bitdepth = 8; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } png_set_strip_16(png_ptr); /* Either allocate a row, or load the entire image into a buffer. This is * because single row access uses less memory but doesn't work for * interlaced PNGs. */ row_size = png_get_rowbytes(png_ptr, info_ptr); if (png_get_interlace_type(png_ptr, info_ptr)==PNG_INTERLACE_NONE) { row_data = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_data) { out = SIMPL_NOMEM; goto error; } } else { row_ptrs = (png_bytep*)calloc(height, sizeof(png_bytep)); if (!row_ptrs) { out = SIMPL_NOMEM; goto error; } for (j=0; j<height; ++j) { row_ptrs[j] = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_ptrs[j]) { out = SIMPL_NOMEM; goto error; } } png_read_image(png_ptr, row_ptrs); } /* Allocate an image of the specified size. */ out = simpl_gray(image, width, height); if (out != SIMPL_OK) goto error; /* Decode the image line by line. */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { pixels = (SimplColorPixel *)malloc(sizeof(SimplColorPixel) * width); if (!pixels) { out = SIMPL_NOMEM; goto error; } alpha = (SimplPixel *)malloc(sizeof(SimplPixel) * width); if (!alpha) { out = SIMPL_NOMEM; goto error; } memset(alpha, 255, width); for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; if (color_type==PNG_COLOR_TYPE_RGB) { for (x=i=0; x<width; ++x, i+=3) { pixels[x].red = row_data[i]; pixels[x].green = row_data[i+1]; pixels[x].blue = row_data[i+2]; } } else { for (x=i=0; x<width; ++x, i+=4) { pixels[x].red = row_data[i]; pixels[x].green = row_data[i+1]; pixels[x].blue = row_data[i+2]; alpha[x] = row_data[i+3]; } } switch(method) { case COLOR_TO_GRAY_RED: for (i=0; i<width; ++i) iptr[i] = pixels[i].red; break; case COLOR_TO_GRAY_GREEN: for (i=0; i<width; ++i) iptr[i] = pixels[i].green; break; case COLOR_TO_GRAY_BLUE: for (i=0; i<width; ++i) iptr[i] = pixels[i].blue; break; case COLOR_TO_GRAY_ALPHA: for (i=0; i<width; ++i) iptr[i] = alpha[i]; break; case COLOR_TO_GRAY_CIE: if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) { for (i=0; i<width; ++i) { value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15; value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255; iptr[i] = (value>255)?255:value; } } else { for (i=0; i<width; ++i) { value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15; iptr[i] = (value>255)?255:value; } } break; case COLOR_TO_GRAY_MEAN: default: if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) { for (i=0; i<width; ++i) { value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3; value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255; iptr[i] = (value>255)?255:value; } } else { for (i=0; i<width; ++i) { value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3; iptr[i] = (value>255)?255:value; } } break; } }
void PNGImage::loadImage() { FILE* file_descriptor = nullptr; png_byte header[8]; png_structp png_ptr = nullptr; png_infop info_ptr = nullptr; png_byte* image_buffer = nullptr; png_bytep* row_ptrs = nullptr; png_int_32 row_size = 0; bool transparency = false; int error_code = 0; size_t header_size = sizeof(header); file_descriptor = std::fopen(m_filename, "rb"); if (file_descriptor == nullptr) { error_code = 10; goto ERROR_PNG; } if (header_size != std::fread(header, 1, header_size, file_descriptor)) { error_code = 11; goto ERROR_PNG; } if (png_sig_cmp(header, 0, 8) != 0) { error_code = 3; goto ERROR_PNG; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { error_code = 4; goto ERROR_PNG; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr) { error_code = 5; goto ERROR_PNG; } png_set_read_fn(png_ptr, file_descriptor, callback_read_file); { int jump_code = 0; if ( (jump_code = setjmp(png_jmpbuf(png_ptr))) != 0) { ERR("PNGImage: setjump() returned code %i", jump_code); error_code = 6; goto ERROR_PNG; } } png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_int_32 depth, color_type; png_uint_32 width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &depth, &color_type, nullptr, nullptr, nullptr); m_width = width; m_height = height; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); transparency = true; } if (depth < 8) { png_set_packing(png_ptr); } else { png_set_strip_16(png_ptr); } switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8(png_ptr); break; case PNG_COLOR_TYPE_GA: png_set_expand_gray_1_2_4_to_8(png_ptr); break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGBA: default: break; } png_read_update_info(png_ptr, info_ptr); row_size = png_get_rowbytes(png_ptr, info_ptr); m_size = row_size * height; if (row_size <= 0) { error_code = 7; goto ERROR_PNG; } image_buffer = new (std::nothrow) png_byte[m_size]; if (image_buffer == nullptr) { error_code = 8; goto ERROR_PNG; } row_ptrs = new (std::nothrow) png_bytep[height]; if (row_ptrs == nullptr) { error_code = 9; goto ERROR_PNG; } for (int32_t i = 0; i < height; ++i) { row_ptrs[height - (i + 1)] = image_buffer + i * row_size; } png_read_image(png_ptr, row_ptrs); std::fclose(file_descriptor); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); delete [] row_ptrs; m_buffer = image_buffer; return; ERROR_PNG: m_error_code = error_code; ERR("Error while reading PNG file: %s, code %i", m_filename, m_error_code); std::fclose(file_descriptor); delete [] image_buffer; image_buffer = nullptr; delete [] row_ptrs; row_ptrs = nullptr; if (png_ptr != nullptr) { png_infop* info_ptr_p = info_ptr != nullptr ? &info_ptr : nullptr; png_destroy_read_struct(&png_ptr, info_ptr_p, nullptr); } }
/* For little endian systems, ARGB is equivalent to the int32 BGRA. * So, to read the image as RGB */ static SLang_Array_Type *read_image_internal (char *file, int flip, int *color_typep) { Png_Type *p; png_uint_32 width, height, rowbytes; png_struct *png; png_info *info; int bit_depth; int interlace_type; int color_type; unsigned int sizeof_type; SLindex_Type dims[2]; SLtype data_type; png_byte **image_pointers = NULL; png_byte *data = NULL; SLang_Array_Type *at; void (*fixup_array_fun) (SLang_Array_Type *); if (NULL == (p = open_png_file (file))) return NULL; png = p->png; if (setjmp (png_jmpbuf (png))) { free_png_type (p); if (data != NULL) SLfree ((char *) data); free_image_pointers (image_pointers); SLang_verror (SL_Read_Error, "Error encountered during I/O to %s", file); return NULL; } png_init_io (png, p->fp); png_set_sig_bytes (png, 8); info = p->info; png_read_info(png, info); width = png_get_image_width (png, info); height = png_get_image_height (png, info); interlace_type = png_get_interlace_type (png, info); bit_depth = png_get_bit_depth (png, info); if (bit_depth == 16) png_set_strip_16 (png); switch (png_get_color_type (png, info)) { case PNG_COLOR_TYPE_GRAY: #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10209) if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8 (png); #else /* deprecated */ if (bit_depth < 8) png_set_gray_1_2_4_to_8 (png); #endif break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* png_set_gray_to_rgb (png); */ break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb (png); break; } if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); png_read_update_info (png, info); color_type = png_get_color_type (png, info); switch (color_type) { case PNG_COLOR_TYPE_RGBA: sizeof_type = 4; fixup_array_fun = fixup_array_rgba; data_type = SLang_get_int_type (32); break; case PNG_COLOR_TYPE_RGB: sizeof_type = 4; fixup_array_fun = fixup_array_rgb; data_type = SLang_get_int_type (32); break; case PNG_COLOR_TYPE_GRAY_ALPHA: sizeof_type = 2; fixup_array_fun = fixup_array_ga; data_type = SLang_get_int_type (16); break; case PNG_COLOR_TYPE_GRAY: sizeof_type = 1; fixup_array_fun = NULL; data_type = SLANG_UCHAR_TYPE; break; default: SLang_verror (SL_Read_Error, "Unsupported PNG color-type"); free_png_type (p); return NULL; } *color_typep = color_type; /* Use the high-level interface */ rowbytes = png_get_rowbytes (png, info); if (rowbytes > width * sizeof_type) { SLang_verror (SL_INTERNAL_ERROR, "Unexpected value returned from png_get_rowbytes"); free_png_type (p); return NULL; } if (NULL == (data = (png_byte *) SLmalloc (height * width * sizeof_type))) { free_png_type (p); return NULL; } if (NULL == (image_pointers = allocate_image_pointers (height, data, width * sizeof_type, flip))) { SLfree ((char *) data); free_png_type (p); return NULL; } png_read_image(png, image_pointers); dims[0] = height; dims[1] = width; if (NULL == (at = SLang_create_array (data_type, 0, (VOID_STAR) data, dims, 2))) { SLfree ((char *) data); free_image_pointers (image_pointers); free_png_type (p); return NULL; } free_png_type (p); free_image_pointers (image_pointers); if (fixup_array_fun != NULL) (*fixup_array_fun) (at); return at; }
static void * do_png_read(struct png_reader * reader, void *(*alloc)(int w, int h, int bpp, void** datap)) { png_structp read_ptr; png_infop info_ptr; TRACE(SYSTEM, "ready to read png stream\n"); if (reader->read_ptr == NULL) { reader->info_ptr = NULL; read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error, png_warning); reader->read_ptr = read_ptr; } else { read_ptr = reader->read_ptr; reader->read_ptr_save = read_ptr; } if (read_ptr == NULL) { ERROR(SYSTEM, "libpng: create read_ptr error\n"); THROW(EXCEPTION_CONTINUE, "libpng read error"); } if (setjmp(png_jmpbuf(read_ptr))) { ERROR(SYSTEM, "libpng: read error\n"); THROW(EXCEPTION_RESOURCE_LOST, "libpng read error"); } if (reader->info_ptr == NULL) { info_ptr = png_create_info_struct(read_ptr); reader->info_ptr = info_ptr; } else { info_ptr = reader->info_ptr; } png_set_read_fn(read_ptr, reader->io_ptr, reader->read_fn); /* here: begin read */ /* code borrowed from SDL_img's IMG_png.c */ png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_read_info(read_ptr, info_ptr); png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); TRACE(SYSTEM, "png bitmap: %dx%d:%d\n", width, height, bit_depth); if (bit_depth > 8) png_set_strip_16(read_ptr); if (bit_depth < 8) png_set_packing(read_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_GRAY\n"); png_set_expand(read_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_GRAY_ALPHA\n"); png_set_gray_to_rgb(read_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) { TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_PALETTE\n"); png_set_palette_to_rgb(read_ptr); } if (png_get_valid(read_ptr, info_ptr, PNG_INFO_tRNS)) { TRACE(SYSTEM, "\tstream has PNG_INFO_tRNS\n"); png_set_tRNS_to_alpha(read_ptr); } png_read_update_info(read_ptr, info_ptr); png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); TRACE(SYSTEM, "update png bitmap: %dx%d:%d\n", width, height, bit_depth); /* start read */ if (bit_depth != 8) { WARNING(RESOURCE, "We don't support this png stream\n"); THROW(EXCEPTION_RESOURCE_LOST, "format error"); } int bytes_pp; switch (color_type) { case PNG_COLOR_TYPE_GRAY: TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_GRAY\n"); bytes_pp = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_GRAY_ALPHA\n"); bytes_pp = 2; break; case PNG_COLOR_TYPE_RGB: TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_RGB\n"); bytes_pp = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: TRACE(SYSTEM, "\tcolor type: PNG_COLOR_TYPE_RGB_ALPHA\n"); bytes_pp = 4; break; case PNG_COLOR_TYPE_PALETTE: WARNING(SYSTEM, "PNG_COLOR_TYPE_PALETTE:" " I don't know how to read PALETTE png stream...\n"); if (png_get_valid(read_ptr, info_ptr, PNG_INFO_tRNS)) bytes_pp = 3; else bytes_pp = 4; break; default: WARNING(RESOURCE, "We don't support this png stream\n"); THROW(EXCEPTION_RESOURCE_LOST, "format error"); }; /* alloc data */ void * retval = NULL; void * data = NULL; retval = alloc(width, height, bytes_pp, &data); assert(retval != NULL); assert(data != NULL); /* start read!! */ VERBOSE(SYSTEM, "png stream read start\n"); png_bytep *volatile row_pointers; int row; #ifdef HAVE_ALLOCA row_pointers = (png_bytep*)alloca(sizeof(png_bytep)*height); #else row_pointers = (png_bytep*)xmalloc(sizeof(png_bytep)*height); reader->row_pointers = row_pointers; #endif assert(row_pointers != NULL); for (row = 0; row < (int)height; row++) { row_pointers[row] = (png_bytep)( (uint8_t*)(data + ((int)height-row) * bytes_pp * width)); } png_read_image(read_ptr, row_pointers); #ifndef HAVE_ALLOCA GC_FREE_BLOCK_SET(row_pointers); reader->row_pointers = NULL; #endif return retval; }
ImageData PNGImageCodec::Load(InputStreamPtr& file, const ImageParams& params, ImageCodecMetaInfo& metaInfo) { InputStream* readr = file.GetPtr(); // check if png_ptr if (!CheckIfPng(readr)) { Warn(String("Image file format is not png: ") + params.name); } png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type; bool alpha; Color32 keycolor; int keycolor_index = -1; bool hascolorkey = false; ImageType imagetype; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png_ptr == NULL) { Error("Could not create read struct"); NEX_THROW_GracefulError(EXCEPT_INVALID_CALL); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); Error("Could not create info struct"); NEX_THROW_GracefulError(EXCEPT_INVALID_CALL); } png_set_error_fn(png_ptr, (void *) (readr), PngWarn, PngWarn); png_set_read_fn(png_ptr, (void *) (readr), PngReadFile); png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, NULL, NULL); // todo Unstrip png_set_strip_16(png_ptr); if (bit_depth != 8 && bit_depth != 16) { Error("Unsupported bit depth"); NEX_THROW_GracefulError(EXCEPT_INVALID_CALL); } switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: if (color_type & PNG_COLOR_MASK_ALPHA) imagetype = GrayAlpha; else { imagetype = Palleted; png_set_strip_alpha(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_color_16p trans_values; png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_values); hascolorkey = true; keycolor.red = uint8(trans_values->gray) & 0xff; keycolor.green = uint8(trans_values->gray) & 0xff; keycolor.blue = uint8(trans_values->gray) & 0xff; keycolor.alpha = uint8(trans_values->gray) & 0xff; } } break; case PNG_COLOR_TYPE_PALETTE: imagetype = Palleted; alpha = true; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // tRNS chunk. Every palette entry gets its own alpha value. png_bytep trans; int num_trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0); // see if there is a single entry w/ alpha==0 and all other 255. // if yes use keycolor transparency. bool only_binary_trans = true; for (int32 i = 0; (i < num_trans) && only_binary_trans; i++) { if (trans[i] != 0xff) { only_binary_trans = only_binary_trans && (trans[i] == 0) && (keycolor_index == -1); keycolor_index = i; } } if (!only_binary_trans) { keycolor_index = -1; png_set_palette_to_rgb(png_ptr); png_set_tRNS_to_alpha(png_ptr); imagetype = RGBImage; } else alpha = false; } else alpha = false; break; case PNG_COLOR_TYPE_RGBA: alpha = true; case PNG_COLOR_TYPE_RGB: imagetype = RGBImage; if (!(color_type & PNG_COLOR_MASK_ALPHA)) { alpha = false; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_color_16p trans_values; png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_values); hascolorkey = true; keycolor.red = uint8((trans_values->red) & 0xff); keycolor.green = uint8((trans_values->green) & 0xff); keycolor.blue = uint8((trans_values->blue) & 0xff); } } break; } // setup gamma //@ TODO: add code to retrieve the gamma here double screen_gamma = 0; //X_SharedPtr(iSystem)->getUserGamma(); // and comment this screen_gamma = 2.2; int intent; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } /* todo Unstrip this */ if (bit_depth > 8) { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } else if (bit_depth < 8) // Expand pictures with less than 8bpp to 8bpp png_set_packing(png_ptr); // update png_read_update_info(png_ptr, info_ptr); png_uint_32 bytes_per_row = (png_uint_32)png_get_rowbytes(png_ptr, info_ptr); //png_read_image PixelFormat fmt; uint32 bpp = 1; // we dont support anything else // other than RGBImage right now // so! if (imagetype == RGBImage) { fmt = PixelFormat::RGBA8; bpp = 4; } else if (imagetype == GrayAlpha && bytes_per_row == 1) fmt = PixelFormat::R8; else { // pallete // cant handle this Warn(String("PixelFormat not supported.") + params.name); NEX_THROW_GracefulError(EXCEPT_INVALID_CALL); } int numPass = png_set_interlace_handling(png_ptr); ImageData img; uint8* imgDest = (uint8*) NEX_ALLOC(bpp * height * width, MEMCAT_GENERAL); img.data = imgDest; img.format = fmt; metaInfo.metaInfoInited = true; metaInfo.mipLevelsToRead = 0; metaInfo.metaInfo.maxDepth = img.depth = 1; metaInfo.metaInfo.maxHeight = img.height = (uint16) height; metaInfo.metaInfo.maxWidth = img.width = (uint16) width; metaInfo.metaInfo.maxMipMapCount = img.numMipMaps = 1; img.numFaces = 1; uint8* imgRows = 0; if (numPass > 1) { imgRows = (uint8*) NEX_ALLOC(bytes_per_row * height, MEMCAT_GENERAL); } else imgRows = (uint8*) NEX_ALLOC(bytes_per_row, MEMCAT_GENERAL); uint32 srcBpp = bytes_per_row / width; for (uint32 i = 0; (int32) i < numPass; ++i) { for (uint32 y = 0; y < height; y++) { uint8* rowPtr = numPass > 1 ? imgRows + bytes_per_row * y : imgRows; png_read_row(png_ptr, rowPtr, NULL); // write only once if (i == numPass - 1) { for (uint32 x = 0; x < width; x++) { // bgra switch (fmt) { case PixelFormat::RGBA8: imgDest[0] = rowPtr[0]; imgDest[1] = rowPtr[1]; imgDest[2] = rowPtr[2]; if (alpha) imgDest[3] = rowPtr[3]; else imgDest[3] = 0xff; break; case PixelFormat::R8: imgDest[0] = rowPtr[0]; break; } imgDest += bpp; rowPtr += srcBpp; } } } } png_read_end(png_ptr, (png_infop) 0); png_destroy_read_struct(&png_ptr, NULL, NULL); NEX_FREE(imgRows, MEMCAT_GENERAL); if (hascolorkey) { imgDest = (uint8*) img.data; for (uint32 y = 0; y < height; y++) { for (uint32 x = 0; x < width; x++) { switch (fmt) { case PixelFormat::RGBA8: if (imgDest[0] == keycolor.red && imgDest[1] == keycolor.green && imgDest[2] == keycolor.blue) imgDest[3] = 0; break; case PixelFormat::R8: if (imgDest[0] == keycolor.alpha) imgDest[0] = 0; break; } imgDest += bpp; } } } return img; }
/* Read a png header. */ static int png2vips_header( Read *read, VipsImage *out ) { png_uint_32 width, height; int bit_depth, color_type; int interlace_type; png_uint_32 res_x, res_y; int unit_type; png_charp name; int compression_type; /* Well thank you, libpng. */ #if PNG_LIBPNG_VER < 10400 png_charp profile; #else png_bytep profile; #endif png_uint_32 proflen; int bands; VipsInterpretation interpretation; double Xres, Yres; if( setjmp( png_jmpbuf( read->pPng ) ) ) return( -1 ); png_get_IHDR( read->pPng, read->pInfo, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); /* png_get_channels() gives us 1 band for palette images ... so look * at colour_type for output bands. * * Ignore alpha, we detect that separately below. */ switch( color_type ) { case PNG_COLOR_TYPE_PALETTE: bands = 3; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_GRAY: bands = 1; break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: bands = 3; break; default: vips_error( "png2vips", "%s", _( "unsupported color type" ) ); return( -1 ); } if( bit_depth > 8 ) { if( bands < 3 ) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_RGB16; } else { if( bands < 3 ) interpretation = VIPS_INTERPRETATION_B_W; else interpretation = VIPS_INTERPRETATION_sRGB; } /* Expand palette images. */ if( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( read->pPng ); /* Expand transparency. */ if( png_get_valid( read->pPng, read->pInfo, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( read->pPng ); bands += 1; } else if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) { /* Some images have no transparency chunk, but still set * color_type to alpha. */ bands += 1; } /* Expand <8 bit images to full bytes. */ if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) png_set_expand_gray_1_2_4_to_8( read->pPng ); /* If we're an INTEL byte order machine and this is 16bits, we need * to swap bytes. */ if( bit_depth > 8 && !vips_amiMSBfirst() ) png_set_swap( read->pPng ); /* Get resolution. Default to 72 pixels per inch, the usual png value. */ unit_type = PNG_RESOLUTION_METER; res_x = (72 / 2.54 * 100); res_y = (72 / 2.54 * 100); png_get_pHYs( read->pPng, read->pInfo, &res_x, &res_y, &unit_type ); switch( unit_type ) { case PNG_RESOLUTION_METER: Xres = res_x / 1000.0; Yres = res_y / 1000.0; break; default: Xres = res_x; Yres = res_y; break; } /* Set VIPS header. */ vips_image_init_fields( out, width, height, bands, bit_depth > 8 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, interpretation, Xres, Yres ); /* Sequential mode needs thinstrip to work with things like * vips_shrink(). */ vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); /* Fetch the ICC profile. @name is useless, something like "icc" or * "ICC Profile" etc. Ignore it. * * @profile was png_charpp in libpngs < 1.5, png_bytepp is the * modern one. Ignore the warning, if any. */ if( png_get_iCCP( read->pPng, read->pInfo, &name, &compression_type, &profile, &proflen ) ) { void *profile_copy; #ifdef DEBUG printf( "png2vips_header: attaching %zd bytes of ICC profile\n", proflen ); printf( "png2vips_header: name = \"%s\"\n", name ); #endif /*DEBUG*/ if( !(profile_copy = vips_malloc( NULL, proflen )) ) return( -1 ); memcpy( profile_copy, profile, proflen ); vips_image_set_blob( out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_free, profile_copy, proflen ); } /* Sanity-check line size. */ png_read_update_info( read->pPng, read->pInfo ); if( png_get_rowbytes( read->pPng, read->pInfo ) != VIPS_IMAGE_SIZEOF_LINE( out ) ) { vips_error( "vipspng", "%s", _( "unable to read PNG header" ) ); return( -1 ); } return( 0 ); }
/** 从本地磁盘中加载图像 @Param 图像文件的路径 */ F3DImage* F3DPNGCodec::Load( const char* filename ) { F3DImage* image; // 打开指定的文件 FVFile file; if( !file.Open(filename,FVFile::VFILE_OPENEXIST) ) { FLOG_WARNINGF( "F3DPNGCodec::Load, Open the image file (%s) failed!",filename ); return NULL; } FBYTE** row_pointers; png_byte buffer[8]; // 判断是否为一个正确的PNG文件 if( file.Read(buffer,8) != 8 || !png_sig_cmp(buffer,0,8) ) { FLOG_WARNINGF( "F3DPNGCodec::Load, Invalid PNG format! (%s)",filename ); return NULL; } // 创建一个PNG读取对象 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL ); // 创建一个PNG信息结构体 png_infop info_ptr = png_create_info_struct( png_ptr ); if( setjmp(png_jmpbuf(png_ptr)) ) { png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); if( row_pointers ) delete[] row_pointers; FLOG_ERROR("F3DPNGCodec::Load, An error occurs when reading..."); return NULL; } // 设置读取数据的回调函数 png_set_read_fn( png_ptr,&file,PNGReadFunc ); // 告诉PNG我们已经读取过文件标识 png_set_sig_bytes( png_ptr,8 ); // 读取PNG文件的信息 png_read_info( png_ptr,info_ptr ); png_uint_32 width,height; int bitDepth,colorType; png_get_IHDR( png_ptr,info_ptr,&width,&height,&bitDepth,&colorType,NULL,NULL,NULL ); // 如果是调色板图像则将其转换为真彩色 if( colorType == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( bitDepth < 8 ) { if ( colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_1_2_4_to_8( png_ptr ); else png_set_packing( png_ptr ); } if( png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS) ) png_set_tRNS_to_alpha( png_ptr ); if( bitDepth == 16 ) png_set_strip_16( png_ptr ); // 将灰色转换为真彩色 if( colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png_ptr ); // 更新信息的改变 png_read_update_info( png_ptr,info_ptr ); // 将RGBA格式转换为BGRA if( colorType == PNG_COLOR_TYPE_RGB_ALPHA ) png_set_bgr( png_ptr ); png_get_IHDR( png_ptr,info_ptr,&width,&height,&bitDepth,&colorType,NULL,NULL,NULL ); // 创建图像对象 if( colorType == PNG_COLOR_TYPE_RGB_ALPHA ) image = new F3DImage( width,height,PFT_A8R8G8B8 ); else image = new F3DImage( width,height,PFT_R8G8B8 ); row_pointers = new png_bytep[height]; FBYTE* imageData = image->GetImageData(); for( size_t i=0;i<height;i++ ) { row_pointers[i] = imageData; imageData += F3D_PixelSize(image->GetPixelFormat()) * image->GetWidth(); } if( setjmp(png_jmpbuf(png_ptr)) ) { png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); delete image; delete[] row_pointers; FLOG_ERROR("F3DPNGCodec::Load, An error occurs when reading..."); return NULL; } // 读取像素数据 png_read_image( png_ptr,row_pointers ); png_read_end( png_ptr,NULL ); png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); delete[] row_pointers; file.Close(); return image; }
bool loadPngFile( IMAGE_T* image, FILE *file) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, 0, 0); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, 0); return false; } //--------------------------------------------------------------------- png_init_io(png_ptr, file); png_read_info(png_ptr, info_ptr); //--------------------------------------------------------------------- png_byte colour_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888; if (colour_type & PNG_COLOR_MASK_ALPHA) { type = VC_IMAGE_RGBA32; } initImage(image, type, png_get_image_width(png_ptr, info_ptr), png_get_image_height(png_ptr, info_ptr), false); //--------------------------------------------------------------------- double gamma = 0.0; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { png_set_gamma(png_ptr, 2.2, gamma); } //--------------------------------------------------------------------- if (colour_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if ((colour_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 (bit_depth == 16) { #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif } if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } //--------------------------------------------------------------------- png_read_update_info(png_ptr, info_ptr); //--------------------------------------------------------------------- png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); png_uint_32 j = 0; for (j = 0 ; j < image->height ; ++j) { row_pointers[j] = image->buffer + (j * image->pitch); } //--------------------------------------------------------------------- png_read_image(png_ptr, row_pointers); //--------------------------------------------------------------------- free(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, 0); return true; }
Image* Image::_loadPng(hsbase& stream, int size) { png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop infoPtr = png_create_info_struct(pngPtr); png_infop endInfo = png_create_info_struct(pngPtr); setjmp(png_jmpbuf(pngPtr)); png_set_read_fn(pngPtr, &stream, &_pngZipRead); png_read_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, NULL, NULL, NULL, NULL, NULL, NULL, NULL); png_set_interlace_handling(pngPtr); int bpp = pngPtr->channels; if (pngPtr->color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(pngPtr); bpp = 3; } if (pngPtr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bpp > 1) { png_set_strip_alpha(pngPtr); bpp -= 1; } if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); ++bpp; } if (pngPtr->bit_depth == 16) { png_set_strip_16(pngPtr); } png_read_update_info(pngPtr, infoPtr); int rowBytes = png_get_rowbytes(pngPtr, infoPtr); png_byte* imageData = new png_byte[rowBytes * pngPtr->height]; png_bytep* rowPointers = new png_bytep[pngPtr->height]; for_itert (unsigned int, i, 0, pngPtr->height) { rowPointers[i] = imageData + i * rowBytes; } png_read_image(pngPtr, rowPointers); png_read_end(pngPtr, infoPtr); // assign Image data Image* image = new Image(); image->data = (unsigned char*)imageData; image->w = pngPtr->width; image->h = pngPtr->height; switch (bpp) { case 4: image->format = FORMAT_RGBA; break; case 3: image->format = FORMAT_RGB; break; case 1: image->format = FORMAT_ALPHA; break; default: image->format = FORMAT_RGBA; // TODOaa - maybe palette should go here break; } // clean up png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo); delete [] rowPointers; return image; }
/** Configure the decoder so that decoded pixels are compatible with a FREE_IMAGE_TYPE format. Set conversion instructions as needed. @param png_ptr PNG handle @param info_ptr PNG info handle @param flags Decoder flags @param output_image_type Returned FreeImage converted image type @return Returns TRUE if successful, returns FALSE otherwise @see png_read_update_info */ static BOOL ConfigureDecoder(png_structp png_ptr, png_infop info_ptr, int flags, FREE_IMAGE_TYPE *output_image_type) { // get original image info const int color_type = png_get_color_type(png_ptr, info_ptr); const int bit_depth = png_get_bit_depth(png_ptr, info_ptr); const int pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); FREE_IMAGE_TYPE image_type = FIT_BITMAP; // assume standard image type // check for transparency table or single transparent color BOOL bIsTransparent = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == PNG_INFO_tRNS ? TRUE : FALSE; // check allowed combinations of colour type and bit depth // then get converted FreeImage type switch(color_type) { case PNG_COLOR_TYPE_GRAY: // color type '0', bitdepth = 1, 2, 4, 8, 16 switch(bit_depth) { case 1: case 2: case 4: case 8: // expand grayscale images to the full 8-bit from 2-bit/pixel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); } // if a tRNS chunk is provided, we must also expand the grayscale data to 8-bits, // this allows us to make use of the transparency table with existing FreeImage methods if (bIsTransparent && (pixel_depth < 8)) { png_set_expand_gray_1_2_4_to_8(png_ptr); } break; case 16: image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN; // 16-bit grayscale images can contain a transparent value (shade) // if found, expand the transparent value to a full alpha channel if (bIsTransparent && (image_type != FIT_UNKNOWN)) { // expand tRNS to a full alpha channel png_set_tRNS_to_alpha(png_ptr); // expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA png_set_gray_to_rgb(png_ptr); image_type = FIT_RGBA16; } break; default: image_type = FIT_UNKNOWN; break; } break; case PNG_COLOR_TYPE_RGB: // color type '2', bitdepth = 8, 16 switch(bit_depth) { case 8: image_type = (pixel_depth == 24) ? FIT_BITMAP : FIT_UNKNOWN; break; case 16: image_type = (pixel_depth == 48) ? FIT_RGB16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } // sometimes, 24- or 48-bit images may contain transparency information // check for this use case and convert to an alpha-compatible format if (bIsTransparent && (image_type != FIT_UNKNOWN)) { // if the image is 24-bit RGB, mark it as 32-bit; if it is 48-bit, mark it as 64-bit image_type = (pixel_depth == 24) ? FIT_BITMAP : (pixel_depth == 48) ? FIT_RGBA16 : FIT_UNKNOWN; // expand tRNS chunk to alpha channel png_set_tRNS_to_alpha(png_ptr); } break; case PNG_COLOR_TYPE_PALETTE: // color type '3', bitdepth = 1, 2, 4, 8 switch(bit_depth) { case 1: case 2: case 4: case 8: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); } // if a tRNS chunk is provided, we must also expand the palletized data to 8-bits, // this allows us to make use of the transparency table with existing FreeImage methods if (bIsTransparent && (pixel_depth < 8)) { png_set_packing(png_ptr); } break; default: image_type = FIT_UNKNOWN; break; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // color type '4', bitdepth = 8, 16 switch(bit_depth) { case 8: // 8-bit grayscale + 8-bit alpha => convert to 32-bit RGBA image_type = (pixel_depth == 16) ? FIT_BITMAP : FIT_UNKNOWN; break; case 16: // 16-bit grayscale + 16-bit alpha => convert to 64-bit RGBA image_type = (pixel_depth == 32) ? FIT_RGBA16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } // expand 8-bit greyscale + 8-bit alpha to 32-bit // expand 16-bit greyscale + 16-bit alpha to 64-bit png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB_ALPHA: // color type '6', bitdepth = 8, 16 switch(bit_depth) { case 8: break; case 16: image_type = (pixel_depth == 64) ? FIT_RGBA16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } break; } // check for unknown or invalid formats if(image_type == FIT_UNKNOWN) { *output_image_type = image_type; return FALSE; } #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 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if((image_type == FIT_BITMAP) && ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { // flip the RGB pixels to BGR (or RGBA to BGRA) png_set_bgr(png_ptr); } #endif // gamma correction // 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") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { 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); // return the output image type *output_image_type = image_type; return TRUE; }
//! @brief PNGファイルを読み込みます //! //! @param[in] filename ファイル名 //! @param[out] outTextureWidth 読み込んだテクスチャの幅 //! @param[out] outTextureWidth 読み込んだテクスチャの高さ //! //! @return 32bit非圧縮RGBAバイトデータ配列 EEbuffer EECFileIO::LoadPngFile( crEEstring filename, pEEuint outTextureWidth, pEEuint outTextureHeight ) { // ファイルポインタを取得する FILE *file = NULL; _tfopen_s(&file, filename.c_str(), _T("rb")); if( file == NULL ) { __EEDEF_DEBUG_ERROR(__EEDEF_FUNCTION_NAME, _EESTR("fail file open.")); return EEbuffer(); } // PNGのシグネチャをチェックする EEubyte header[8] = { }; size_t header_size = sizeof(header); fread_s(header, header_size, header_size, 1, file); if( png_sig_cmp(header, 0, header_size) != 0) { fclose(file); __EEDEF_DEBUG_ERROR(__EEDEF_FUNCTION_NAME, _EESTR("unknown signature.")); return EEbuffer(); } // PNG構造体を初期化する png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, // 使用するlibpngのバージョン (png_voidp)NULL, // 使用する構造体 (png_error_ptr)NULL, // エラー用関数ポインタ (png_error_ptr)NULL // 警告用関数ポインタ ); if( png_ptr == NULL ) { fclose(file); __EEDEF_DEBUG_ERROR(__EEDEF_FUNCTION_NAME, _EESTR("unknown structure.")); return EEbuffer(); } // ヘッダー情報のチャンクを初期化する png_infop 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(file); __EEDEF_DEBUG_ERROR(__EEDEF_FUNCTION_NAME, _EESTR("unknown header info.")); return EEbuffer(); } // フッター情報のチャンクを初期化する png_infop end_info = png_create_info_struct(png_ptr); if( end_info == NULL ) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(file); __EEDEF_DEBUG_ERROR(__EEDEF_FUNCTION_NAME, _EESTR("unknown footer info.")); return EEbuffer(); } // ファイルポインタをライブラリに設定する png_init_io(png_ptr, file); // シグネチャのチェックを行った場合は、データを読み込む前にその通知をする png_set_sig_bytes(png_ptr, header_size); // ヘッダ情報を読み込む png_read_info(png_ptr, info_ptr); png_uint_32 png_width = 0; png_uint_32 png_height = 0; EEint png_bit_depth = 0; EEint png_color_type = 0; // IHDRチャンク情報を読み込む png_get_IHDR( png_ptr, // PNG構造体 info_ptr, // ヘッダー情報チャンク &png_width, // [出力] 画像の幅 &png_height, // [出力] 画像の高さ &png_bit_depth, // [出力] ビット深度 &png_color_type, // [出力] カラータイプ NULL, // NULL, // NULL // ); if( png_bit_depth == 1 || png_bit_depth == 2 || png_bit_depth == 4 ) { // 1,2,4bit → 8bit png_set_packing(png_ptr); } else if( png_bit_depth == 16 ) { // 16bit → 8bit png_set_strip_16(png_ptr); } if( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) { // tRNSチャンクがある → アルファチャンネルに変換 png_set_tRNS_to_alpha(png_ptr); } else if ( !IS_BIT_STAND(png_color_type, PNG_COLOR_MASK_ALPHA) ) { // アルファチャンネルがない → アルファチャンネルを追加 png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); } if ( IS_BIT_STAND(png_color_type, PNG_COLOR_MASK_PALETTE) ) { // カラーパレットがある → RGBフルカラーへ変換 png_set_palette_to_rgb(png_ptr); } if ( !IS_BIT_STAND(png_color_type, PNG_COLOR_MASK_COLOR) ) { // グレースケールである → RGBフルカラーへ変換 png_set_gray_to_rgb(png_ptr); } // 変換を反映する png_read_update_info(png_ptr, info_ptr); // 領域の確保 png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); EEbuffer returnBuffer(rowbytes * png_height); // 行配列にデータを取得する png_bytepp image_row_pointer = new png_bytep[png_height]; for( png_uint_32 i = 0; i < png_height; i++ ) { image_row_pointer[i] = &returnBuffer[i * rowbytes]; } png_read_image(png_ptr, image_row_pointer); delete[] image_row_pointer; // 不要になったデータを破棄 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(file); // 出力 __EEDEF_DEBUG_MESSAGE(__EEDEF_FUNCTION_NAME, _EESTR("success.")); if( outTextureWidth != EENULL ) *outTextureWidth = png_width; if( outTextureHeight != EENULL ) *outTextureHeight = png_height; return returnBuffer; }
void png::load(const std::string& file_name) { // unfortunately, we need to break down to the C-code level here, since // libpng is written in C itself // we need to open the file in binary mode FILE* fp = fopen(file_name.c_str(), "rb"); if (!fp) { throw std::runtime_error{"failed to open " + file_name}; } // read in the header (max size of 8), use it to validate this as a png file png_byte header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { fclose(fp); throw std::runtime_error{file_name + " is not a valid png file"}; } // set up libpng structs for reading info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { fclose(fp); throw std::runtime_error{"Failed to create libpng read struct"}; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, nullptr, nullptr); fclose(fp); throw std::runtime_error{"Failed to create libpng info struct"}; } // set error handling to not abort the entire program if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(fp); throw std::runtime_error{"Error reading png metadata"}; } // initialize png reading png_init_io(png_ptr, fp); // let it know we've already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read in the basic image info png_read_info(png_ptr, info_ptr); // convert to 8 bits png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); // verify this is in RGBA format, and if not, convert it to RGBA png_byte color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGBA && color_type != PNG_COLOR_TYPE_RGB) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } // convert tRNS to alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); size_t width = png_get_image_width(png_ptr, info_ptr); size_t height = png_get_image_height(png_ptr, info_ptr); rgba_pixel* newpix = nullptr; png_byte* row = nullptr; png_read_update_info(png_ptr, info_ptr); // begin reading in the image if (setjmp(png_jmpbuf(png_ptr))) { delete[] newpix; delete[] row; png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(fp); throw std::runtime_error{"Error reading image with libpng"}; } int bpr = png_get_rowbytes(png_ptr, info_ptr); // number of bytes in a row // initialize our image storage newpix = new rgba_pixel[height * width]; row = new png_byte[bpr]; int numchannels = png_get_channels(png_ptr, info_ptr); for (size_t y = 0; y < height; y++) { png_read_row(png_ptr, row, nullptr); png_byte* pix = row; for (size_t x = 0; x < width; x++) { rgba_pixel& px = newpix[width * y + x]; if (numchannels == 1 || numchannels == 2) { // monochrome unsigned char color = (unsigned char)*pix++; px.red = color; px.green = color; px.blue = color; if (numchannels == 2) px.alpha = (unsigned char)*pix++; else px.alpha = 255; } else if (numchannels == 3 || numchannels == 4) { px.red = (unsigned char)*pix++; px.green = (unsigned char)*pix++; px.blue = (unsigned char)*pix++; if (numchannels == 4) px.alpha = (unsigned char)*pix++; else px.alpha = 255; } } } // replace image delete[] pixels_; pixels_ = newpix; width_ = width; height_ = height; // cleanup delete[] row; png_read_end(png_ptr, nullptr); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(fp); }
/* 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, png_infopp_NULL, png_infopp_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, png_infopp_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 * dithering, 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, png_voidp_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, int_p_NULL, int_p_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 */ png_set_strip_16(png_ptr); /* 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)) 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)) 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)
static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) { png_structp png; png_infop info; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: png_destroy_read_struct(&png, NULL, NULL); if (rgb) free(rgb); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; png_init_io(png, in_file); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } #ifdef WEBP_EXPERIMENTAL_FEATURES if (has_alpha) { pic->colorspace |= WEBP_CSP_ALPHA_BIT; } #endif num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); free(rgb); End: return ok; }
void set_tRNS_to_alpha() const { TRACE_IO_TRANSFORM("png_set_tRNS_to_alpha\n"); png_set_tRNS_to_alpha(m_png); }
bool Cc3dImage::_initWithPngData(void * pData, int nDatalen) { // length of bytes to check if it is a valid png file #define PNGSIGSIZE 8 bool bRet = false; png_byte header[PNGSIGSIZE] = {0}; png_structp png_ptr = 0; png_infop info_ptr = 0; do { // png header len is 8 bytes if(nDatalen < PNGSIGSIZE) break; // check the data is png or not memcpy(header, pData, PNGSIGSIZE); if(png_sig_cmp(header, 0, PNGSIGSIZE)) break; // init png_struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if(! png_ptr) break; // init png_info info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) break; // set the read call back function tImageSource imageSource; imageSource.data = (unsigned char*)pData; imageSource.size = nDatalen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png header info // read png file info png_read_info(png_ptr, info_ptr); m_nWidth = png_get_image_width(png_ptr, info_ptr); m_nHeight = png_get_image_height(png_ptr, info_ptr); m_nBitsPerComponent = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); //CCLOG("color type %u", color_type); // force palette images to be expanded to 24-bit RGB // it may include alpha channel if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // low-bit-depth grayscale images are to be expanded to 8 bits if (color_type == PNG_COLOR_TYPE_GRAY && m_nBitsPerComponent < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } // expand any tRNS chunk data into a full alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } // reduce images with 16-bit samples to 8 bits if (m_nBitsPerComponent == 16) { png_set_strip_16(png_ptr); } // expand grayscale images to RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } // read png data // m_nBitsPerComponent will always be 8 m_nBitsPerComponent = 8; png_uint_32 rowbytes; png_bytep* row_pointers = (png_bytep*)malloc( sizeof(png_bytep) * m_nHeight ); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); m_pData = new unsigned char[rowbytes * m_nHeight]; if(!m_pData) break; for (unsigned short i = 0; i < m_nHeight; ++i) { row_pointers[i] = m_pData + i*rowbytes; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); png_uint_32 channel = rowbytes/m_nWidth; if (channel == 4) { m_bHasAlpha = true; unsigned int *tmp = (unsigned int *)m_pData; for(unsigned short i = 0; i < m_nHeight; i++) { for(unsigned int j = 0; j < rowbytes; j += 4) { *tmp++ = CC_RGB_PREMULTIPLY_ALPHA( row_pointers[i][j], row_pointers[i][j + 1], row_pointers[i][j + 2], row_pointers[i][j + 3] ); } } m_bPreMulti = true; } do { if(row_pointers) { free(row_pointers); (row_pointers) = 0; } } while(0); bRet = true; } while (0); if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return bRet; }
GLuint MaterialLibrary::loadImage(const char *filename) { GLuint texture; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep *row_pointers = NULL; int bitDepth, colourType; FILE *pngFile; fopen_s(&pngFile, filename, "rb"); if(!pngFile) return 0; png_byte sig[8]; fread(&sig, 8, sizeof(png_byte), pngFile); rewind(pngFile); if(!png_check_sig(sig, 8)) return 0; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if(!png_ptr) return 0; if(setjmp(png_jmpbuf(png_ptr))) return 0; info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) return 0; png_init_io(png_ptr, pngFile); png_read_info(png_ptr, info_ptr); bitDepth = png_get_bit_depth(png_ptr, info_ptr); colourType = png_get_color_type(png_ptr, info_ptr); if(colourType == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if(colourType == PNG_COLOR_TYPE_GRAY && bitDepth < 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(bitDepth == 16) png_set_strip_16(png_ptr); else if(bitDepth < 8) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_uint_32 width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colourType, NULL, NULL, NULL); int components = GetTextureInfo(colourType); if(components == -1) { if(png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (width * height * components)); row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height); for(unsigned int i = 0; i < height; ++i) row_pointers[i] = (png_bytep)(pixels + (i * width * components)); png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); // make it glGenTextures(1, &texture); // bind it glBindTexture(GL_TEXTURE_2D, texture); // here we has the problems GLuint glcolours; (components==4) ? (glcolours = GL_RGBA): (0); (components==3) ? (glcolours = GL_RGB): (0); (components==2) ? (glcolours = GL_LUMINANCE_ALPHA): (0); (components==1) ? (glcolours = GL_LUMINANCE): (0); GLubyte a[1000]; strcpy_s((char*)a, sizeof(a), (char*)glGetString(GL_VERSION)); // stretch it glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //OpenGL 1.1 // gluBuild2DMipmaps(GL_TEXTURE_2D, components, width, height, glcolours, GL_UNSIGNED_BYTE, pixels); //OpenGL 1.4 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); //OpenGL 3.0 // http://www.opengl.org/wiki/Common_Mistakes#gluBuild2DMipmaps //On ATI glEnable(GL_TEXTURE_2D); //Warning: It has been reported that on some ATI drivers, //glGenerateMipmap(GL_TEXTURE_2D) has no effect unless you //precede it with a call to glEnable(GL_TEXTURE_2D) in this particular case. //Once again, to be clear, bind the texture, glEnable, then glGenerateMipmap. //This is a bug and has been in the ATI drivers for a while. //Perhaps by the time you read this, it will have been corrected. //(glGenerateMipmap doesn't work on ATI as of 2011) // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // glGenerateMipmap(GL_TEXTURE_2D); //Generate mipmaps now!!! glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, glcolours, GL_UNSIGNED_BYTE, pixels); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(pngFile); free(row_pointers); free(pixels); return texture; }
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_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 && ( (FT_UInt)x_offset + metrics->width > map->width || (FT_UInt)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 ) { FT_ULong size; 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 > 0x7FFF || map->width > 0x7FFF ) { error = FT_THROW( Array_Too_Large ); goto DestroyExit; } /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */ size = map->rows * (FT_ULong)map->pitch; error = ft_glyphslot_alloc_bitmap( slot, size ); if ( error ) 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; }
bool LoadPNG(const String& filename, png_byte* &PNG_image_buffer, png_uint_32 &width, png_uint_32 &height) { FILE *PNG_file = fopen(filename.c_str(), "rb"); if (PNG_file == NULL) { sysLog.Printf("ERROR: Couldn't open %s.", filename.c_str()); return false; } GLubyte PNG_header[8]; fread(PNG_header, 1, 8, PNG_file); if (png_sig_cmp(PNG_header, 0, 8) != 0) { sysLog.Printf("ERROR: %s is not a PNG.", filename.c_str()); return false; } png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (PNG_reader == NULL) { sysLog.Printf("ERROR: Can't start reading %s.", filename.c_str()); fclose(PNG_file); return false; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (PNG_info == NULL) { sysLog.Printf("ERROR: Can't get info for %s.", filename.c_str()); png_destroy_read_struct(&PNG_reader, NULL, NULL); fclose(PNG_file); return false; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { sysLog.Printf("ERROR: Can't get end info for %s.", filename.c_str()); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); fclose(PNG_file); return false; } if (setjmp(png_jmpbuf(PNG_reader))) { sysLog.Printf("ERROR: Can't load %s.", filename.c_str()); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return false; } png_init_io(PNG_reader, PNG_file); png_set_sig_bytes(PNG_reader, 8); png_read_info(PNG_reader, PNG_info); width = png_get_image_width(PNG_reader, PNG_info); height = png_get_image_height(PNG_reader, PNG_info); 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); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_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_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_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return true; }
static pixman_image_t * load_png(FILE *fp) { png_struct *png; png_info *info; png_byte *data = NULL; png_byte **row_pointers = NULL; png_uint_32 width, height; int depth, color_type, interlace, stride; unsigned int i; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_callback, NULL); if (!png) return NULL; info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, &info, NULL); return NULL; } if (setjmp(png_jmpbuf(png))) { if (data) free(data); if (row_pointers) free(row_pointers); png_destroy_read_struct(&png, &info, NULL); 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 = stride_for_width(width); data = malloc(stride * height); if (!data) { png_destroy_read_struct(&png, &info, NULL); return NULL; } row_pointers = malloc(height * sizeof row_pointers[0]); if (row_pointers == NULL) { free(data); png_destroy_read_struct(&png, &info, NULL); 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); return pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, (uint32_t *) data, stride); }
int simpl_image_load_png(SimplImage **image, SimplInStream istream) { png_structp png_ptr; png_infop info_ptr; png_byte color_type, bitdepth, *row_data=NULL; png_bytep* row_ptrs=NULL; png_uint_32 i, j, width, height, row_size; SimplColorPixel *iptr; SimplPixel *aptr; int out = SIMPL_INTERNAL; /* Create a read struct. */ if (!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) { return SIMPL_INTERNAL; } /* Create an info struct. */ if (!(info_ptr = png_create_info_struct(png_ptr))) { goto error; } /* Handle libpng errors with a magic setjmp. */ if (setjmp(png_jmpbuf(png_ptr))) { goto error; } /* Set the stream-based data source. */ png_set_read_fn(png_ptr, istream, StreamReadData); /* Read the info chunk. */ png_read_info(png_ptr, info_ptr); /* Get the dimensions and color information. */ width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); bitdepth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); /* If palette, low bit depth gray, transparent w/o alpha, or 16 bit, fix it. */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } else if (color_type == PNG_COLOR_TYPE_GRAY) { if (bitdepth<8) png_set_expand_gray_1_2_4_to_8(png_ptr); bitdepth = 8; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } png_set_strip_16(png_ptr); /* Either allocate a row, or load the entire image into a buffer. This is * because single row access uses less memory but doesn't work for * interlaced PNGs. */ row_size = png_get_rowbytes(png_ptr, info_ptr); if (png_get_interlace_type(png_ptr, info_ptr)==PNG_INTERLACE_NONE) { row_data = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_data) { out = SIMPL_NOMEM; goto error; } } else { row_ptrs = (png_bytep*)calloc(height, sizeof(png_bytep)); if (!row_ptrs) { out = SIMPL_NOMEM; goto error; } for (j=0; j<height; ++j) { row_ptrs[j] = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_ptrs[j]) { out = SIMPL_NOMEM; goto error; } } png_read_image(png_ptr, row_ptrs); } /* Allocate an image of the specified size. */ out = simpl_image(image, width, height); if (out != SIMPL_OK) goto error; /* Store the decoded image into our format. */ if (color_type == PNG_COLOR_TYPE_RGB) { for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; for (i=0; i<3*width; i+=3) { iptr->red = row_data[i]; iptr->green = row_data[i+1]; iptr->blue = row_data[i+2]; iptr++; } } } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { simpl_alpha_create(*image); for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; aptr = (*image)->alpha + j * width; for (i=0; i<4*width; i+=4) { iptr->red = row_data[i]; iptr->green = row_data[i+1]; iptr->blue = row_data[i+2]; iptr++; *aptr++ = row_data[i+3]; } } } else if (color_type == PNG_COLOR_TYPE_GRAY) { for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; for (i=0; i<width; i++) { iptr->red = row_data[i]; iptr->green = row_data[i]; iptr->blue = row_data[i]; iptr++; } } } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { simpl_alpha_create(*image); for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; aptr = (*image)->alpha + j * width; for (i=0; i<2*width; i+=2) { iptr->red = row_data[i]; iptr->green = row_data[i]; iptr->blue = row_data[i]; iptr++; *aptr++ = row_data[i+1]; } } } else goto error; error: if (row_ptrs) { for (j=0; j<height; ++j) { if (row_ptrs[j]) free((void *)row_ptrs[j]); } free((void *)row_ptrs); } else { if (row_data) free((void *)row_data); } png_destroy_read_struct(&png_ptr, &info_ptr, 0); return out; }
/* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal) { BITMAP *bmp; PALETTE tmppal; png_uint_32 width, height, rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp, dest_bpp; int tRNS_to_alpha = FALSE; int number_passes, pass; ASSERT(png_ptr && info_ptr && rgb); /* 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); /* 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); /* 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(png_ptr); /* Adds a full alpha channel if there is transparency information * in a tRNS chunk. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); tRNS_to_alpha = TRUE; } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ if (_png_screen_gamma != 0.0) { screen_gamma = get_gamma(); if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Even if the user doesn't supply space for a palette, we want * one for the load process. */ if (!pal) pal = tmppal; /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red >> 2; /* 256 -> 64 */ pal[i].g = palette[i].green >> 2; pal[i].b = palette[i].blue >> 2; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } }
void LoadPNG( const char *name, byte **pic, int *width, int *height, int *numLayers, int *numMips, int *bits, byte alphaByte ) { int bit_depth; int color_type; png_uint_32 w; png_uint_32 h; unsigned int row; // size_t rowbytes; png_infop info; png_structp png; png_bytep *row_pointers; byte *data; byte *out; // int size; // load png ri.FS_ReadFile( name, ( void ** ) &data ); if ( !data ) { return; } //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) NULL, png_user_error_fn, png_user_warning_fn ); if ( !png ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_write_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); return; } // allocate/initialize the memory for image information. REQUIRED info = png_create_info_struct( png ); if ( !info ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_info_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) NULL, ( png_infopp ) NULL ); return; } /* * Set error handling if you are using the setjmp/longjmp method (this is * the common 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 ) ) ) { // if we get here, we had a problem reading the file ri.Printf( PRINT_WARNING, "LoadPNG: first exception handler called for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) NULL ); return; } //png_set_write_fn(png, buffer, png_write_data, png_flush_data); png_set_read_fn( png, data, png_read_data ); png_set_sig_bytes( png, 0 ); // 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, info ); // get picture info png_get_IHDR( png, info, ( png_uint_32 * ) &w, ( png_uint_32 * ) &h, &bit_depth, &color_type, NULL, NULL, NULL ); // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16( png ); // expand paletted images to RGB triplets if ( color_type & PNG_COLOR_MASK_PALETTE ) { png_set_expand( png ); } // expand gray-scaled images to RGB triplets if ( !( color_type & PNG_COLOR_MASK_COLOR ) ) { png_set_gray_to_rgb( png ); } // 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_gray_1_2_4_to_8(png); // 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, info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( png ); } // if there is no alpha information, fill with alphaByte if ( !( color_type & PNG_COLOR_MASK_ALPHA ) ) { png_set_filler( png, alphaByte, PNG_FILLER_AFTER ); } // expand pictures with less than 8bpp to 8bpp if ( bit_depth < 8 ) { png_set_packing( png ); } // update structure with the above settings png_read_update_info( png, info ); // allocate the memory to hold the image *width = w; *height = h; *pic = out = ( byte * ) ri.Z_Malloc( w * h * 4 ); row_pointers = ( png_bytep * ) ri.Hunk_AllocateTempMemory( sizeof( png_bytep ) * h ); // set a new exception handler if ( setjmp( png_jmpbuf( png ) ) ) { ri.Printf( PRINT_WARNING, "LoadPNG: second exception handler called for (%s)\n", name ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) NULL ); return; } //rowbytes = png_get_rowbytes(png, info); for ( row = 0; row < h; row++ ) { row_pointers[ row ] = ( png_bytep )( out + ( row * 4 * w ) ); } // read image data png_read_image( png, row_pointers ); // read rest of file, and get additional chunks in info png_read_end( png, info ); // clean up after the read, and free any memory allocated png_destroy_read_struct( &png, &info, ( png_infopp ) NULL ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); }
// load in the image data Picture PictureLoaderPng::load( io::NFile file ) const { if(!file.isOpen()) { Logger::warning( "LOAD PNG: can't open file %s", file.getFileName().toString().c_str() ); return Picture::getInvalid(); } png_byte buffer[8]; // Read the first few bytes of the PNG file if( file.read(buffer, 8) != 8 ) { Logger::warning( "LOAD PNG: can't read file %s", file.getFileName().toString().c_str() ); return Picture::getInvalid(); } // Check if it really is a PNG file if( png_sig_cmp(buffer, 0, 8) ) { Logger::warning( "LOAD PNG: not really a png %s", file.getFileName().toString().c_str() ); return Picture::getInvalid(); } // Allocate the png read struct png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn); if( !png_ptr ) { Logger::warning( "LOAD PNG: Internal PNG create read struct failure %s", file.getFileName().toString().c_str() ); return Picture::getInvalid(); } // Allocate the png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { Logger::warning( "LOAD PNG: Internal PNG create info struct failure 5s", file.getFileName().toString().c_str() ); png_destroy_read_struct(&png_ptr, NULL, NULL); return Picture::getInvalid(); } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* if( RowPointers ) delete [] RowPointers; */ return Picture::getInvalid(); } // changed by zola so we don't need to have public FILE pointers png_set_read_fn(png_ptr, &file, user_read_data_fcn); png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature png_read_info(png_ptr, info_ptr); // Read the info section of the png file unsigned int Width; unsigned int Height; int BitDepth; int ColorType; { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert palette color to true color if (ColorType==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); // Convert low bit colors to 8 bit colors if (BitDepth < 8) { if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_expand_gray_1_2_4_to_8(png_ptr); else png_set_packing(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // Convert high bit colors to 8 bit colors if (BitDepth == 16) png_set_strip_16(png_ptr); // Convert gray color to true color if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); int intent; const double screen_gamma = 2.2; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } // Update the changes in between, as we need to get the new color type // for proper processing of the RGBA type png_read_update_info(png_ptr, info_ptr); { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert RGBA to BGRA if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) { png_set_bgr(png_ptr); } // Create the image structure to be filled by png data Picture* pic = GfxEngine::instance().createPicture( Size( Width, Height ) ); GfxEngine::instance().loadPicture( *pic ); if( pic->getSize().getArea() == 0 ) { Logger::warning( "LOAD PNG: Internal PNG create image struct failure %s", file.getFileName().toString().c_str() ); png_destroy_read_struct(&png_ptr, NULL, NULL); return Picture::getInvalid(); } if( !Height ) { Logger::warning( "LOAD PNG: Internal PNG create row pointers failure %s", file.getFileName().toString().c_str() ); png_destroy_read_struct(&png_ptr, NULL, NULL); return Picture::getInvalid(); } // Create array of pointers to rows in image data ScopedPtr<unsigned char*> RowPointers( (unsigned char**)new png_bytep[ Height ] ); // Fill array of pointers to rows in image data SDL_LockSurface( pic->getSurface() ); unsigned char* data = (unsigned char*)pic->getSurface()->pixels; for(unsigned int i=0; i<Height; ++i) { RowPointers.data()[i] = data; data += pic->getSurface()->pitch; } // for proper error handling if( setjmp( png_jmpbuf( png_ptr ) ) ) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); GfxEngine::instance().deletePicture( pic ); return Picture::getInvalid(); } // Read data using the library function that handles all transformations including interlacing png_read_image( png_ptr, RowPointers.data() ); png_read_end( png_ptr, NULL ); png_destroy_read_struct( &png_ptr, &info_ptr, 0 ); // Clean up memory SDL_UnlockSurface(pic->getSurface()); return *pic; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with a complete compressed frame. ****************************************************************************/ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; picture_t *p_pic = 0; png_uint_32 i_width, i_height; int i_color_type, i_interlace_type, i_compression_type, i_filter_type; int i_bit_depth, i; png_structp p_png; png_infop p_info, p_end_info; png_bytep *p_row_pointers = NULL; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; p_sys->b_error = false; if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) { block_Release( p_block ); *pp_block = NULL; return NULL; } p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( p_png == NULL ) { block_Release( p_block ); *pp_block = NULL; return NULL; } p_info = png_create_info_struct( p_png ); if( p_info == NULL ) { png_destroy_read_struct( &p_png, NULL, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } p_end_info = png_create_info_struct( p_png ); if( p_end_info == NULL ) { png_destroy_read_struct( &p_png, &p_info, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } /* libpng longjmp's there in case of error */ if( setjmp( png_jmpbuf( p_png ) ) ) goto error; png_set_read_fn( p_png, (void *)p_block, user_read ); png_set_error_fn( p_png, (void *)p_dec, user_error, user_warning ); png_read_info( p_png, p_info ); if( p_sys->b_error ) goto error; png_get_IHDR( p_png, p_info, &i_width, &i_height, &i_bit_depth, &i_color_type, &i_interlace_type, &i_compression_type, &i_filter_type); if( p_sys->b_error ) goto error; /* Set output properties */ p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width = i_width; p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = i_height; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; p_dec->fmt_out.video.i_rmask = 0x000000ff; p_dec->fmt_out.video.i_gmask = 0x0000ff00; p_dec->fmt_out.video.i_bmask = 0x00ff0000; if( i_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( p_png ); if( i_color_type == PNG_COLOR_TYPE_GRAY || i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( p_png ); /* Strip to 8 bits per channel */ if( i_bit_depth == 16 ) png_set_strip_16( p_png ); if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( p_png ); } else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) ) { p_dec->fmt_out.i_codec = VLC_CODEC_RGB24; } /* Get a new picture */ p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) goto error; /* Decode picture */ p_row_pointers = malloc( sizeof(png_bytep) * i_height ); if( !p_row_pointers ) goto error; for( i = 0; i < (int)i_height; i++ ) p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i; png_read_image( p_png, p_row_pointers ); if( p_sys->b_error ) goto error; png_read_end( p_png, p_end_info ); if( p_sys->b_error ) goto error; png_destroy_read_struct( &p_png, &p_info, &p_end_info ); free( p_row_pointers ); p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts; block_Release( p_block ); *pp_block = NULL; return p_pic; error: free( p_row_pointers ); png_destroy_read_struct( &p_png, &p_info, &p_end_info ); block_Release( p_block ); *pp_block = NULL; return NULL; }
void png_load_from_memory(aasset_buffer_t& buf, raw_bitmap_t* out_bitmap) { //png header - 8 bytes if (png_sig_cmp(buf.data(), 0, 8)) { my_assert(false && "Couldn't load texture. It isn't png file."); return; } auto png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); my_assert(png_ptr && "Couldn't load texture. Png load error."); MAKE_GUARD(png_ptr, [](decltype(png_ptr) ptr) { png_destroy_read_struct(&ptr, (png_infopp)NULL, (png_infopp)NULL);}); auto info_ptr = png_create_info_struct(png_ptr); my_assert(info_ptr && "Couldn't load texture. Png load error."); auto info_deleter = [png_ptr](decltype(info_ptr) ptr) { png_destroy_info_struct(png_ptr, &ptr);}; MAKE_GUARD(info_ptr, info_deleter); // the code in this if statement gets called if libpng encounters an error if (setjmp((long*) png_jmpbuf(png_ptr))) { my_assert(false && "error from libpng"); return; } png_set_read_fn(png_ptr, &buf, read_from_aasset_buffer); // tell libpng we already read the signature png_set_sig_bytes(png_ptr, 8); buf.seek(8); png_read_info(png_ptr, info_ptr); png_uint_32 width = 0; png_uint_32 height = 0; int bitDepth = 0; int colorType = -1; auto res = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); my_assert(res == 1); bool transparency = false; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); transparency = true; } // Expands PNG with less than 8bits per channel to 8bits. if (bitDepth < 8) { png_set_packing(png_ptr); // Shrinks PNG with 16bits per color channel down to 8bits. } else if (bitDepth == 16) { png_set_strip_16(png_ptr); } uint32_t format = 0; switch (colorType) { case PNG_COLOR_TYPE_RGB: format = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGBA: format = GL_RGBA; break; case PNG_COLOR_TYPE_PALETTE: { png_set_palette_to_rgb(png_ptr); format = transparency ? GL_RGBA : GL_RGB; break; } default: my_assert(false && "Png read error. Uknown color type"); return; } //apply transformations png_read_update_info(png_ptr, info_ptr); out_bitmap->init(width, height, format); auto row_size = png_get_rowbytes(png_ptr, info_ptr); my_assert(row_size > 0); my_assert(row_size == width * out_bitmap->bytes_per_pixel()); auto row_ptrs = new png_bytep[height]; MAKE_GUARD(row_ptrs, [](decltype(row_ptrs) ptr) { delete[] ptr;}); for (int32_t i = 0; i < height; ++i) { row_ptrs[height - (i + 1)] = out_bitmap->get_row(i); } png_read_image(png_ptr, row_ptrs); }