/** * @brief internal function used to write a byte array as a PNG file * * The PNG file is written as a 8bit image file, interlaced, * truecolor. Depending on the number of channels, the color model is * gray, gray+alpha, rgb, rgb+alpha. * * @todo handle 16bit * * @param fname PNG file name, "-" means stdout * @param data deinterlaced (RRR..GGG..BBB..AAA) image byte array * @param nx, ny, nc number of columns, lines and channels * @param dtype identifier for the data type to be used for output * @return 0 if everything OK, -1 if an error occured */ static int write_png_raw(const char *fname, const void *data, size_t nx, size_t ny, size_t nc, int dtype) { png_structp png_ptr; png_infop info_ptr; png_byte *idata = NULL, *idata_ptr = NULL; png_bytep *row_pointers = NULL; png_byte bit_depth; /* volatile : because of setjmp/longjmp */ FILE *volatile fp; const unsigned char *data_u8 = NULL; const unsigned char *data_u8_ptr = NULL; const float *data_f32 = NULL; const float *data_f32_ptr = NULL; float tmp; int color_type, interlace, compression, filter; size_t size; size_t i, j, k; /* parameters check */ if (0 >= nx || 0 >= ny || 0 >= nc) return -1; if (NULL == fname || NULL == data) return -1; if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype) return -1; /* open the PNG output file */ if (0 == strcmp(fname, "-")) fp = stdout; else if (NULL == (fp = fopen(fname, "wb"))) return -1; /* allocate the interlaced array and row pointers */ size = nx * ny * nc; if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte)))) return write_png_abort(fp, NULL, NULL, NULL, NULL); if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep)))) return write_png_abort(fp, idata, NULL, NULL, NULL); /* * create and initialize the png_struct * with the default stderr and error handling */ if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) return write_png_abort(fp, idata, row_pointers, NULL, NULL); /* allocate/initialize the memory for image information */ if (NULL == (info_ptr = png_create_info_struct(png_ptr))) return write_png_abort(fp, idata, row_pointers, &png_ptr, NULL); /* set error handling */ if (0 != setjmp(png_jmpbuf(png_ptr))) /* if we get here, we had a problem reading the file */ return write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr); /* set up the input control using standard C streams */ png_init_io(png_ptr, fp); /* set image informations */ bit_depth = 8; switch (nc) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: png_destroy_read_struct(&png_ptr, NULL, NULL); free(row_pointers); free(idata); (void) fclose(fp); return -1; } interlace = PNG_INTERLACE_ADAM7; compression = PNG_COMPRESSION_TYPE_BASE; filter = PNG_FILTER_TYPE_BASE; /* set image header */ png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny, bit_depth, color_type, interlace, compression, filter); /* TODO : significant bit (sBIT), gamma (gAMA), comments (text) chunks */ png_write_info(png_ptr, info_ptr); /* * interlace and convert RRR GGG BBB to RGB RGB RGB * the image is interlaced layer after layer * this involves more memory exchange, but allows a generic loop */ switch (dtype) { case IO_PNG_U8: data_u8 = (unsigned char *) data; for (k = 0; k < nc; k++) { /* channel loop */ data_u8_ptr = data_u8 + (size_t) (nx * ny * k); idata_ptr = idata + (size_t) k; for (j = 0; j < ny; j++) { /* row loop */ for (i = 0; i < nx; i++) { /* pixel loop */ *idata_ptr = (png_byte) * data_u8_ptr++; idata_ptr += nc; } } } break; case IO_PNG_F32: data_f32 = (float *) data; for (k = 0; k < nc; k++) { /* channel loop */ data_f32_ptr = data_f32 + (size_t) (nx * ny * k); idata_ptr = idata + (size_t) k; for (j = 0; j < ny; j++) { /* row loop */ for (i = 0; i < nx; i++) { /* pixel loop */ tmp = floor(*data_f32_ptr++ + .5); *idata_ptr = (png_byte) (tmp < 0. ? 0. : (tmp > 255. ? 255. : tmp)); idata_ptr += nc; } } } break; } /* set row pointers */ for (j = 0; j < ny; j++) row_pointers[j] = idata + (size_t) (nc * nx * j); /* write out the entire image and end it */ png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); /* clean up and free any memory allocated, close the file */ (void) write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr); return 0; }
void save(void) { char file[MAX_PATH]; strcpy(file,firstFile); char* p = strrchr(file,'\\'); if (p == 0) p = file; else p++; char* x = strrchr(p,'.'); if (x == 0) x = p+strlen(p); strcpy(x,".png"); OPENFILENAME ofn; ZeroMemory(&ofn, sizeof ofn); ofn.lStructSize = sizeof ofn; ofn.hwndOwner = wnd; ofn.lpstrFilter = "PNG Image Files (*.png)\0*.png\0All Files (*.*)\0*.*\0"; ofn.lpstrFile = file; ofn.nMaxFile = sizeof file; ofn.lpstrTitle = "Save as a PNG Image"; ofn.Flags = OFN_ENABLEHOOK|OFN_ENABLESIZING|OFN_EXPLORER|OFN_HIDEREADONLY; ofn.lpfnHook = fileDialogProc; prepareOFN(&ofn); if (GetSaveFileName(&ofn)) { FILE* f = fopen(file,"wb"); if (f == 0) fatal("Could not open ouput PNG file"); png_structp pngp = png_create_write_struct (PNG_LIBPNG_VER_STRING,(png_voidp)0,0,0); if (pngp == 0) fatal("Could not create PNG write structure"); png_infop infop = png_create_info_struct(pngp); if (infop == 0) fatal("Could not create PNG info structure"); if (setjmp(png_jmpbuf(pngp))) fatal("Could not write PNG file"); png_init_io(pngp,f); png_set_IHDR(pngp,infop,width,height,8,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_set_bgr(pngp); png_bytep* rows = (png_bytep*)malloc(sizeof(png_bytep)*height); for (int y = 0; y < height; y++) rows[y] = bits+(3*y*width); png_set_rows(pngp,infop,rows); png_write_png(pngp,infop,PNG_TRANSFORM_IDENTITY,0); free(rows); png_destroy_write_struct(&pngp,&infop); fclose(f); } }
static int savePNGto(FILE *fp, gPixmap *pixmap) { gUnmanagedSurface *surface = pixmap->surface; if (!surface) return -2; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { eDebug("[ePNG] couldn't allocate write struct"); return -2; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { eDebug("[ePNG] failed to allocate info struct"); png_destroy_write_struct(&png_ptr, 0); return -3; } png_set_IHDR(png_ptr, info_ptr, surface->x, surface->y, surface->bpp/surface->bypp, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (setjmp(png_jmpbuf(png_ptr))) { eDebug("[ePNG] png setjump failed or activated"); png_destroy_write_struct(&png_ptr, &info_ptr); return -4; } png_init_io(png_ptr, fp); png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH); png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); png_byte *row_pointer; png_byte *cr = new png_byte[surface->y * surface->stride]; if (cr == NULL) { eDebug("[ePNG] failed to allocate memory image"); return -5; } for (int i = 0; i < surface->y; ++i) { row_pointer = ((png_byte*)surface->data) + i * surface->stride; if (surface->bypp == 4) { memcpy(cr, row_pointer, surface->stride); for (int j = 0; j < surface->stride; j += 4) { unsigned char tmp = cr[j]; cr[j] = cr[j+2]; cr[j+2] = tmp; } png_write_row(png_ptr, cr); } else png_write_row(png_ptr, row_pointer); } delete [] cr; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; }
/* Read a PNG image file from "fname", using routines from libpng. * Returns 0 on success, or negative on various failures: * -2: File is not PNG, or file is corrupt * -3: Can't malloc a big enough image buffer * -4: PNG image data is neither grayscale nor RGB (unsupported format) */ int ReadPNG(const char *fname, unsigned char (**data)[3], int *w, int *h) { FILE *fp = fopen(fname, "rb"); png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; int transforms = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_PACKSWAP | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SHIFT; int channels; int bytes; png_bytepp row_pointers = NULL; int rc = 0; if (fp == NULL) return -1; (*data) = NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png_ptr == NULL) goto err_nomem; info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) goto err_nomem; end_info = png_create_info_struct(png_ptr); if (end_info == NULL) goto err_nomem; if (setjmp(png_jmpbuf(png_ptr))) goto err_corrupt; png_init_io(png_ptr, fp); png_read_png(png_ptr, info_ptr, transforms, NULL); *w = png_get_image_width(png_ptr, info_ptr); *h = png_get_image_height(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); bytes = png_get_rowbytes(png_ptr, info_ptr); if (bytes != channels*(*w)) goto err_unsupported; row_pointers = png_get_rows(png_ptr, info_ptr); if (row_pointers == NULL) goto err_nomem; (*data) = malloc(*w * *h * sizeof **data); if (*data == NULL) goto err_nomem; if (channels == 1) { int j; for (j=0; j < *h; ++j) { int i; unsigned char (*imrow)[3] = (*data) + j*(*w); for (i=0; i < *w; ++i) memset(imrow[i], row_pointers[j][i], 3); } } else if (channels == 3) { int j; for (j=0; j < *h; ++j) { unsigned char (*imrow)[3] = (*data) + j*(*w); memcpy(imrow, row_pointers[j], 3*(*w)); } } else goto err_unsupported; go_return: png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return rc; err_corrupt: rc = -2; free(data); goto go_return; err_nomem: rc = -3; free(data); goto go_return; err_unsupported: rc = -4; free(data); goto go_return; }
/** * From: http://stackoverflow.com/a/11297197 */ GLuint gl4::TextureManager::_loadTextureFromPNG(const char * file_name, int * width, int * height) { png_byte header[8]; FILE *fp = fopen(file_name, "rb"); if (fp == 0) { perror(file_name); return 0; } // read the header fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "error: %s is not a PNG.\n", file_name); fclose(fp); return 0; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "error: png_create_read_struct returned 0.\n"); fclose(fp); return 0; } // create png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return 0; } // create png info struct png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); fclose(fp); return 0; } // the code in this if statement gets called if libpng encounters an error if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "error from libpng\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; } // init png reading png_init_io(png_ptr, fp); // let libpng know you already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read all the info up to the image data png_read_info(png_ptr, info_ptr); // variables to pass to get info int bit_depth, color_type; png_uint_32 temp_width, temp_height; // get info about png png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, NULL, NULL, NULL); if (width != 0){ *width = temp_width; } if (height != 0){ *height = temp_height; } // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Row size in bytes. int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // glTexImage2d requires rows to be 4-byte aligned rowbytes += 3 - ((rowbytes-1) % 4); // Allocate the image_data as a big block, to be given to opengl png_byte * image_data; image_data = (png_byte*)std::malloc(rowbytes * temp_height * sizeof(png_byte)+15); if (image_data == NULL) { fprintf(stderr, "error: could not allocate memory for PNG image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; } // row_pointers is for pointing to image_data for reading the png with libpng png_bytep * row_pointers = (png_bytep*)std::malloc(temp_height * sizeof(png_bytep)); if (row_pointers == NULL) { fprintf(stderr, "error: could not allocate memory for PNG row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(image_data); fclose(fp); return 0; } // set the individual row_pointers to point at the correct offsets of image_data int i; for (i = 0; i < temp_height; i++) { row_pointers[temp_height - 1 - i] = image_data + i * rowbytes; } // read the png into image_data through row_pointers png_read_image(png_ptr, row_pointers); // Generate the OpenGL texture object GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, temp_width, temp_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); // clean up png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(image_data); free(row_pointers); fclose(fp); return texture; }
/** PNG content to bitmap conversion. * * This routine generates a bitmap object from a PNG image content */ static struct bitmap * png_cache_convert(struct content *c) { png_structp png_ptr; png_infop info_ptr; png_infop end_info_ptr; volatile struct bitmap *bitmap = NULL; struct png_cache_read_data_s png_cache_read_data; png_uint_32 width, height; volatile png_bytep *row_pointers = NULL; png_cache_read_data.data = content__get_source_data(c, &png_cache_read_data.size); if ((png_cache_read_data.data == NULL) || (png_cache_read_data.size <= 8)) { return NULL; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, nspng_error, nspng_warning); if (png_ptr == NULL) { return NULL; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } end_info_ptr = png_create_info_struct(png_ptr); if (end_info_ptr == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } /* setup error exit path */ if (setjmp(png_jmpbuf(png_ptr))) { /* cleanup and bail */ goto png_cache_convert_error; } /* read from a buffer instead of stdio */ png_set_read_fn(png_ptr, &png_cache_read_data, png_cache_read_fn); /* ensure the png info structure is populated */ png_read_info(png_ptr, info_ptr); /* setup output transforms */ nspng_setup_transforms(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); /* Claim the required memory for the converted PNG */ bitmap = bitmap_create(width, height, BITMAP_NEW); if (bitmap == NULL) { /* cleanup and bail */ goto png_cache_convert_error; } row_pointers = calc_row_pointers((struct bitmap *) bitmap); if (row_pointers != NULL) { png_read_image(png_ptr, (png_bytep *) row_pointers); } png_cache_convert_error: /* cleanup png read */ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); free((png_bytep *) row_pointers); if (bitmap != NULL) bitmap_modified((struct bitmap *)bitmap); return (struct bitmap *)bitmap; }
VBuf *BmpHandleToPngByte(HBITMAP hBmp) { BITMAP bmp; BITMAPINFO *bmi = NULL; int palette, total_size, header_size, data_size, line_size; HWND hWnd = ::GetDesktopWindow(); HDC hDc = NULL; VBuf bmpVbuf; png_struct *png = NULL; png_info *info = NULL; png_color_8 sbit; png_byte **lines = NULL; VBuf *vbuf = NULL, *ret = NULL; if (!::GetObject(hBmp, sizeof(bmp), &bmp)) return NULL; //if (bmp.bmBitsPixel < 24) bmp.bmBitsPixel = 24; line_size = bmp.bmWidth * ALIGN_SIZE(bmp.bmBitsPixel, 8) / 8; line_size = ALIGN_SIZE(line_size, 4); data_size = line_size * bmp.bmHeight; palette = bmp.bmBitsPixel <= 8 ? 1 << bmp.bmBitsPixel : 0; header_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palette; total_size = header_size + data_size; if (!bmpVbuf.AllocBuf(total_size)) return NULL; bmi = (BITMAPINFO *)bmpVbuf.Buf(); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biWidth = bmp.bmWidth; bmi->bmiHeader.biHeight = bmp.bmHeight; bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biBitCount = bmp.bmBitsPixel; bmi->bmiHeader.biCompression = BI_RGB; bmi->bmiHeader.biClrUsed = palette; bmi->bmiHeader.biClrImportant = palette; if (!(hDc = ::GetDC(hWnd)) || !::GetDIBits(hDc, hBmp, 0, bmp.bmHeight, (char *)bmi + header_size, bmi, DIB_RGB_COLORS)) { goto END; } if (!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL; if (!(info = png_create_info_struct(png))) goto END; if (!(vbuf = new VBuf(0, total_size))) goto END; png_set_write_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_wfunc, (png_flush_ptr)png_vbuf_wflush); if (palette) { png_color png_palette[256]; for (int i=0; i < palette; i++) { png_palette[i].red = bmi->bmiColors[i].rgbRed; png_palette[i].green = bmi->bmiColors[i].rgbGreen; png_palette[i].blue = bmi->bmiColors[i].rgbBlue; } png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, bmp.bmBitsPixel, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png, info, png_palette, palette); } else { png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, 8, bmp.bmBitsPixel > 24 ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } sbit.red = sbit.green = sbit.blue = 8; sbit.alpha = bmp.bmBitsPixel > 24 ? 8 : 0; png_set_sBIT(png, info, &sbit); if (setjmp(png_jmpbuf(png))) { goto END; } else { png_write_info(png, info); png_set_bgr(png); lines = (png_byte **)malloc(sizeof(png_bytep *) * bmp.bmHeight); for (int i = 0; i < bmp.bmHeight; i++) { lines[i] = bmpVbuf.Buf() + header_size + line_size * (bmp.bmHeight - i - 1); } png_write_image(png, lines); png_write_end(png, info); ret = vbuf; } END: if (png) png_destroy_write_struct(&png, &info); if (hDc) ::ReleaseDC(hWnd, hDc); if (lines) free(lines); if (!ret && vbuf) delete vbuf; return ret; }
static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask) { png_byte header[8]; png_structp png_ptr; png_infop info_ptr, end_info; uint bit_depth, colour_type; uint i, pixelsize; SpriteLoader::CommonPixel *dst; if (!OpenPNGFile(filename, id, mask)) return mask; // If mask is true, and file not found, continue true anyway, as it isn't a show-stopper /* Check the header */ FioReadBlock(header, 8); if (png_sig_cmp(header, 0, 8) != 0) return false; /* Create the reader */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_my_error, png_my_warning); if (png_ptr == NULL) return false; /* Create initial stuff */ 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 false; } end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } /* Make sure that upon error, we can clean up graceful */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return false; } /* Read the file */ png_set_read_fn(png_ptr, NULL, png_my_read); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); if (!mask) { /* Read the text chunks */ png_textp text_ptr; int num_text = 0; png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); if (num_text == 0) DEBUG(misc, 0, "Warning: PNG Sprite '%s/%d.png' doesn't have x_offs and y_offs; expect graphical problems", filename, id); for (int i = 0; i < num_text; i++) { /* x_offs and y_offs are in the text-chunk of PNG */ if (strcmp("x_offs", text_ptr[i].key) == 0) sprite->x_offs = strtol(text_ptr[i].text, NULL, 0); if (strcmp("y_offs", text_ptr[i].key) == 0) sprite->y_offs = strtol(text_ptr[i].text, NULL, 0); } sprite->height = png_get_image_height(png_ptr, info_ptr); sprite->width = png_get_image_width(png_ptr, info_ptr); sprite->AllocateData(sprite->width * sprite->height); } bit_depth = png_get_bit_depth(png_ptr, info_ptr); colour_type = png_get_color_type(png_ptr, info_ptr); if (mask && (bit_depth != 8 || colour_type != PNG_COLOR_TYPE_PALETTE)) { DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't a 8 bit palette image", id); return true; } if (!mask) { if (bit_depth == 16) png_set_strip_16(png_ptr); if (colour_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); colour_type = PNG_COLOR_TYPE_RGB; } if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); colour_type = PNG_COLOR_TYPE_RGB; } if (colour_type == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } pixelsize = sizeof(uint32); } else { pixelsize = sizeof(uint8); } png_bytep row_pointer = AllocaM(png_byte, png_get_image_width(png_ptr, info_ptr) * pixelsize); for (i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) { png_read_row(png_ptr, row_pointer, NULL); dst = sprite->data + i * png_get_image_width(png_ptr, info_ptr); for (uint x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) { if (mask) { if (row_pointer[x * sizeof(uint8)] != 0) { dst[x].r = 0; dst[x].g = 0; dst[x].b = 0; /* Alpha channel is used from the original image (to allow transparency in remap colours) */ dst[x].m = row_pointer[x * sizeof(uint8)]; } } else { dst[x].r = row_pointer[x * sizeof(uint32) + 0]; dst[x].g = row_pointer[x * sizeof(uint32) + 1]; dst[x].b = row_pointer[x * sizeof(uint32) + 2]; dst[x].a = row_pointer[x * sizeof(uint32) + 3]; dst[x].m = 0; } } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return true; }
Image* Image::LoadPNG( IFileReader* file ) { png_byte header[8]; if ( file->ReadByte( header, sizeof(header) ) == false ) { RETURN_ERROR( "failed to read png header from %s", file->GetFileName( ) ); } if ( png_sig_cmp(header, 0, 8) != 0 ) { RETURN_ERROR( "%s is not png format!", file->GetFileName( ) ); } png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( png_ptr == NULL ) { RETURN_ERROR( "png_create_read_struct returned 0" ); } // create png info struct 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_ERROR( "png_create_info_struct returned 0" ); } // create png info struct 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_ERROR( "error: png_create_info_struct returned 0" ); } // init png reading png_set_read_fn( png_ptr, file, png_read_callback ); // the code in this if statement gets called if libpng encounters an error if ( setjmp( png_jmpbuf( png_ptr ) ) ) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); RETURN_ERROR( "error from libpng" ); } // let libpng know you already read the first 8 bytes png_set_sig_bytes( png_ptr, 8 ); // read all the info up to the image data png_read_info( png_ptr, info_ptr ); // variables to pass to get info int bit_depth, color_type; png_uint_32 width, height; // get info about png png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL ); bool hasAlpha = false; if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( png_ptr ); hasAlpha = true; } // Expands PNG with less than 8bits per channel to 8bits. if ( bit_depth < 8 ) { png_set_packing ( png_ptr ); // Shrinks PNG with 16bits per color channel down to 8bits. } else if ( bit_depth == 16 ) { png_set_strip_16( png_ptr ); } // Indicates that image needs conversion to RGBA if needed. GLint format; switch ( color_type ) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( png_ptr ); format = hasAlpha ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGB: format = hasAlpha ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGBA: format = GL_RGBA; break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8( png_ptr ); format = hasAlpha ? GL_LUMINANCE_ALPHA:GL_LUMINANCE; break; case PNG_COLOR_TYPE_GA: png_set_expand_gray_1_2_4_to_8( png_ptr ); format = GL_LUMINANCE_ALPHA; break; default: format = 0; break; } // Update the png info struct. png_read_update_info( png_ptr, info_ptr ); // Row size in bytes. int rowbytes = (int)png_get_rowbytes( png_ptr, info_ptr ); // glTexImage2d requires rows to be 4-byte aligned rowbytes += 3 - ((rowbytes-1) % 4); // Allocate the image_data as a big block, to be given to opengl png_byte* image_data; image_data = new png_byte[rowbytes * height * sizeof(png_byte) + 15]; if (image_data == NULL) { delete[] image_data; png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); RETURN_ERROR( "could not allocate memory for PNG image data" ); } // row_pointers is for pointing to image_data for reading the png with libpng png_bytep* row_pointers = new png_bytep[height * sizeof(png_bytep)]; if (row_pointers == NULL) { delete[] image_data; delete[] row_pointers; png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); RETURN_ERROR( "could not allocate memory for PNG row pointers" ); } // set the individual row_pointers to point at the correct offsets of image_data for ( unsigned int i = 0; i < height; i++ ) { row_pointers[height - 1 - i] = image_data + i * rowbytes; } // read the png into image_data through row_pointers png_read_image( png_ptr, row_pointers ); png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); return new Image( width, height, format, image_data ); }
void read_png(unsigned char **block, png_uint_32 *width, png_uint_32 *height, FILE *file) { png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; unsigned row, x, y; int rowbytes; char *dst; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) { printf("\nERROR: read_png: Could not create read struct.\n"); exit(1); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { printf("\nERROR: read_png: Could not create info struct.\n"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); exit(1); } if (setjmp(png_ptr->jmpbuf)) { printf("\nERROR: read_png: fatal error.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_info **)0); /* free pointers before returning, if necessary */ free(png_ptr); free(info_ptr); exit(1); } /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, file); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, width, height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // printf("read_png: width=%d, height=%d, bit_depth=%d\n", width, height, bit_depth); // printf("read_png: color_type=%d, interlace_type=%d\n", color_type, interlace_type); // strip alpha information if (color_type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(png_ptr); } // /* tell libpng to strip 16 bit/color files down to 8 bits/color */ // png_set_strip_16(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); /* Expand paletted colors into true RGB triplets */ png_set_expand(png_ptr); png_start_read_image(png_ptr); /* The easiest way to read the image: */ rowbytes = png_get_rowbytes(png_ptr, info_ptr) * 3; row_pointers = (png_bytep *)malloc((*height) * sizeof(*row_pointers)); row_pointers[0] = (png_bytep)malloc(rowbytes * (*height) * 2); for(row = 1; row < (*height); row++) { row_pointers[row] = row_pointers[row - 1] + rowbytes*2; } /* Read the entire image in one go */ png_read_image(png_ptr, row_pointers); // we use fixed height here because block is of limited, fixed size // not fixed any more *block = realloc(*block, *height * *width * 3); // *block = malloc(*height * *width * 6); dst = *block; for(y = 0; y < *height; y++) { for(x = 0; x < *width * 3; x++) { *dst++ = row_pointers[y][x]; // *dst++ = 0; } } free(row_pointers[0]); free(row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* At this point you have read the entire image */ /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); }
static int open_png(const char *name, png_structp *png_ptr, png_infop *info_ptr, FILE **fp, png_uint_32 *width, png_uint_32 *height, png_byte *channels) { char resPath[256]; unsigned char header[8]; int color_type, bit_depth, result = 0; size_t bytesRead; snprintf(resPath, sizeof(resPath) - 1, "/res/images/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; *fp = fopen(resPath, "rb"); if (*fp == NULL) { result = -1; goto exit; } 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); png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, &color_type, NULL, NULL, NULL); *channels = png_get_channels(*png_ptr, *info_ptr); if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { /* 8-bit RGB images: great, nothing to do. */ } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { /* 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. */ png_set_expand_gray_1_2_4_to_8(*png_ptr); } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { /* paletted images: expand to 8-bit RGB. Note that we DON'T * currently expand the tRNS chunk (if any) to an alpha * channel, because minui doesn't support alpha channels * in general. */ png_set_palette_to_rgb(*png_ptr); *channels = 3; } else { fprintf(stderr, "minui doesn't support PNG depth %d channels %d " "color_type %d\n", bit_depth, *channels, color_type); result = -7; goto exit; } return result; exit: if (result < 0) png_destroy_read_struct(png_ptr, info_ptr, NULL); if (*fp != NULL) { fclose(*fp); *fp = NULL; } return result; }
/*! \brief Reads a PNG file and places the pixel data in the * passed array. * * \param filename The name of the file to read. * \param image The array of \ref Pixel data to read the image into. * \param width Variable used to return the width of the image. * \param height Variable used to return the height of the image. */ inline void readPNGFile(const std::string& filename, std::vector<uint8_t>& image, size_t& width, size_t& height, size_t& components) { std::ifstream pngFile(filename.c_str(), std::fstream::binary); if(!pngFile.is_open()) { std::stringstream strm; strm << "failed to open file '" << filename << "'"; throw std::runtime_error(strm.str().c_str()); } pngFile.exceptions(std::fstream::badbit | std::fstream::failbit); const size_t pngHeaderSize = 8; png_byte pngHeader[pngHeaderSize]; pngFile.read(reinterpret_cast<char*>(pngHeader), pngHeaderSize); if(png_sig_cmp(pngHeader, 0, pngHeaderSize)) { std::stringstream strm; strm << "failed to read '" << filename << "': not a png file"; throw std::runtime_error(strm.str().c_str()); } png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) throw std::runtime_error("failed to allocate png_struct"); png_infop pngInfo = png_create_info_struct(png); if(!pngInfo) { png_destroy_read_struct(&png, NULL, NULL); throw std::runtime_error("failed to allocate png_info_struct"); } png_infop pngEndInfo = png_create_info_struct(png); if(!pngEndInfo) { png_destroy_read_struct(&png, &pngInfo, NULL); throw std::runtime_error("failed to allocate png_info_struct"); } // set up error handling the hard way if(setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); throw std::runtime_error("libpng: failed to set up io"); } png_set_read_fn(png, static_cast<void*>(&pngFile), detail::read); png_set_sig_bytes(png, pngHeaderSize); png_read_info(png, pngInfo); if(png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGBA && png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGB) { png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); std::stringstream strm; strm << "unsupported color type in '" << filename << "'"; throw std::runtime_error(strm.str().c_str()); } width = png_get_image_width(png, pngInfo); height = png_get_image_height(png, pngInfo); components = png_get_channels(png, pngInfo); if ((components != 3) && (components != 4)) throw std::runtime_error("Unsupported number of components"); size_t bitDepth = png_get_bit_depth(png, pngInfo); if(bitDepth != 8) { png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); std::stringstream strm; strm << "failed to read '" << filename << "': invalid bit " << "depth: " << bitDepth; throw std::runtime_error(strm.str().c_str()); } size_t bytesPerRow = png_get_rowbytes(png, pngInfo); png_bytep* pngRows = new png_bytep[height]; png_bytep pngData = 0; image.resize(height * width * components); size_t offset = 0; png_bytep basePointer = reinterpret_cast<png_bytep>(&image[0]); for(size_t row = 0; row < height; ++row) { pngRows[row] = basePointer + offset; offset += bytesPerRow; } // set up error handling the hard way if(setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); delete[] pngData; delete[] pngRows; throw std::runtime_error("libpng: failed to read image"); } png_read_image(png, pngRows); png_read_end(png, pngEndInfo); // all went well, we can clean up now png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); delete[] pngData; delete[] pngRows; }
/*! \brief Writes a PNG file using the pixel data in the passed * array. * * \param filename The name of the file to create/overwrite. * \param image The array of \ref Pixel data to write out. * \param width The width of the image. * \param height The height of the image. * \param compressionLevel The level of compression requested from the PNG library. * \param disableFiltering Prevent the PNG library from filtering the output. * \param flip Flips the vertical ordering of the image (to allow easy saving of OpenGL renderings). */ inline void writePNGFile(const std::string& filename, std::vector<uint8_t >& image, size_t width, size_t height, size_t components, int compressionLevel = PNG_COMPRESSION_TYPE_DEFAULT, bool disableFiltering = false, bool flip = false) { if(image.size() != width * height * components) { std::stringstream strm; strm << "invalid input to writePNGFile(): " << "size mismatch of input vector (is " << image.size() << ", should be " << width << "x" << height << " = " << width * height; throw std::runtime_error(strm.str().c_str()); } if(compressionLevel < 0 || compressionLevel > 9) { std::stringstream strm; strm << "invalid input to writePNGFile(): " << "valid compression levels range from 0 to 9 (default: " << PNG_COMPRESSION_TYPE_DEFAULT << ")"; throw std::runtime_error(strm.str().c_str()); } std::ofstream pngFile(filename.c_str(), std::fstream::binary); if(!pngFile.is_open()) { std::stringstream strm; strm << "failed to open file '" << filename << "'"; throw std::runtime_error(strm.str().c_str()); } pngFile.exceptions(std::fstream::badbit | std::fstream::failbit); png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) throw std::runtime_error("failed to allocate png_struct"); png_infop pngInfo = png_create_info_struct(png); if(!pngInfo) { png_destroy_write_struct(&png, NULL); throw std::runtime_error("failed to allocate png_info_struct"); } // set up error handling the hard way if(setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &pngInfo); throw std::runtime_error("libpng: failed to set up io"); } png_set_write_fn(png, static_cast<void*>(&pngFile), detail::write, detail::flush); switch (components) { case 3: png_set_IHDR(png, pngInfo, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); break; case 4: png_set_IHDR(png, pngInfo, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); break; default: throw std::runtime_error("Unsupported number of components"); } if(disableFiltering) png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); if(compressionLevel != PNG_COMPRESSION_TYPE_DEFAULT) png_set_compression_level(png, compressionLevel); png_write_info(png, pngInfo); size_t bytesPerRow = png_get_rowbytes(png, pngInfo); png_bytep* pngRows = new png_bytep[height]; if(image.size() != (height * bytesPerRow)) { std::stringstream strm; strm << "writePNGFile(): invalid size of input data"; throw std::runtime_error(strm.str().c_str()); } size_t offset = 0; png_bytep basePointer = reinterpret_cast<png_bytep>(&image[0]); if (flip) for(int row = height - 1; row >= 0; --row) { pngRows[row] = basePointer + offset; offset += bytesPerRow; } else for(size_t row = 0; row < height; ++row) { pngRows[row] = basePointer + offset; offset += bytesPerRow; } // set up error handling the hard way if(setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &pngInfo); delete[] pngRows; throw std::runtime_error("libpng: failed to write image"); } png_write_image(png, pngRows); png_write_end(png, NULL); // all went well, we can clean up now png_destroy_write_struct(&png, &pngInfo); delete[] pngRows; }
/** * @brief internal function used to read a PNG file into an array * * @todo don't loose 16bit info * * @param fname PNG file name, "-" means stdin * @param nx, ny, nc pointers to variables to be filled * with the number of columns, lines and channels of the image * @param transform a PNG_TRANSFORM to be added to the default read transforms * @param dtype identifier for the data type to be used for output * @return pointer to an allocated array of pixels, * or NULL if an error happens */ static void *read_png_raw(const char *fname, size_t * nx, size_t * ny, size_t * nc, int transform, int dtype) { png_byte png_sig[PNG_SIG_LEN]; png_structp png_ptr; png_infop info_ptr; png_bytepp row_pointers; png_bytep row_ptr; /* volatile : because of setjmp/longjmp */ FILE *volatile fp = NULL; void *data = NULL; unsigned char *data_u8 = NULL; unsigned char *data_u8_ptr = NULL; float *data_f32 = NULL; float *data_f32_ptr = NULL; size_t size; size_t i, j, k; /* parameters check */ if (NULL == fname || NULL == nx || NULL == ny || NULL == nc) return NULL; if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype) return NULL; /* open the PNG input file */ if (0 == strcmp(fname, "-")) fp = stdin; else if (NULL == (fp = fopen(fname, "rb"))) return NULL; /* read in some of the signature bytes and check this signature */ if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp)) || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN)) return read_png_abort(fp, NULL, NULL); /* * create and initialize the png_struct * with the default stderr and error handling */ if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) return read_png_abort(fp, NULL, NULL); /* allocate/initialize the memory for image information */ if (NULL == (info_ptr = png_create_info_struct(png_ptr))) return read_png_abort(fp, &png_ptr, NULL); /* set error handling */ if (0 != setjmp(png_jmpbuf(png_ptr))) /* if we get here, we had a problem reading the file */ /* free all of the memory associated with the png_ptr and info_ptr */ return read_png_abort(fp, &png_ptr, &info_ptr); /* set up the input control using standard C streams */ png_init_io(png_ptr, fp); /* let libpng know that some bytes have been read */ png_set_sig_bytes(png_ptr, PNG_SIG_LEN); /* * set the read filter transforms, to get 8bit RGB whatever the * original file may contain: * PNG_TRANSFORM_STRIP_16 strip 16-bit samples to 8 bits * PNG_TRANSFORM_PACKING expand 1, 2 and 4-bit * samples to bytes */ transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING); /* read in the entire image at once */ png_read_png(png_ptr, info_ptr, transform, NULL); /* get image informations */ *nx = (size_t) png_get_image_width(png_ptr, info_ptr); *ny = (size_t) png_get_image_height(png_ptr, info_ptr); *nc = (size_t) png_get_channels(png_ptr, info_ptr); row_pointers = png_get_rows(png_ptr, info_ptr); /* * allocate the output data RGB array * deinterlace and convert png RGB RGB RGB 8bit to RRR GGG BBB * the image is deinterlaced layer after layer * this generic loop also works for one single channel */ size = *nx * *ny * *nc; switch (dtype) { case IO_PNG_U8: if (NULL == (data_u8 = (unsigned char *) malloc(size * sizeof(unsigned char)))) return read_png_abort(fp, &png_ptr, &info_ptr); data = (void *) data_u8; for (k = 0; k < *nc; k++) { /* channel loop */ data_u8_ptr = data_u8 + (size_t) (*nx * *ny * k); for (j = 0; j < *ny; j++) { /* row loop */ row_ptr = row_pointers[j] + k; for (i = 0; i < *nx; i++) { /* pixel loop */ *data_u8_ptr++ = (unsigned char) *row_ptr; row_ptr += *nc; } } } break; case IO_PNG_F32: if (NULL == (data_f32 = (float *) malloc(size * sizeof(float)))) return read_png_abort(fp, &png_ptr, &info_ptr); data = (void *) data_f32; for (k = 0; k < *nc; k++) { /* channel loop */ data_f32_ptr = data_f32 + (size_t) (*nx * *ny * k); for (j = 0; j < *ny; j++) { /* row loop */ row_ptr = row_pointers[j] + k; for (i = 0; i < *nx; i++) { /* pixel loop */ *data_f32_ptr++ = (float) *row_ptr; row_ptr += *nc; } } } break; } /* clean up and free any memory allocated, close the file */ (void) read_png_abort(fp, &png_ptr, &info_ptr); return data; }
void save_as_png(T & file, std::vector<mapnik::rgb> const& palette, mapnik::image_data_8 const& image, unsigned width, unsigned height, unsigned color_depth, int compression, int strategy, std::vector<unsigned> const&alpha) { png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); return; } jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>); png_set_compression_level(png_ptr, compression); png_set_compression_strategy(png_ptr, strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr,width,height,color_depth, PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_color* pal = const_cast<png_color*>(reinterpret_cast<const png_color*>(&palette[0])); png_set_PLTE(png_ptr, info_ptr, pal, palette.size()); // make transparent lowest indexes, so tRNS is small if (alpha.size()>0) { std::vector<png_byte> trans(alpha.size()); unsigned alphaSize=0;//truncate to nonopaque values for(unsigned i=0; i < alpha.size(); i++) { trans[i]=alpha[i]; if (alpha[i]<255) alphaSize = i+1; } if (alphaSize>0) png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0); } png_write_info(png_ptr, info_ptr); for (unsigned i=0;i<height;i++) { png_write_row(png_ptr,(png_bytep)image.getRow(i)); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); }
static HPDF_STATUS LoadPngData (HPDF_Dict image, HPDF_Xref xref, HPDF_Stream png_data, HPDF_BOOL delayed_loading) { HPDF_STATUS ret = HPDF_OK; png_uint_32 width, height; int bit_depth, color_type; png_structp png_ptr = NULL; png_infop info_ptr = NULL; HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n")); /* create read_struct. */ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, image->error, PngErrorFunc, PngErrorFunc); if (png_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); return HPDF_FAILD_TO_ALLOC_MEM; } /* create info-struct */ info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); goto Exit; } png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK); png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc); /* reading info structure. */ png_read_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* 16bit images are not supported. */ if (bit_depth == 16) { png_set_strip_16(png_ptr); } png_read_update_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } /* check palette-based images for transparent areas and load them immediately if found */ if (xref && PNG_COLOR_TYPE_PALETTE & color_type) { png_bytep trans; int num_trans; HPDF_Dict smask; png_bytep smask_data; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { goto no_transparent_color_in_palette; } smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); ret += CreatePallet(image, png_ptr, info_ptr); ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } no_transparent_color_in_palette: /* read images with alpha channel right away we have to do this because image transparent mask must be added to the Xref */ if (xref && PNG_COLOR_MASK_ALPHA & color_type) { HPDF_Dict smask; png_bytep smask_data; smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); } else { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); } ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } /* if the image has color palette, copy the pallet of the image to * create color map. */ if (color_type == PNG_COLOR_TYPE_PALETTE) ret = CreatePallet(image, png_ptr, info_ptr); else if (color_type == PNG_COLOR_TYPE_GRAY) ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); else ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); if (ret != HPDF_OK) goto Exit; /* read image-data * if the image is interlaced, read whole image at once. * if delayed_loading is HPDF_TRUE, the data does not load this phase. */ if (delayed_loading) { image->before_write_fn = PngBeforeWrite; image->after_write_fn = PngAfterWrite; } else { if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE) ret = ReadPngData_Interlaced(image, png_ptr, info_ptr); else ret = ReadPngData(image, png_ptr, info_ptr); if (ret != HPDF_OK) goto Exit; } /* setting the info of the image. */ if (HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth) != HPDF_OK) goto Exit; /* clean up */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; Exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (ret != HPDF_OK) { return ret; } return image->error->error_no; }
boolean mgSaveToPng(FILE *png_file, struct memGfx *mg, boolean useTransparency) /* Save PNG to an already open file. * If useTransparency, then the first color in memgfx's colormap/palette is * assumed to be the image background color, and pixels of that color * are made transparent. */ /* Reference: http://libpng.org/pub/png/libpng-1.2.5-manual.html */ { if (!png_file || !mg) errAbort("mgSaveToPng: called with a NULL"); png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, // don't need pointer to data for err/warn handlers pngAbort, pngWarn); if (!png) { errAbort("png_write_struct failed"); return FALSE; } png_infop info = png_create_info_struct(png); if (!info) { errAbort("png create_info_struct failed"); png_destroy_write_struct(&png, NULL); return FALSE; } // If setjmp returns nonzero, it means png_error is returning control here. // But that should not happen because png_error should call pngAbort which calls errAbort. if (setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &info); fclose(png_file); errAbort("pngwrite: setjmp nonzero. " "why didn't png_error..pngAbort..errAbort stop execution before this errAbort?"); return FALSE; } // Configure PNG output params: png_init_io(png, png_file); #ifdef COLOR32 png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); #else png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png, info, (png_color *)(mg->colorMap), // png_color is same as struct rgbColor! mg->colorsUsed); #endif #ifndef COLOR32 if (useTransparency) { // First palette color is assumed to be background/transparent, so // that's the only one we need in the parallel array opacities[]. png_byte opacities[] = {0}; int num_opacities = ArraySize(opacities); png_color_16p nonPalette_opacities_values = NULL; // n/a for us, we're using palette png_set_tRNS(png, info, opacities, num_opacities, nonPalette_opacities_values); } #endif // Write header/params, write pixels, close and clean up. // PNG wants a 2D array of pointers to byte offsets into palette/colorMap. // mg has a 1D array of byte offsets. Make row pointers for PNG: png_byte **row_pointers = needMem(mg->height * sizeof(png_byte *)); int i; for (i = 0; i < mg->height; i++) row_pointers[i] = (unsigned char *)&(mg->pixels[i*mg->width]); png_set_rows(png, info, row_pointers); png_write_png(png, info, PNG_TRANSFORM_IDENTITY, // no transform NULL); // unused as of PNG 1.2 png_destroy_write_struct(&png, &info); return TRUE; }
/////////////////////////////////////////////////////////////////////// // code based on example code from // http://zarb.org/~gc/html/libpng.html /////////////////////////////////////////////////////////////////////// void FIELD_2D::readPNG(string filename) { cout << " Reading in PNG file " << filename.c_str() << endl; int width, height; png_structp png_ptr; png_infop info_ptr; png_byte color_type; png_byte bit_depth; int number_of_passes; png_bytep* row_pointers; png_byte header[8]; // 8 is the maximum size that can be checked // open file and test for it being a png FILE *fp = fopen(filename.c_str(), "rb"); if (fp == NULL) { printf("[read_png_file] File %s could not be opened for reading\n", filename.c_str()); exit(0); } fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) printf("[read_png_file] File %s is not recognized as a PNG file\n", filename.c_str()); // initialize stuff png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) printf("[read_png_file] png_create_read_struct failed\n"); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) printf("[read_png_file] png_create_info_struct failed\n"); if (setjmp(png_jmpbuf(png_ptr))) printf("[read_png_file] Error during init_io\n"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // read file if (setjmp(png_jmpbuf(png_ptr))) printf("[read_png_file] Error during read_image\n"); row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); for (int y = 0; y < height; y++) row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); png_read_image(png_ptr, row_pointers); fclose(fp); // push the data into the member variables _xRes = width; _yRes = height; _totalCells = _xRes * _yRes; if (_data) delete[] _data; _data = new float[_totalCells]; if (color_type == PNG_COLOR_TYPE_GRAY) { cout << " PNG color type is gray" << endl; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) (*this)(x,y) = row_pointers[height - 1 - y][x] / 255.0; } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { cout << " PNG color type is gray with alpha" << endl; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) (*this)(x,y) = row_pointers[height - 1 - y][2 * x] / 255.0; } else if (color_type == PNG_COLOR_TYPE_RGB) { cout << " PNG color type is RGB" << endl; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) { float r = (float)row_pointers[height - 1 - y][3 * x] / 255.0; float g = (float)row_pointers[height - 1 - y][3 * x + 1] / 255.0; float b = (float)row_pointers[height - 1 - y][3 * x + 2] / 255.0; (*this)(x,y) = (r + g + b) / 3.0; } } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { cout << " PNG color type is RGB with alpha" << endl; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) { float r = (float)row_pointers[height - 1 - y][4 * x] / 255.0; float g = (float)row_pointers[height - 1 - y][4 * x + 1] / 255.0; float b = (float)row_pointers[height - 1 - y][4 * x + 2] / 255.0; (*this)(x,y) = (r + g + b) / 3.0; } } else { cout << " PNG color type " << (int)color_type << " is unsupported! " << endl; exit(0); } for (int y = 0; y < height; y++) free(row_pointers[y]); free(row_pointers); }
HBITMAP PngByteToBmpHandle(VBuf *vbuf) { png_struct *png = NULL; png_info *info = NULL; HBITMAP hBmp = NULL; BITMAPINFO *bmi = NULL; png_byte **row = NULL; BYTE *data = NULL; HWND hWnd = ::GetDesktopWindow(); HDC hDc = NULL; int line_size, aligned_line_size, header_size; VBuf bmpVbuf; if (vbuf->Size() < PNG_SIG_SIZE || !png_check_sig(vbuf->Buf(), PNG_SIG_SIZE)) return NULL; if (!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL; if (!(info = png_create_info_struct(png))) goto END; if (setjmp(png_jmpbuf(png))) goto END; png_set_user_limits(png, 15000, 10000); // 15,000 * 10,000 pix png_set_read_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_rfunc); png_read_png(png, info, PNG_TRANSFORM_BGR, NULL); if (info->bit_depth > 8) goto END; // not support line_size = info->width * info->channels * ALIGN_SIZE(info->bit_depth, 8) / 8; aligned_line_size = ALIGN_SIZE(line_size, 4); header_size = sizeof(BITMAPV5HEADER) + sizeof(RGBQUAD) * info->num_palette; if (!bmpVbuf.AllocBuf(header_size + aligned_line_size * info->height)) goto END; bmi = (BITMAPINFO *)bmpVbuf.Buf(); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biSizeImage = aligned_line_size * info->height; bmi->bmiHeader.biWidth = info->width; bmi->bmiHeader.biHeight = -(int)info->height; bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biCompression = BI_RGB; if (info->color_type == PNG_COLOR_TYPE_PALETTE) { bmi->bmiHeader.biBitCount = info->bit_depth; bmi->bmiHeader.biClrUsed = info->num_palette; for (int i=0; i < info->num_palette; i++) { bmi->bmiColors[i].rgbRed = info->palette[i].red; bmi->bmiColors[i].rgbGreen = info->palette[i].green; bmi->bmiColors[i].rgbBlue = info->palette[i].blue; } } else { bmi->bmiHeader.biBitCount = info->bit_depth * info->channels; if (info->channels == 4) { bmi->bmiHeader.biSize = sizeof(BITMAPV5HEADER); BITMAPV5HEADER *bm5 = (BITMAPV5HEADER*)bmi; bm5->bV5Compression = BI_BITFIELDS; bm5->bV5RedMask = 0x00FF0000; bm5->bV5GreenMask = 0x0000FF00; bm5->bV5BlueMask = 0x000000FF; bm5->bV5AlphaMask = 0xFF000000; } } if (!(row = png_get_rows(png, info))) goto END; data = bmpVbuf.Buf() + header_size; u_int i; for (i=0; i < info->height; i++) { memcpy(data + aligned_line_size * i, row[i], line_size); } if (!(hDc = ::GetDC(hWnd))) goto END; hBmp = ::CreateDIBitmap(hDc, (BITMAPINFOHEADER *)bmi, CBM_INIT, data, bmi, DIB_RGB_COLORS); if (hDc) ::ReleaseDC(hWnd, hDc); END: png_destroy_read_struct(&png, &info, 0); return hBmp; }
/////////////////////////////////////////////////////////////////////// // code based on example code from // http://zarb.org/~gc/html/libpng.html /////////////////////////////////////////////////////////////////////// void FIELD_2D::writePNG(string filename) { cout << " Writing out PNG file " << filename.c_str() << endl; int width = _xRes; int height = _yRes; // copy image data into pointers png_bytep* row_pointers; row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); for (int y = 0; y < height; y++) row_pointers[y] = (png_byte*) malloc(sizeof(png_byte) * width); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { float value = (*this)(x,y) * 255; value = (value > 255) ? 255 : value; value = (value < 0) ? 0 : value; row_pointers[height - 1 - y][x] = (unsigned char)value; } png_structp png_ptr; png_infop info_ptr; png_byte color_type = PNG_COLOR_TYPE_GRAY; png_byte bit_depth = 8; // create file FILE *fp = fopen(filename.c_str(), "wb"); if (fp == NULL) printf("[write_png_file] File %s could not be opened for writing\n", filename.c_str()); // initialize stuff png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) printf("[write_png_file] png_create_write_struct failed\n"); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) printf("[write_png_file] png_create_info_struct failed\n"); if (setjmp(png_jmpbuf(png_ptr))) printf("[write_png_file] Error during init_io\n"); png_init_io(png_ptr, fp); // write header if (setjmp(png_jmpbuf(png_ptr))) printf("[write_png_file] Error during writing header\n"); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); // write bytes if (setjmp(png_jmpbuf(png_ptr))) printf("[write_png_file] Error during writing bytes\n"); png_write_image(png_ptr, row_pointers); // end write if (setjmp(png_jmpbuf(png_ptr))) printf("[write_png_file] Error during end of write\n"); png_write_end(png_ptr, NULL); // cleanup heap allocation for (int y=0; y<height; y++) free(row_pointers[y]); free(row_pointers); fclose(fp); }
Texture* PNGLoader::load(string fileName, bool mipMaps) { png_structp png_ptr; png_infop info_ptr; unsigned long sig_read = 0; int bit_depth, color_type, interlace_type; png_uint_32 width, height; unsigned short components; // Load file from disk FILE* file = fopen(fileName.c_str(), "rb"); if (file == NULL) return NULL; // Create png read and info structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(file); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(NULL); return NULL; } // Set up the function to read bytes from file stream png_set_read_fn(png_ptr, file, png_read_file_data); png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*) &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Adjust image format if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (bit_depth < 8) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == 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 (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*)&height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { #ifdef __BIG_ENDIAN__ png_set_swap_alpha(png_ptr); #else png_set_bgr(png_ptr); #endif } png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*) &height, &bit_depth, &color_type, NULL, NULL, NULL); // Store the components amount if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) components = 32; else components = 24; // Start reading from buffer png_byte** row = new png_byte*[height]; png_byte* buffer = new png_byte[width * height * (components / 8)]; png_byte* it = buffer; for (png_uint_32 i = 0; i < height; i++) { row[i] = it; it += width * (components / 8); } png_read_image(png_ptr, row); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); Texture* tex = new Texture(buffer, width, height, components, mipMaps); delete [] row; delete [] buffer; fclose(file); return tex; }
/* Writes a non-interlaced, no-frills PNG, taking the usual save_xyz * parameters. Returns non-zero on error. */ bool _al_save_png_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp) { jmp_buf jmpbuf; png_structp png_ptr = NULL; png_infop info_ptr = NULL; int colour_type; /* Create and initialize the png_struct with the * desired error handler functions. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) goto Error; /* Allocate/initialize the image information data. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto Error; /* Set error handling. */ if (setjmp(jmpbuf)) { goto Error; } png_set_error_fn(png_ptr, jmpbuf, user_error_fn, NULL); /* Use packfile routines. */ png_set_write_fn(png_ptr, fp, (png_rw_ptr) write_data, flush_data); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. */ colour_type = PNG_COLOR_TYPE_RGB_ALPHA; /* Set compression level. */ png_set_compression_level(png_ptr, _al_png_compression_level); png_set_IHDR(png_ptr, info_ptr, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 8, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Optionally write comments into the image ... Nah. */ /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* Once we write out the header, the compression type on the text * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again * at the end. */ if (!save_rgba(png_ptr, bmp)) goto Error; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return true; Error: if (png_ptr) { if (info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); else png_destroy_write_struct(&png_ptr, NULL); } return false; }
static int png_load_file(FILE *infile, unsigned long *pWidth, unsigned long *pHeight, unsigned char *red, unsigned char *green, unsigned char *blue, int *pChannels, unsigned long *pRowbytes, unsigned char **image_data) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; int bit_depth, color_type; png_uint_32 width, height; unsigned char sig[8]; png_color_16p pBackground; double gamma; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; fread(sig, 1, 8, infile); if (png_sig_cmp(sig, 0, 8)) return 1; /* bad signature */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return 4; /* out of memory */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 4; /* out of memory */ } /* setjmp() must be called in every function that calls a PNG-reading * libpng function */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 2; } png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (pWidth) *pWidth = width; if (pHeight) *pHeight = height; if (red && green && blue) { if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { png_get_bKGD(png_ptr, info_ptr, &pBackground); if (bit_depth == 16) { *red = pBackground->red >> 8; *green = pBackground->green >> 8; *blue = pBackground->blue >> 8; } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { if (bit_depth == 1) *red = *green = *blue = pBackground->gray ? 255 : 0; else if (bit_depth == 2) *red = *green = *blue = (255 / 3) * pBackground->gray; else /* bit_depth == 4 */ *red = *green = *blue = (255 / 15) * pBackground->gray; } else { *red = (unsigned char) pBackground->red; *green = (unsigned char) pBackground->green; *blue = (unsigned char) pBackground->blue; } }
// Reads the header and initializes the output fields, if not NULL. // // @param stream Input data. Will be read to get enough information to properly // setup the codec. // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is // expected to continue to own it for the lifetime of the png_ptr. // @param outCodec Optional output variable. If non-NULL, will be set to a new // SkPngCodec on success. // @param png_ptrp Optional output variable. If non-NULL, will be set to a new // png_structp on success. // @param info_ptrp Optional output variable. If non-NULL, will be set to a new // png_infop on success; // @return true on success, in which case the caller is responsible for calling // png_destroy_read_struct(png_ptrp, info_ptrp). // If it returns false, the passed in fields (except stream) are unchanged. static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec, png_structp* png_ptrp, png_infop* info_ptrp) { // The image is known to be a PNG. Decode enough to know the SkImageInfo. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_fn, sk_warning_fn); if (!png_ptr) { return false; } AutoCleanPng autoClean(png_ptr); png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr) { return false; } autoClean.setInfoPtr(info_ptr); // FIXME: Could we use the return value of setjmp to specify the type of // error? if (setjmp(png_jmpbuf(png_ptr))) { return false; } png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. // This needs to be installed before we read the png header. Android may store ninepatch // chunks in the header. if (chunkReader) { png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk); } #endif // 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_uint_32 origWidth, origHeight; int bitDepth, encodedColorType; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, &encodedColorType, nullptr, nullptr, nullptr); // Tell libpng to strip 16 bit/color files down to 8 bits/color. // TODO: Should we handle this in SkSwizzler? Could this also benefit // RAW decodes? if (bitDepth == 16) { SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); png_set_strip_16(png_ptr); } // Now determine the default colorType and alphaType and set the required transforms. // Often, we depend on SkSwizzler to perform any transforms that we need. However, we // still depend on libpng for many of the rare and PNG-specific cases. SkEncodedInfo::Color color; SkEncodedInfo::Alpha alpha; switch (encodedColorType) { case PNG_COLOR_TYPE_PALETTE: // Extract multiple pixels with bit depths of 1, 2, and 4 from a single // byte into separate bytes (useful for paletted and grayscale images). if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? png_set_packing(png_ptr); } color = SkEncodedInfo::kPalette_Color; // Set the alpha depending on if a transparency chunk exists. alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha; break; case PNG_COLOR_TYPE_RGB: if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // Convert to RGBA if transparency chunk exists. png_set_tRNS_to_alpha(png_ptr); color = SkEncodedInfo::kRGBA_Color; alpha = SkEncodedInfo::kBinary_Alpha; } else { color = SkEncodedInfo::kRGB_Color; alpha = SkEncodedInfo::kOpaque_Alpha; } break; case PNG_COLOR_TYPE_GRAY: // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? 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); color = SkEncodedInfo::kGrayAlpha_Color; alpha = SkEncodedInfo::kBinary_Alpha; } else { color = SkEncodedInfo::kGray_Color; alpha = SkEncodedInfo::kOpaque_Alpha; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: color = SkEncodedInfo::kGrayAlpha_Color; alpha = SkEncodedInfo::kUnpremul_Alpha; break; case PNG_COLOR_TYPE_RGBA: color = SkEncodedInfo::kRGBA_Color; alpha = SkEncodedInfo::kUnpremul_Alpha; break; default: // All the color types have been covered above. SkASSERT(false); color = SkEncodedInfo::kRGBA_Color; alpha = SkEncodedInfo::kUnpremul_Alpha; } int numberPasses = png_set_interlace_handling(png_ptr); autoClean.release(); if (png_ptrp) { *png_ptrp = png_ptr; } if (info_ptrp) { *info_ptrp = info_ptr; } if (outCodec) { sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr); if (!colorSpace) { // Treat unmarked pngs as sRGB. colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); } SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8); SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace); if (SkEncodedInfo::kOpaque_Alpha == alpha) { png_color_8p sigBits; if (png_get_sBIT(png_ptr, info_ptr, &sigBits)) { if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) { // Recommend a decode to 565 if the sBIT indicates 565. imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType); } } } if (1 == numberPasses) { *outCodec = new SkPngNormalCodec(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth); } else { *outCodec = new SkPngInterlacedCodec(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses); } } return true; }
int read_header(const char *filename, dt_imageio_png_t *png) { png->f = fopen(filename, "rb"); if(!png->f) return 1; #define NUM_BYTES_CHECK (8) png_byte dat[NUM_BYTES_CHECK]; size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f); if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK)) { fclose(png->f); return 1; } png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png->png_ptr) { fclose(png->f); return 1; } png->info_ptr = png_create_info_struct(png->png_ptr); if(!png->info_ptr) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, NULL, NULL); return 1; } if(setjmp(png_jmpbuf(png->png_ptr))) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); return 1; } png_init_io(png->png_ptr, png->f); // we checked some bytes png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK); // image info png_read_info(png->png_ptr, png->info_ptr); png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr); png->color_type = png_get_color_type(png->png_ptr, png->info_ptr); // image input transformations // palette => rgb if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr); // 1, 2, 4 bit => 8 bit if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png->png_ptr); png->bit_depth = 8; } // strip alpha channel if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr); // grayscale => rgb if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png->png_ptr); // reflect changes png_read_update_info(png->png_ptr, png->info_ptr); // png->bytespp = 3*bit_depth/8; png->width = png_get_image_width(png->png_ptr, png->info_ptr); png->height = png_get_image_height(png->png_ptr, png->info_ptr); #undef NUM_BYTES_CHECK return 0; }
Py::Object Image::write_png(const Py::Tuple& args) { //small memory leak in this function - JDH 2004-06-08 _VERBOSE("Image::write_png"); args.verify_length(1); FILE *fp = NULL; Py::Object py_fileobj = Py::Object(args[0]); if (py_fileobj.isString()) { std::string fileName = Py::String(py_fileobj); const char *file_name = fileName.c_str(); if ((fp = fopen(file_name, "wb")) == NULL) throw Py::RuntimeError( Printf("Could not open file %s", file_name).str() ); } else { PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write"); if (!(write_method && PyCallable_Check(write_method))) { Py_XDECREF(write_method); throw Py::TypeError("Object does not appear to be a path or a Python file-like object"); } Py_XDECREF(write_method); } png_structp png_ptr; png_infop info_ptr; struct png_color_8_struct sig_bit; png_uint_32 row=0; //todo: allocate on heap png_bytep *row_pointers = NULL; std::pair<agg::int8u*,bool> bufpair; bufpair.first = NULL; bufpair.second = false; try { row_pointers = new png_bytep[rowsOut]; if (!row_pointers) throw Py::RuntimeError("Out of memory"); bufpair = _get_output_buffer(); for (row = 0; row < rowsOut; ++row) row_pointers[row] = bufpair.first + row * colsOut * 4; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) throw Py::RuntimeError("Could not create write struct"); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) throw Py::RuntimeError("Could not create info struct"); if (setjmp(png_ptr->jmpbuf)) throw Py::RuntimeError("Error building image"); if (fp) { png_init_io(png_ptr, fp); } else { png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(), &write_png_data, &flush_png_data); } png_set_IHDR(png_ptr, info_ptr, colsOut, rowsOut, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // this a a color image! sig_bit.gray = 0; sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; /* if the image has an alpha channel then */ sig_bit.alpha = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); } catch (...) { if (bufpair.second) delete [] bufpair.first; if (fp) fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; throw; } if (fp) fclose(fp); delete [] row_pointers; if (bufpair.second) delete [] bufpair.first; return Py::Object(); }
int writePng( PIXEL ** matrix, int width, int height) { png_structp png_ptr; png_infop info_ptr; png_bytep * row_pointers; int i,j,x,y; /* create file */ FILE *fp = fopen("terrain.png", "wb"); if (!fp) //abort_("[write_png_file] File %s could not be opened for writing", "decoded.png"); return -1; /* initialize stuff */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) //abort_("[write_png_file] png_create_write_struct failed"); return -1; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) //abort_("[write_png_file] png_create_info_struct failed"); return -1; if (setjmp(png_jmpbuf(png_ptr))) //abort_("[write_png_file] Error during init_io"); return -1; png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) //abort_("[write_png_file] Error during writing header"); return -1; png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); /* init buffer */ row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height ); for (y=0; y<height; y++) row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); /* COPY BUFFER */ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) //abort_("[process_file] input file is PNG_COLOR_TYPE_RGB but must be PNG_COLOR_TYPE_RGBA " // "(lacks the alpha channel)"); return -1; if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA) //abort_("[process_file] color_type of input file must be PNG_COLOR_TYPE_RGBA (%d) (is %d)", // PNG_COLOR_TYPE_RGBA, png_get_color_type(png_ptr, info_ptr)); return -1; for (y=0; y<height; y++) { png_byte* row = row_pointers[y]; for (x=0; x<width; x++) { //std::cout << x << " " << y <<"\n"; png_byte* ptr = &(row[x*4]); ptr[0] = matrix[x][y].Red; ptr[1] = matrix[x][y].Green; ptr[2] = matrix[x][y].Blue; ptr[3] = 255; } } /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) //abort_("[write_png_file] Error during writing bytes"); return -1; png_write_image(png_ptr, row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) //abort_("[write_png_file] Error during end of write"); return -1; png_write_end(png_ptr, NULL); /* cleanup heap allocation */ for (y=0; y<height; y++) free(row_pointers[y]); free(row_pointers); fclose(fp); }
Py::Object _image_module::readpng(const Py::Tuple& args) { args.verify_length(1); std::string fname = Py::String(args[0]); png_byte header[8]; // 8 is the maximum size that can be checked FILE *fp = fopen(fname.c_str(), "rb"); if (!fp) throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str()); if (fread(header, 1, 8, fp) != 8) throw Py::RuntimeError("_image_module::readpng: error reading PNG header"); if (png_sig_cmp(header, 0, 8)) throw Py::RuntimeError("_image_module::readpng: file not recognized as a PNG file"); /* initialize stuff */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) throw Py::RuntimeError("_image_module::readpng: png_create_read_struct failed"); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) throw Py::RuntimeError("_image_module::readpng: png_create_info_struct failed"); if (setjmp(png_jmpbuf(png_ptr))) throw Py::RuntimeError("_image_module::readpng: error during init_io"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = info_ptr->width; png_uint_32 height = info_ptr->height; // convert misc color types to rgb for simplicity if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); int bit_depth = info_ptr->bit_depth; if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); bool rgba = info_ptr->color_type == PNG_COLOR_TYPE_RGBA; if ( (info_ptr->color_type != PNG_COLOR_TYPE_RGB) && !rgba) { std::cerr << "Found color type " << (int)info_ptr->color_type << std::endl; throw Py::RuntimeError("_image_module::readpng: cannot handle color_type"); } /* read file */ if (setjmp(png_jmpbuf(png_ptr))) throw Py::RuntimeError("_image_module::readpng: error during read_image"); png_bytep *row_pointers = new png_bytep[height]; png_uint_32 row; for (row = 0; row < height; row++) row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)]; png_read_image(png_ptr, row_pointers); int dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols dimensions[2] = 4; PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(3, dimensions, PyArray_FLOAT); for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { png_byte* ptr = (rgba) ? &(row[x*4]) : &(row[x*3]); size_t offset = y*A->strides[0] + x*A->strides[1]; //if ((y<10)&&(x==10)) std::cout << "r = " << ptr[0] << " " << ptr[0]/255.0 << std::endl; *(float*)(A->data + offset + 0*A->strides[2]) = ptr[0]/255.0; *(float*)(A->data + offset + 1*A->strides[2]) = ptr[1]/255.0; *(float*)(A->data + offset + 2*A->strides[2]) = ptr[2]/255.0; *(float*)(A->data + offset + 3*A->strides[2]) = rgba ? ptr[3]/255.0 : 1.0; } } //free the png memory png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); for (row = 0; row < height; row++) delete [] row_pointers[row]; delete [] row_pointers; return Py::asObject((PyObject*)A); }
/* TODO: I wonder why this function ALWAYS returns 0 */ int loadPNG(ePtr<gPixmap> &result, const char *filename, int accel) { if (pixmapFromTable(result, filename) == 0) return 0; CFile fp(filename, "rb"); if (!fp) { eDebug("[ePNG] couldn't open %s", filename ); return 0; } { __u8 header[8]; if (!fread(header, 8, 1, fp)) { eDebug("[ePNG] failed to get png header"); return 0; } if (png_sig_cmp(header, 0, 8)) { eDebug("[ePNG] header size mismatch"); return 0; } } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { eDebug("[ePNG] failed to create read struct"); return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { eDebug("[ePNG] failed to create info struct"); png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { eDebug("[ePNG] failed to create end info struct"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { eDebug("[ePNG] png setjump failed or activated"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); result = 0; return 0; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth; int color_type; int interlace_type; int channels; int trns; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, 0, 0); channels = png_get_channels(png_ptr, info_ptr); trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); //eDebug("[ePNG] %s: before %dx%dx%dbpcx%dchan coltyp=%d", filename, (int)width, (int)height, bit_depth, channels, color_type); /* * gPixmaps use 8 bits per channel. rgb pixmaps are stored as abgr. * So convert 1,2 and 4 bpc to 8bpc images that enigma can blit * so add 'empty' alpha channel * Expand G+tRNS to GA, RGB+tRNS to RGBA */ 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 && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && trns) png_set_tRNS_to_alpha(png_ptr); if ((color_type == PNG_COLOR_TYPE_GRAY && trns) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); } if (color_type == PNG_COLOR_TYPE_RGB) { if (trns) png_set_tRNS_to_alpha(png_ptr); else png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // Update the info structures after the transformations take effect if (interlace_type != PNG_INTERLACE_NONE) png_set_interlace_handling(png_ptr); // needed before read_update_info() png_read_update_info (png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); channels = png_get_channels(png_ptr, info_ptr); result = new gPixmap(width, height, bit_depth * channels, pixmapDisposed, accel); gUnmanagedSurface *surface = result->surface; png_bytep *rowptr = new png_bytep[height]; for (unsigned int i = 0; i < height; i++) rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride; png_read_image(png_ptr, rowptr); delete [] rowptr; int num_palette = -1, num_trans = -1; if (color_type == PNG_COLOR_TYPE_PALETTE) { if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_color *palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette) surface->clut.data = new gRGB[num_palette]; else surface->clut.data = 0; surface->clut.colors = num_palette; for (int i = 0; i < num_palette; i++) { surface->clut.data[i].a = 0; surface->clut.data[i].r = palette[i].red; surface->clut.data[i].g = palette[i].green; surface->clut.data[i].b = palette[i].blue; } if (trns) { png_byte *trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0); for (int i = 0; i < num_trans; i++) surface->clut.data[i].a = 255 - trans[i]; for (int i = num_trans; i < num_palette; i++) surface->clut.data[i].a = 0; } } else { surface->clut.data = 0; surface->clut.colors = 0; } surface->clut.start = 0; } pixmapToTable(result, filename); //eDebug("[ePNG] %s: after %dx%dx%dbpcx%dchan coltyp=%d cols=%d trans=%d", filename, (int)width, (int)height, bit_depth, channels, color_type, num_palette, num_trans); png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return 0; }
void pngRead(const std::string& file, ImageBuffer<RGBA8>& image) { // open file FILE* fp = nullptr; try { fp = fopen(file.c_str(), "rb"); if(!fp) throw; // check if it's a png, 8 is the maximum size that can be checked png_byte header[8]; fread(header, 1, 8, fp); if(png_sig_cmp(header, 0, 8)) throw; // try to create read struct png_structp pStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!pStruct) throw; // try to create info struct png_infop pInfo = png_create_info_struct(pStruct); if(!pInfo) throw; // read info png_init_io(pStruct, fp); png_set_sig_bytes(pStruct, 8); png_read_info(pStruct, pInfo); int width = png_get_image_width(pStruct, pInfo); int height = png_get_image_height(pStruct, pInfo); png_byte colorType = png_get_color_type(pStruct, pInfo); png_byte bitDepth = png_get_bit_depth(pStruct, pInfo); png_byte channels = png_get_channels(pStruct, pInfo); png_read_update_info(pStruct, pInfo); // read data std::vector<std::vector<png_byte>> rowBytes(height); std::vector<png_byte*> rowPointers(height); png_size_t rowByteCount = png_get_rowbytes(pStruct, pInfo); for(int y = 0; y < height; y++) { rowBytes[y].resize(rowByteCount); rowPointers[y] = rowBytes[y].data(); } png_read_image(pStruct, rowPointers.data()); if(colorType == PNG_COLOR_TYPE_RGB) { image.setSize(width, height); for(int y = 0; y < height; y++) { png_byte* pBytes = rowPointers[y]; for(int x = 0; x < width; x++, pBytes += 3) { image(x, y) = {pBytes[0], pBytes[1], pBytes[2], 255}; } } } else if(colorType == PNG_COLOR_TYPE_RGBA) { image.setSize(width, height); for(int y = 0; y < height; y++) { png_byte* pBytes = rowPointers[y]; for(int x = 0; x < width; x++, pBytes += 4) { image(x, y) = {pBytes[0], pBytes[1], pBytes[2], pBytes[3]}; } } } else { throw; } } catch(...) { // File couldn't be loaded or read. assert(0); if(fp) fclose(fp); } }