int R2Image:: ReadPNG(const char *filename) { // Open file FILE *fp = fopen(filename, "rb"); if (!fp) { fprintf(stderr, "Unable to open PNG file %s\n", filename); return 0; } // Create and initialize the png_struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return 0; } // Allocate/initialize the memory for image information. png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // Set up the input control if you are using standard C streams png_init_io(png_ptr, fp); // Read the png info png_read_info(png_ptr, info_ptr); // Extract image info png_byte color_type = png_get_color_type(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); // Set nchannels nchannels = 0; if (color_type == PNG_COLOR_TYPE_GRAY) nchannels = 1; else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) nchannels = 2; else if (color_type == PNG_COLOR_TYPE_RGB) nchannels = 3; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) nchannels = 4; else { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // Allocate the pixels and row pointers int rowsize = png_get_rowbytes(png_ptr, info_ptr); assert(rowsize >= width * nchannels); png_bytep buffer = new unsigned char [ height * rowsize * png_sizeof(png_bytep) ]; png_bytep *row_pointers = (png_bytep *) png_malloc(png_ptr, height * png_sizeof(png_bytep)); for (int i = 0; i < height; i++) row_pointers[i] = &buffer[ (height - i - 1) * rowsize ]; // Read the pixels png_read_image(png_ptr, row_pointers); // Finish reading png_read_end(png_ptr, info_ptr); // Copy pixels from temporary buffer pixels = new double [ height * width * nchannels ]; for (int j = 0; j < height; j++) { for (int i = 0; i < width * nchannels; i++) { pixels[j*width*nchannels + i] = buffer[j*width*nchannels + i] / 255.0; } } // Free the row pointers png_free(png_ptr, row_pointers); // Clean up after the read, and free any memory allocated png_destroy_read_struct(&png_ptr, &info_ptr, NULL); // Close the file fclose(fp); // Delete temporary buffer delete [] buffer; // Return success return 1; }
~PNGAutoClean() { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); }
struct gl_texture_t *ReadPNGFromFile (const char *filename) { FILE *fp; png_byte magic[8]; /* Open image file */ fp = fopen (filename, "rb"); if (!fp) { fprintf (stderr, "error: couldn't open \"%s\"!\n", filename); return NULL; } /* Read magic number */ fread (magic, 1, sizeof (magic), fp); /* Check for valid magic number */ if (!png_check_sig (magic, sizeof (magic))) { fprintf (stderr, "error: \"%s\" is not a valid PNG image!\n",filename); fclose (fp); return NULL; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose (fp); return NULL; } /* Create a png info struct */ png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose (fp); png_destroy_read_struct (&png_ptr, NULL, NULL); return NULL; } /* Create our OpenGL texture object */ struct gl_texture_t *texinfo = (struct gl_texture_t *) malloc (sizeof (struct gl_texture_t)); /* Initialize the setjmp for returning properly after a libpng error occured */ if (setjmp (png_jmpbuf(png_ptr))) { fclose (fp); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); if (texinfo) { if (texinfo->texels) free (texinfo->texels); free (texinfo); } return NULL; } /* Setup libpng for using standard C fread() function with our FILE pointer */ png_init_io (png_ptr, fp); /* Tell libpng that we have already read the magic number */ png_set_sig_bytes (png_ptr, sizeof (magic)); /* Read png info */ png_read_info (png_ptr, info_ptr); int bit_depth, color_type; /* Get some usefull information from header */ bit_depth = png_get_bit_depth (png_ptr, info_ptr); color_type = png_get_color_type (png_ptr, info_ptr); /* Convert index color images to RGB images */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (png_ptr); /* Convert 1-2-4 bits grayscale images to 8 bits grayscale. */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8 (png_ptr); if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png_ptr); if (bit_depth == 16) png_set_strip_16 (png_ptr); else if (bit_depth < 8) png_set_packing (png_ptr); /* Update info structure to apply transformations */ png_read_update_info (png_ptr, info_ptr); /* Retrieve updated information */ png_uint_32 w, h; png_get_IHDR (png_ptr, info_ptr, &w, &h, &bit_depth,&color_type, NULL, NULL, NULL); texinfo->width = w; texinfo->height = h; switch (color_type) { case PNG_COLOR_TYPE_GRAY: texinfo->format = GL_LUMINANCE; texinfo->internalFormat = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: texinfo->format = GL_LUMINANCE_ALPHA; texinfo->internalFormat = 2; break; case PNG_COLOR_TYPE_RGB: texinfo->format = GL_RGB; texinfo->internalFormat = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: texinfo->format = GL_RGBA; texinfo->internalFormat = 4; break; default: /* Badness */ break; } /* We can now allocate memory for storing pixel data */ texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte)*texinfo->width*texinfo->height*texinfo->internalFormat); png_bytep *row_pointers; /* Setup a pointer array. Each one points at the begening of a row. */ row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * texinfo->height); for (int i = 0; i < texinfo->height; ++i) row_pointers[i] = (png_bytep)(texinfo->texels + ((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat)); /* Read pixel data using row pointers */ png_read_image(png_ptr, row_pointers); /* We don't need row pointers anymore */ free (row_pointers); return(texinfo); }
/* 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)
void t_RenderClass::loadTexture(int target, const char *filename) { FILE *theFile = fopen(filename,"rb"); if (!theFile) { LOGI("Fopen failed"); exit(1); } char header[8]; fread(header,1,8,theFile); if (ferror(theFile)) { LOGI("Fread failed"); exit(1); } if (png_sig_cmp((png_byte *) header,0,8)) { LOGI("The file is not a png\n"); exit(1); } png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL,NULL,NULL ); if (!png_ptr) { printf("Failed initialization of png_ptr\n"); exit(1); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); printf("Info ptr creation failed\n"); exit(1); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); printf("Info ptr creation failed\n"); exit(1); } png_init_io(png_ptr,theFile); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); int width = png_get_image_width(png_ptr,info_ptr); int height = png_get_image_width(png_ptr,info_ptr); int depth = png_get_bit_depth(png_ptr,info_ptr); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_byte* image_data = new png_byte[rowbytes * height]; png_bytep *row_pointers = new png_bytep [height]; for (int i = 0; i < height; ++i) { row_pointers[i] = image_data + i * rowbytes; } LOGI("I have read the image with width %d, height %d, depth %d, rowbytes %d\n",width,height,depth,rowbytes); png_read_image(png_ptr,row_pointers); png_read_end(png_ptr,NULL); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,image_data); checkGlError("glClear"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGlError("glClear"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGlError("glClear"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); checkGlError("glClear"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); checkGlError("glClear"); }
unsigned char *read_png_file(const char* file_name, int *width, int *height, int *stride) { png_byte color_type; png_byte bit_depth; png_structp png_ptr; png_infop info_ptr; int number_of_passes; png_bytep* row_pointers; int y; unsigned char header[8]; // 8 is the maximum size that can be checked unsigned char *buf; FILE *fp; /* open file and test for it being a png */ fp = fopen(file_name, "rb"); if (!fp) return NULL; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { roadmap_log (ROADMAP_ERROR, "[read_png_file] File %s is not recognized as a PNG file", file_name); fclose(fp); return NULL; } /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { roadmap_log (ROADMAP_ERROR, "[read_png_file] png_create_read_struct failed"); fclose(fp); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { roadmap_log (ROADMAP_ERROR, "[read_png_file] png_create_info_struct failed"); fclose(fp); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { roadmap_log (ROADMAP_ERROR, "[read_png_file] Error during init_io"); fclose(fp); return NULL; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); *width = info_ptr->width; *height = info_ptr->height; *stride = info_ptr->rowbytes; color_type = info_ptr->color_type; bit_depth = info_ptr->bit_depth; 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))) { roadmap_log (ROADMAP_ERROR, "[read_png_file] Error during read_image"); fclose(fp); return NULL; } row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * *height); buf = malloc (*height * info_ptr->rowbytes); for (y=0; y<*height; y++) { row_pointers[y] = (png_byte*) (buf + y * info_ptr->rowbytes); } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); free (row_pointers); fclose(fp); return buf; }
uint8_t* ImageDecoder::decodePNGImpl(png_structp pngPtr, uint32_t* width, uint32_t* height) { png_bytep* rowPtrs = NULL; uint8_t* outData = NULL; png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { LOG(LOG_ERROR,"Couldn't initialize png info struct"); png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); return NULL; } if (setjmp(png_jmpbuf(pngPtr))) { png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); if (rowPtrs != NULL) delete [] rowPtrs; if (outData != NULL) delete [] outData; LOG(LOG_ERROR,"error during reading of the png file"); return NULL; } png_read_info(pngPtr, infoPtr); *width = png_get_image_width(pngPtr, infoPtr); *height = png_get_image_height(pngPtr, infoPtr); //bits per CHANNEL! note: not per pixel! png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr); //Number of channels png_uint_32 channels = png_get_channels(pngPtr, infoPtr); //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr); // Transform everything into 24 bit RGB switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); // png_set_palette_to_rgb wil convert into 32 // bit, but we don't want the alpha png_set_strip_alpha(pngPtr); break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) png_set_gray_to_rgb(pngPtr); break; } if (bitdepth == 16) { png_set_strip_16(pngPtr); } if (channels > 3) { LOG(LOG_NOT_IMPLEMENTED, "Alpha channel not supported in PNG"); png_set_strip_alpha(pngPtr); } // Update the infoPtr to reflect the transformations set // above. Read new values by calling png_get_* again. png_read_update_info(pngPtr, infoPtr); //bitdepth = png_get_bit_depth(pngPtr, infoPtr); //color_type = png_get_color_type(pngPtr, infoPtr); channels = png_get_channels(pngPtr, infoPtr); if (channels != 3) { // Should never get here because of the // transformations LOG(LOG_NOT_IMPLEMENTED, "Unexpected number of channels in PNG!"); png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); return NULL; } const unsigned int stride = png_get_rowbytes(pngPtr, infoPtr); outData = new uint8_t[(*height) * stride]; rowPtrs = new png_bytep[(*height)]; for (size_t i = 0; i < (*height); i++) { rowPtrs[i] = (png_bytep)outData + i* stride; } png_read_image(pngPtr, rowPtrs); png_read_end(pngPtr, NULL); png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); delete[] (png_bytep)rowPtrs; return outData; }
int load_png_image(const char *filepath, struct pngload_attribute *png_attr) { FILE *fp; png_structp png_ptr; png_infop info_ptr; png_bytep* row_pointers; char buf[PNG_BYTES_TO_CHECK]; int w, h, x, y, temp, color_type; fp = fopen( filepath, "rb" ); if( fp == NULL ) { return -1; } png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); info_ptr = png_create_info_struct( png_ptr ); setjmp( png_jmpbuf(png_ptr) ); /* 读取PNG_BYTES_TO_CHECK个字节的数据 */ temp = fread( buf, 1, PNG_BYTES_TO_CHECK, fp ); /* 若读到的数据并没有PNG_BYTES_TO_CHECK个字节 */ if( temp < PNG_BYTES_TO_CHECK ) { fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return -3; } /* 检测数据是否为PNG的签名 */ temp = png_sig_cmp( (png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK ); /* 如果不是PNG的签名,则说明该文件不是PNG文件 */ if( temp != 0 ) { fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return -4; } /* 复位文件指针 */ rewind( fp ); /* 开始读文件 */ png_init_io( png_ptr, fp ); /* 读取PNG图片信息 */ png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0 ); /* 获取图像的色彩类型 */ color_type = png_get_color_type( png_ptr, info_ptr ); /* 获取图像的宽高 */ png_attr->width = w = png_get_image_width( png_ptr, info_ptr ); png_attr->height = h = png_get_image_height( png_ptr, info_ptr ); printf("w=%d,h=%d\n", w, h); /* 获取图像的所有行像素数据,row_pointers里边就是rgba数据 */ row_pointers = png_get_rows( png_ptr, info_ptr ); unsigned char *data; int index = 0; /* 根据不同的色彩类型进行相应处理 */ png_attr->color_type = color_type; switch( color_type ) { case PNG_COLOR_TYPE_RGB_ALPHA: printf("rgba\n"); data = malloc(w*h*4); png_attr->buf = data; for( y=0; y<h; ++y ) { for( x=0; x<w*4; ) { /* 以下是RGBA数据,需要自己补充代码,保存RGBA数据 */ data[index++] = row_pointers[y][x++]; // red data[index++] = row_pointers[y][x++]; // green data[index++] = row_pointers[y][x++]; // blue data[index++] = row_pointers[y][x++]; // alpha } } break; case PNG_COLOR_TYPE_RGB: printf("rgb\n"); data = malloc(w*h*3); png_attr->buf = data; for( y=0; y<h; ++y ) { for( x=0; x<w*3; ) { data[index++] = row_pointers[y][x++]; // red data[index++] = row_pointers[y][x++]; // green data[index++] = row_pointers[y][x++]; // blue } } break; /* 其它色彩类型的图像就不读了 */ default: fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return -2; } png_destroy_read_struct( &png_ptr, &info_ptr, 0); return 0; }
// Loads a PNG image // // filename - name of the targa file to load // image_data - allocated storage for the bitmap // // returns - true if succesful, false otherwise // int png_read_bitmap(char *real_filename, ubyte *image_data, ubyte *bpp, int dest_size, int cf_type) { char filename[MAX_FILENAME_LEN]; png_infop info_ptr; png_structp png_ptr; png_bytepp row_pointers; unsigned int i, len; png_file = NULL; strcpy_s( filename, real_filename ); char *p = strchr( filename, '.' ); if ( p ) *p = 0; strcat_s( filename, ".png" ); png_file = cfopen(filename, "rb", CFILE_NORMAL, cf_type); if (png_file == NULL) return PNG_ERROR_READING; /* 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, NULL, NULL, NULL); if (png_ptr == NULL) { mprintf(("png_read_bitmap: png_ptr went wrong\n")); cfclose(png_file); return PNG_ERROR_READING; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { mprintf(("png_read_bitmap: info_ptr went wrong\n")); cfclose(png_file); png_destroy_read_struct(&png_ptr, NULL, NULL); return PNG_ERROR_READING; } if (setjmp(png_jmpbuf(png_ptr))) { mprintf(("png_read_bitmap: something went wrong\n")); /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); cfclose(png_file); /* If we get here, we had a problem reading the file */ return PNG_ERROR_READING; } png_set_read_fn(png_ptr, &png_file, png_scp_read_data); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL); len = png_get_rowbytes(png_ptr, info_ptr); row_pointers = png_get_rows(png_ptr, info_ptr); if(bpp) *bpp = (ubyte)(len / png_get_image_width(png_ptr, info_ptr)) << 3; //copy row data to image unsigned int height = png_get_image_height(png_ptr, info_ptr); for (i = 0; i < height; i++) { memcpy(&image_data[i * len], row_pointers[i], len); } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); cfclose(png_file); return PNG_ERROR_NONE; }
unsigned char *readpng_get_image( png_store* pngdata) { double gamma; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; png_structp png_ptr = pngdata->png_ptr; png_infop info_ptr = pngdata->info_ptr; int color_type = pngdata->colortype; int bit_depth = pngdata->bitdepth; int height = pngdata->height; double display_exponent = DISPLAY_EXPONENT; int *pChannels = &(pngdata->channels); unsigned long *pRowbytes = &(pngdata->rowbytes); unsigned char * image_data; /* 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 NULL; } /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* 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_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, display_exponent, gamma); /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(png_ptr, info_ptr); *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); *pChannels = (int)png_get_channels(png_ptr, info_ptr); if ((image_data = (unsigned char *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(image_data); image_data = NULL; return NULL; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ // free(row_pointers); // row_pointers = NULL; png_read_end(png_ptr, NULL); pngdata->image_data = image_data; pngdata->row_pointers = row_pointers; return image_data; }
int readpng_init(FILE *infile, png_store *pngdata) { unsigned char sig[8]; long width,height; int bit_depth, color_type; /* first do a quick check that the file really is a PNG image; could * have used slightly more general png_sig_cmp() function instead */ size_t fr = fread(sig, 1, 8, infile); if(fr != 1*8) return 1; /* bad signature */ if (!png_check_sig(sig, 8)) return 1; /* bad signature */ /* could pass pointers to user-defined error handlers instead of NULLs: */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return 4; /* out of memory */ png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 4; /* out of memory */ } /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* 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 */ /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pngdata->width = width; pngdata->height = height; pngdata->bitdepth = bit_depth; pngdata->colortype = color_type; pngdata->png_ptr = png_ptr; pngdata->info_ptr = info_ptr; /* OK, that's all we need for now; return happy */ return 0; }
/** The constructor loads the named PNG image from the given png filename. <P>The destructor free all memory and server resources that are used by the image. */ void LoadPNG(const char *png) // I - File to read { int i; // Looping var FILE *fp; // File pointer int channels; // Number of color channels png_structp pp; // PNG read pointer png_infop info; // PNG info pointers png_bytep *rows; // PNG row pointers // Open the PNG file... if ((fp = fopen(png, "rb")) == NULL) return; // Setup the PNG data structures... pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(pp); if (setjmp(pp->jmpbuf)) { int debug = 1; return; } // Initialize the PNG read "engine"... png_init_io(pp, fp); // Get the image dimensions and convert to grayscale or RGB... png_read_info(pp, info); if (info->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(pp); if (info->color_type & PNG_COLOR_MASK_COLOR) channels = 3; else channels = 1; if ((info->color_type & PNG_COLOR_MASK_ALPHA) || info->num_trans) channels ++; int w = (int)(info->width); int h = (int)(info->height); int d = channels; pictureWidth = w; pictureHeight = h; if (info->bit_depth < 8) { png_set_packing(pp); png_set_expand(pp); } else if (info->bit_depth == 16) png_set_strip_16(pp); # if defined(HAVE_PNG_GET_VALID) && defined(HAVE_PNG_SET_TRNS_TO_ALPHA) // Handle transparency... if (png_get_valid(pp, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pp); # endif // HAVE_PNG_GET_VALID && HAVE_PNG_SET_TRNS_TO_ALPHA unsigned char *array = (unsigned char *)pictureS; // Allocate pointers... rows = new png_bytep[h]; for (i = 0; i < h; i ++) rows[i] = (png_bytep)(array + i * w * d); // we flip it // Read the image, handling interlacing as needed... for (i = png_set_interlace_handling(pp); i > 0; i --) png_read_rows(pp, rows, NULL, h); #ifdef WIN32 // Some Windows graphics drivers don't honor transparency when RGB == white if (channels == 4) { // Convert RGB to 0 when alpha == 0... unsigned char *ptr = (unsigned char *)array; for (i = w * h; i > 0; i --, ptr += 4) if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0; } #endif // WIN32 if (channels == 3) { unsigned char *array2 = new unsigned char[pictureWidth * pictureHeight * 4]; for (int i = w * h - 1; i >= 0; --i) { array2[i*4+0] = array[i*3+0]; array2[i*4+1] = array[i*3+1]; array2[i*4+2] = array[i*3+2]; array2[i*4+3] = 255; } memcpy(array, array2, w * h * 4); delete[] array2; } // Free memory and return... delete[] rows; png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); fclose(fp); }
static rt_bool_t rtgui_image_png_load(struct rtgui_image *image, struct rtgui_filerw *file, rt_bool_t load) { png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; double gamma; struct rtgui_image_png *png; png = (struct rtgui_image_png *) rtgui_malloc(sizeof(struct rtgui_image_png)); png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png->png_ptr == RT_NULL) { rtgui_free(png); return RT_FALSE; } png->info_ptr = png_create_info_struct(png->png_ptr); if (png->info_ptr == RT_NULL) { png_destroy_read_struct(&png->png_ptr, NULL, NULL); rtgui_free(png); return RT_FALSE; } png->filerw = file; png_set_read_fn(png->png_ptr, png->filerw, rtgui_image_png_read_data); png_read_info(png->png_ptr, png->info_ptr); png_get_IHDR(png->png_ptr, png->info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* set image information */ image->w = width; image->h = height; image->engine = &rtgui_image_png_engine; image->data = png; if (bit_depth == 16) png_set_strip_16(png->png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png->png_ptr); if (bit_depth < 8) png_set_expand(png->png_ptr); if (png_get_valid(png->png_ptr, png->info_ptr, PNG_INFO_tRNS)) png_set_expand(png->png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png->png_ptr); /* Ignore background color */ /* set gamma conversion */ if (png_get_gAMA(png->png_ptr, png->info_ptr, &gamma)) png_set_gamma(png->png_ptr, (double)2.2, gamma); png_read_update_info(png->png_ptr, png->info_ptr); if (load == RT_TRUE) { /* load all pixels */ png->pixels = rtgui_malloc(image->w * image->h * sizeof(rtgui_color_t)); if (png->pixels == RT_NULL) { png_read_end(png->png_ptr, RT_NULL); /* destroy png struct */ png_destroy_info_struct(png->png_ptr, &png->info_ptr); png_destroy_read_struct(&png->png_ptr, RT_NULL, RT_NULL); /* release data */ rtgui_free(png); return RT_FALSE; } rtgui_image_png_process(png->png_ptr, png->info_ptr, png); } else { png->pixels = RT_NULL; } return RT_TRUE; }
~png_struct_guard() { png_destroy_read_struct(p_,i_,0); }
char *sng_load_png_texture(const char *filename, int flipVertical, int flipHorizontal, int pre_multiply_alpha, int *w, int *h, int *hasAlpha, char *whynot, int whynotlen) { #ifndef WITHOUTOPENGL int i, j, bit_depth, color_type, row_bytes, image_data_row_bytes; png_byte header[8]; png_uint_32 tw, th; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_byte *image_data = NULL; FILE *fp = fopen(filename, "rb"); if (!fp) { snprintf(whynot, whynotlen, "Failed to open '%s': %s", filename, strerror(errno)); return 0; } if (fread(header, 1, 8, fp) != 8) { snprintf(whynot, whynotlen, "Failed to read 8 byte header from '%s'\n", filename); goto cleanup; } if (png_sig_cmp(header, 0, 8)) { snprintf(whynot, whynotlen, "'%s' isn't a png file.", filename); goto cleanup; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { snprintf(whynot, whynotlen, "png_create_read_struct() returned NULL"); goto cleanup; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { snprintf(whynot, whynotlen, "png_create_info_struct() returned NULL"); goto cleanup; } end_info = png_create_info_struct(png_ptr); if (!end_info) { snprintf(whynot, whynotlen, "2nd png_create_info_struct() returned NULL"); goto cleanup; } if (setjmp(png_jmpbuf(png_ptr))) { snprintf(whynot, whynotlen, "libpng encounted an error"); goto cleanup; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); /* * PNG_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); png_get_IHDR(png_ptr, info_ptr, &tw, &th, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth != 8) { snprintf(whynot, whynotlen, "load_png_texture only supports 8-bit image channel depth"); goto cleanup; } if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) { snprintf(whynot, whynotlen, "load_png_texture only supports RGB and RGBA"); goto cleanup; } if (w) *w = tw; if (h) *h = th; int has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA); if (hasAlpha) *hasAlpha = has_alpha; row_bytes = png_get_rowbytes(png_ptr, info_ptr); image_data_row_bytes = row_bytes; /* align to 4 byte boundary */ if (image_data_row_bytes & 0x03) image_data_row_bytes += 4 - (image_data_row_bytes & 0x03); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); image_data = malloc(image_data_row_bytes * th * sizeof(png_byte) + 15); if (!image_data) { snprintf(whynot, whynotlen, "malloc failed in load_png_texture"); goto cleanup; } int bytes_per_pixel = (color_type == PNG_COLOR_TYPE_RGB_ALPHA ? 4 : 3); for (i = 0; i < th; i++) { png_byte *src_row; png_byte *dest_row = image_data + i * image_data_row_bytes; if (flipVertical) src_row = row_pointers[th - i - 1]; else src_row = row_pointers[i]; if (flipHorizontal) { for (j = 0; j < tw; j++) { png_byte *src = src_row + bytes_per_pixel * j; png_byte *dest = dest_row + bytes_per_pixel * (tw - j - 1); memcpy(dest, src, bytes_per_pixel); } } else { memcpy(dest_row, src_row, row_bytes); } if (has_alpha && pre_multiply_alpha) { for (j = 0; j < tw; j++) { png_byte *pixel = dest_row + bytes_per_pixel * j; float alpha = pixel[3] / 255.0; pixel[0] = pixel[0] * alpha; pixel[1] = pixel[1] * alpha; pixel[2] = pixel[2] * alpha; } } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return (char *)image_data; cleanup: if (image_data) free(image_data); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); #else snprintf(whynot, whynotlen, "load_png_texture: compiled without opengl support."); #endif return 0; }
// Reads header information from the PNG file into the bitmap pointer // // filename - name of the PNG bitmap file // w - (output) width of the bitmap // h - (output) height of the bitmap // bpp - (output) bits per pixel of the bitmap // // returns - PNG_ERROR_NONE if successful, otherwise error code // int png_read_header(char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette) { char filename[MAX_FILENAME_LEN]; png_infop info_ptr; png_structp png_ptr; png_file = NULL; //mprintf(("png_read_header: %s\n", real_filename)); if (img_cfp == NULL) { strcpy_s( filename, real_filename ); char *p = strchr( filename, '.' ); if ( p ) *p = 0; strcat_s( filename, ".png" ); png_file = cfopen( filename , "rb" ); if ( !png_file ) { return PNG_ERROR_READING; } } else { png_file = img_cfp; } Assert( png_file != NULL ); if (png_file == NULL) return PNG_ERROR_READING; /* 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, NULL, NULL, NULL); if (png_ptr == NULL) { mprintf(("png_read_header: error creating read struct\n")); cfclose(png_file); return PNG_ERROR_READING; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { mprintf(("png_read_header: error creating info struct\n")); cfclose(png_file); png_destroy_read_struct(&png_ptr, NULL, NULL); return PNG_ERROR_READING; } if (setjmp(png_jmpbuf(png_ptr))) { mprintf(("png_read_header: something went wrong\n")); /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); cfclose(png_file); /* If we get here, we had a problem reading the file */ return PNG_ERROR_READING; } png_set_read_fn(png_ptr, &png_file, png_scp_read_data); png_read_info(png_ptr, info_ptr); if (w) *w = png_get_image_width(png_ptr, info_ptr); if (h) *h = png_get_image_height(png_ptr, info_ptr); // this turns out to be near useless, but meh if (bpp) *bpp = (png_get_channels(png_ptr, info_ptr) * png_get_bit_depth(png_ptr, info_ptr)); if (img_cfp == NULL) { cfclose(png_file); png_file = NULL; } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return PNG_ERROR_NONE; }
g_error png_load(hwrbitmap *hbmp, const u8 *data, u32 datalen) { png_structp png_ptr; png_infop info_ptr; struct datablock d; png_bytep *row_pointers; png_uint_32 width, height; int bit_depth,colortype,interlace; int x,y; u8 r,g,b,a; pgcolor c; png_bytep p; g_error e; png_colorp palette; int num_palette; png_colorp pp; png_bytep trans; int num_trans = 0; #ifdef CONFIG_DITHER hwrdither dither; #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ } /* Set libpng error handler */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 71); /* Error reading PNG */ } /* Set libpng read handler */ d.data = data; d.length = datalen; png_set_read_fn(png_ptr, &d, (png_rw_ptr) &png_user_read_data); /* Read the png into memory */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &colortype, &interlace, NULL, NULL); if (colortype == PNG_COLOR_TYPE_PALETTE) { png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); } if (interlace != PNG_INTERLACE_NONE) fprintf(stderr, "png loader: OOPS... interlaced image, will b0rk\n"); /* Allocate the picogui bitmap * * Important note: normally we create bitmaps at the display's * color depth, but if we have an alpha channel * we need room for ARGB colors. */ if (colortype == PNG_COLOR_TYPE_GRAY_ALPHA || colortype == PNG_COLOR_TYPE_RGB_ALPHA || num_trans) e = vid->bitmap_new(hbmp,width,height,32); else e = vid->bitmap_new(hbmp,width,height,vid->bpp); if (iserror(e)) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); errorcheck; #ifdef CONFIG_DITHER /* Start dithering */ e = vid->dither_start(&dither, *hbmp, 0,0,0,width,height); errorcheck; #endif /* Transcribe it into a picogui bitmap. * This method is slow, but ensures compatibility */ for (y=0;y<height;y++) { p = row_pointers[y]; for (x=0;x<width;x++) { switch (colortype) { case PNG_COLOR_TYPE_GRAY: g = *(p++); c = mkcolor(g,g,g); break; case PNG_COLOR_TYPE_GRAY_ALPHA: g = *(p++); a = *(p++); c = mkcolora(a>>1,g,g,g); break; case PNG_COLOR_TYPE_PALETTE: pp = &palette[ (*p) % num_palette ]; if (*p < num_trans) c = mkcolora(trans[*p]>>1, pp->red, pp->green, pp->blue); else if (num_trans) c = mkcolora(0x7f, pp->red, pp->green, pp->blue); else c = mkcolor(pp->red, pp->green, pp->blue); p++; break; case PNG_COLOR_TYPE_RGB: r = *(p++); g = *(p++); b = *(p++); c = mkcolor(r,g,b); break; case PNG_COLOR_TYPE_RGB_ALPHA: r = *(p++); g = *(p++); b = *(p++); a = *(p++); c = mkcolora(a>>1,r,g,b); break; } #ifdef CONFIG_DITHER vid->dither_store(dither, c, PG_LGOP_NONE); #else vid->pixel(*hbmp,x,y,VID(color_pgtohwr)(c),PG_LGOP_NONE); #endif } }
void CachedTexture::reload() { //..... load file ...... GLenum internal_format = GL_RGB; GLenum data_format = GL_RGB; unsigned char *data = NULL; if (filename.size() >= 4 && filename.substr(filename.size()-4,4) == ".png") { //Load a png file, as per the libpng docs: FILE *fp = fopen(filename.c_str(), "rb"); if (!fp) { cerr << " cannot open file." << endl; return; } png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); if (!png) { cerr << " cannot alloc read struct." << endl; fclose(fp); return; } png_infop info = png_create_info_struct(png); if (!info) { cerr << " cannot alloc info struct." << endl; png_destroy_read_struct(&png, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return; } png_bytep *row_pointers = NULL; if (setjmp(png_jmpbuf(png))) { cerr << " png interal error." << endl; png_destroy_read_struct(&png, &info, (png_infopp)NULL); if (data != NULL) delete[] data; if (row_pointers != NULL) delete[] row_pointers; fclose(fp); return; } png_init_io(png, fp); png_read_info(png, info); w = png_get_image_width(png, info); h = png_get_image_height(png, info); { //find power-of-two dimensions... tw = 1; while (tw < w) tw *= 2; th = 1; while (th < h) th *= 2; } if (!pad && (tw != w || th != h)) { if (!have_ARB_texture_non_power_of_two()) { cerr << "WARNING: trying to load texture of size " << w << " x " << h << ", but non-power-of-two textures not supported." << endl; } tw = w; th = h; } if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (png_get_bit_depth(png, info) < 8) png_set_packing(png); if (png_get_bit_depth(png,info) == 16) png_set_strip_16(png); png_read_update_info(png, info); unsigned int rowbytes = png_get_rowbytes(png, info); //Make sure it's the format we think it is... bool problem = false; if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY) { data_format = internal_format = GL_LUMINANCE; if (rowbytes != w*1) problem = true; } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY_ALPHA) { data_format = internal_format = GL_LUMINANCE_ALPHA; if (rowbytes != w*2) problem = true; } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE || png_get_color_type(png, info) == PNG_COLOR_TYPE_RGB) { data_format = internal_format = GL_RGB; if (rowbytes != w*3) problem = true; } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_RGB_ALPHA) { data_format = internal_format = GL_RGBA; if (rowbytes != w*4) problem = true; } else { cerr << " unknown color format." << endl; problem = true; } if (problem) { cerr << " color format problem. (rowbytes: " << rowbytes << " w:" << w << ")" << endl; png_destroy_read_struct(&png, &info, NULL); fclose(fp); return; } unsigned int pixelbytes = rowbytes / w; assert(rowbytes == pixelbytes * w); //sanity check, should have bailed earlier if this was the case. data = new uint8_t[th*tw*pixelbytes]; row_pointers = new png_bytep[th]; if (flip) { //texture origin goes top-left, as in most images: for (unsigned int r = 0; r < th; ++r) { row_pointers[r] = (png_bytep)(data + r*pixelbytes*tw); } } else { //texture origin goes bottom-left, as GL says: for (unsigned int r = 0; r < th; ++r) { row_pointers[th-1-r] = (png_bytep)(data + r*tw*pixelbytes); } } png_read_image(png, row_pointers); png_destroy_read_struct(&png, &info, NULL); fclose(fp); delete[] row_pointers; if (pad && h != 0 && w != 0) { //duplicate the last column accross the texture: for (unsigned int r = 0; r < h; ++r) { for (unsigned int c = w; c < tw; ++c) { memcpy(&(data[(r*tw+c)*pixelbytes]), &(data[(r*tw+w-1)*pixelbytes]),pixelbytes); } } //duplicate the last row down the texture: for (unsigned int r = h; r < th; ++r) { memcpy(&(data[r*pixelbytes*tw]), &(data[(h-1)*pixelbytes*tw]), pixelbytes*tw); } } } else { //well, not a supported image type I'm afraid. cerr << " unknown image type." << endl; return; } glGenTextures(1, &obj); glBindTexture(GL_TEXTURE_2D, obj); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, tw, th, 0, data_format, GL_UNSIGNED_BYTE, data); glBindTexture(GL_TEXTURE_2D, 0); glPopClientAttrib(); delete[] data; loaded = true; gl_errors("CachedTexture::reload()"); }
bool Image::loadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, unsigned char** outData) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; FILE *fp; if ((fp = fopen(name, "rb")) == NULL) return false; /* 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, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return false; } // 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 false; } /* 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 false; } /* Set up the output control if you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* * 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_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, png_voidp_NULL); outWidth = png_get_image_width(png_ptr,info_ptr); // ширина изображение outHeight = png_get_image_height(png_ptr,info_ptr); // высота изображения // проверка на наличие альфа-канала switch (png_get_color_type(png_ptr,info_ptr)) { case PNG_COLOR_TYPE_RGBA: outHasAlpha = true; break; case PNG_COLOR_TYPE_RGB: outHasAlpha = false; break; default: std::cout << "Color type " << png_get_color_type(png_ptr,info_ptr) << " not supported" << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return false; } unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); *outData = (unsigned char*) malloc(row_bytes * outHeight); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < outHeight; i++) { // note that png is ordered top to bottom, but OpenGL expect it bottom to top // so the order or swapped memcpy(*outData+(row_bytes * (outHeight-1-i)), row_pointers[i], row_bytes); } /* Clean up after the read, and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); /* Close the file */ fclose(fp); return true; }
static void display_clean_read(struct display *dp) { if (dp->read_pp != NULL) png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL); }
int fh_png_load(const char *name, unsigned char *buffer, int x, int y) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes, pass; png_byte * fbptr; FILE * fh; if (!(fh = fopen(name, "rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) return(FH_ERROR_FORMAT); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr, fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)buffer; for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
int read_png_file(const char *file, int32 *pwidth, int32 *pheight, uint8 **image_data_ptr) { FILE *infile; /* PNG file pointer */ png_structp png_ptr; /* internally used by libpng */ png_infop info_ptr; /* user requested transforms */ uint8 *image_data; /* raw png image data */ char sig[8]; /* PNG signature array */ /*char **row_pointers; */ int bit_depth; int color_type; png_uint_32 width; /* PNG image width in pixels */ png_uint_32 height; /* PNG image height in pixels */ unsigned int rowbytes; /* raw bytes at row n in image */ image_data = NULL; int i; png_bytepp row_pointers = NULL; /* Open the file. */ infile = fopen(file, "rb"); if (!infile) { return 0; } /* * 13.3 readpng_init() */ /* Check for the 8-byte signature */ fread(sig, 1, 8, infile); if (png_sig_cmp((unsigned char *) sig, 0, 8) != 0) { fclose(infile); return 0; } /* * Set up the PNG structs */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(infile); return 4; /* out of memory */ } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); fclose(infile); return 4; /* out of memory */ } /* * block to handle libpng errors, * then check whether the PNG file had a bKGD chunk */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(infile); return 0; } /* * takes our file stream pointer (infile) and * stores it in the png_ptr struct for later use. */ /* png_ptr->io_ptr = (png_voidp)infile;*/ png_init_io(png_ptr, infile); /* * lets libpng know that we already checked the 8 * signature bytes, so it should not expect to find * them at the current file pointer location */ png_set_sig_bytes(png_ptr, 8); /* Read the image info.*/ /* * reads and processes not only the PNG file's IHDR chunk * but also any other chunks up to the first IDAT * (i.e., everything before the image data). */ /* read all the info up to the image data */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); *pwidth = width; *pheight = height; if (bit_depth > 8) { png_set_strip_16(png_ptr); } #if defined(__DAVAENGINE_WIN32__) if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); #endif if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); if (CommandLineParser::Instance()->GetVerbose()) printf("*** TOCHECK: convert tRNS to alpha\n"); } if (color_type == PNG_COLOR_TYPE_RGB) { if (CommandLineParser::Instance()->GetVerbose()) printf("*** Converting %s from RGB to RGBA\n", file); png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER); } /* Update the png info struct.*/ png_read_update_info(png_ptr, info_ptr); /* Rowsize in bytes. */ rowbytes = png_get_rowbytes(png_ptr, info_ptr); char string_format[16]; strcpy(string_format, "undefined"); if (color_type == PNG_COLOR_TYPE_RGBA) { strcpy(string_format, "RGBA"); } if (CommandLineParser::Instance()->GetVerbose()) { printf("* Reading PNG file: %s format: %s bit_depth:%d bytes_per_pixel:%d\n", file, string_format, bit_depth, rowbytes / width); } /* Allocate the image_data buffer. */ // printf("r/w: %d %d\n" , rowbytes / width, bit_depth); if ((image_data = new uint8 [rowbytes * height]) ==NULL) { memset(image_data, 0, rowbytes * height); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 4; } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete [] (image_data); image_data = NULL; return 4; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < (int)height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ /* Clean up. */ free(row_pointers); /* Clean up. */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(infile); *image_data_ptr = image_data; return 1; }
/* This routine is based in part on the Chapter 13 demo code in * "PNG: The Definitive Guide" (http://www.libpng.org/pub/png/book/). */ BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile) { png_byte sig[8]; #ifdef PNG_SETJMP_SUPPORTED jmpbuf_wrapper jbw; #endif png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height, rowbytes, w, h, res_x, res_y; int bit_depth, color_type, interlace_type, unit_type; int num_palette, num_trans; png_colorp palette; png_color_16p trans_gray_rgb; png_color_16p trans_color_rgb; png_bytep trans; png_bytep image_data = NULL; png_bytepp row_pointers = NULL; gdImagePtr im = NULL; int i, j, *open = NULL; volatile int transparent = -1; volatile int palette_allocated = FALSE; /* Make sure the signature can't match by dumb luck -- TBB */ /* GRR: isn't sizeof(infile) equal to the size of the pointer? */ memset (sig, 0, sizeof (sig)); /* first do a quick check that the file really is a PNG image; could * have used slightly more general png_sig_cmp() function instead */ if (gdGetBuf (sig, 8, infile) < 8) { return NULL; } if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */ return NULL; /* bad signature */ } #ifdef PNG_SETJMP_SUPPORTED png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL); #else png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif if (png_ptr == NULL) { gd_error("gd-png error: cannot allocate libpng main struct\n"); return NULL; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { gd_error("gd-png error: cannot allocate libpng info struct\n"); png_destroy_read_struct (&png_ptr, NULL, NULL); return NULL; } /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* setjmp() must be called in every non-callback function that calls a * PNG-reading libpng function */ #ifdef PNG_SETJMP_SUPPORTED if (setjmp(jbw.jmpbuf)) { gd_error("gd-png error: setjmp returns error condition 1\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } #endif png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ png_set_read_fn (png_ptr, (void *) infile, gdPngReadData); 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, &interlace_type, NULL, NULL); if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { im = gdImageCreateTrueColor ((int) width, (int) height); } else { im = gdImageCreate ((int) width, (int) height); } if (im == NULL) { gd_error("gd-png error: cannot allocate gdImage struct\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } if (bit_depth == 16) { png_set_strip_16 (png_ptr); } else if (bit_depth < 8) { png_set_packing (png_ptr); /* expand to 1 byte per pixel */ } /* setjmp() must be called in every non-callback function that calls a * PNG-reading libpng function */ #ifdef PNG_SETJMP_SUPPORTED if (setjmp(jbw.jmpbuf)) { gd_error("gd-png error: setjmp returns error condition 2\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); gdFree(image_data); gdFree(row_pointers); if (im) { gdImageDestroy(im); } return NULL; } #endif #ifdef PNG_pHYs_SUPPORTED /* check if the resolution is specified */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) { switch (unit_type) { case PNG_RESOLUTION_METER: im->res_x = DPM2DPI(res_x); im->res_y = DPM2DPI(res_y); break; } } } #endif switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette); #ifdef DEBUG gd_error("gd-png color_type is palette, colors: %d\n", num_palette); #endif /* DEBUG */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { /* gd 2.0: we support this rather thoroughly now. Grab the * first fully transparent entry, if any, as the value of * the simple-transparency index, mostly for backwards * binary compatibility. The alpha channel is where it's * really at these days. */ int firstZero = 1; png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL); for (i = 0; i < num_trans; ++i) { im->alpha[i] = gdAlphaMax - (trans[i] >> 1); if ((trans[i] == 0) && (firstZero)) { /* 2.0.5: long-forgotten patch from Wez Furlong */ transparent = i; firstZero = 0; } } } break; case PNG_COLOR_TYPE_GRAY: /* create a fake palette and check for single-shade transparency */ if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) { gd_error("gd-png error: cannot allocate gray palette\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } palette_allocated = TRUE; if (bit_depth < 8) { num_palette = 1 << bit_depth; for (i = 0; i < 256; ++i) { j = (255 * i) / (num_palette - 1); palette[i].red = palette[i].green = palette[i].blue = j; } } else { num_palette = 256; for (i = 0; i < 256; ++i) { palette[i].red = palette[i].green = palette[i].blue = i; } } if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb); if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */ transparent = trans_gray_rgb->gray >> 8; } else { transparent = trans_gray_rgb->gray; } /* Note slight error in 16-bit case: up to 256 16-bit shades * may get mapped to a single 8-bit shade, and only one of them * is supposed to be transparent. IOW, both opaque pixels and * transparent pixels will be mapped into the transparent entry. * There is no particularly good way around this in the case * that all 256 8-bit shades are used, but one could write some * custom 16-bit code to handle the case where there are gdFree * palette entries. This error will be extremely rare in * general, though. (Quite possibly there is only one such * image in existence.) */ }
~PngContext() { png_destroy_read_struct(&png, &info, &endinfo); }
bool SkPNGImageDecoderMy::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp, png_infop *info_ptrp) { /* 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. */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL); // png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { return false; } *png_ptrp = png_ptr; /* Allocate/initialize the memory for image information. */ 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 false; } *info_ptrp = info_ptr; /* 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))) { return false; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); png_set_seek_fn(png_ptr, sk_seek_fn); /* where user_io_ptr is a structure you want available to the callbacks */ /* If we have already read some of the signature */ // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); // hookup our peeker so we can see any user-chunks the caller may be interested in png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); if (this->getPeeker()) { png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); } /* 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 bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (bit_depth == 16) { 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). */ if (bit_depth < 8) { 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_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } return true; }
short load_inp_png_file(ImageData& img, const std::string& fname_inp, ProgramOptions& opts) { FILE* pngfile = fopen(fname_inp.c_str(),"rb"); if (pngfile == NULL) { perror(fname_inp.c_str()); return ERR_CANT_OPEN; } png_byte header[8]; if (fread(header,8,1,pngfile) != 1) { perror(fname_inp.c_str()); fclose(pngfile); return ERR_FILE_READ; } if (png_sig_cmp(header,0,8)) { LogErr("%s: Not a PNG file",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!img.png_ptr) { LogErr("%s: png_create_read_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.info_ptr=png_create_info_struct(img.png_ptr); if (!img.info_ptr) { png_destroy_read_struct(&img.png_ptr, (png_infopp)NULL, (png_infopp)NULL); LogErr("%s: png_create_info_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.end_info=png_create_info_struct(img.png_ptr); if (!img.end_info) { png_destroy_read_struct(&img.png_ptr, &img.info_ptr, (png_infopp)NULL); LogErr("%s: png_create_info_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } if (setjmp(png_jmpbuf(img.png_ptr))) { png_destroy_read_struct(&img.png_ptr, &img.info_ptr, &img.end_info); LogErr("%s: PNG error",fname_inp.c_str()); fclose(pngfile); exit(1); } png_init_io(img.png_ptr, pngfile); png_set_sig_bytes(img.png_ptr,8); int trafo=PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_EXPAND; png_read_png(img.png_ptr, img.info_ptr, trafo , NULL); int bit_depth, interlace_type, compression_type, filter_method; png_get_IHDR(img.png_ptr, img.info_ptr, &img.width, &img.height, &bit_depth, &img.color_type, &interlace_type, &compression_type, &filter_method); if ((img.color_type & PNG_COLOR_MASK_COLOR)==0) { LogErr("%s: Grayscale image not supported",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } fclose(pngfile); if (img.color_type==PNG_COLOR_TYPE_PALETTE) { LogErr("Invalid format. This shouldn't happen. PNG_TRANSFORM_EXPAND transforms image to RGB."); return ERR_BAD_FILE; } if (img.color_type & PNG_COLOR_MASK_ALPHA) { img.col_bits = 32; } else { img.col_bits = 24; } return ERR_OK; }
int main(int argc, char *argv[]) { char filename1[MAXNAMELENGTH], filename2[MAXNAMELENGTH]; int idx, k, j; FILE *fd, *lut=NULL; byte *imgarr; int userfill=-1; int colorstyle=GRAYSCALE; int red, green, blue, alpha; int redarr[256], greenarr[256], bluearr[256], alphaarr[256]; unsigned char lutname[MAXNAMELENGTH]; unsigned char verbose=FALSE; png_structp png_ptr; png_infop info_ptr; png_colorp png_palette; png_colorp dest_pal; unsigned char *png_trans; png_structp in_png_ptr; png_infop in_info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; png_uint_32 i, rowbytes; byte *image_data = NULL; png_bytepp row_pointers = NULL; int bytesperpixel; int found; int num_not_found=0; int rednotfound[MAX_NOT_FOUND], greennotfound[MAX_NOT_FOUND], bluenotfound[MAX_NOT_FOUND]; int return_code=0; filename1[0] = '\0'; filename2[0] = '\0'; lutname[0] = '\0'; if (argc < 2) { fprintf(stderr, "Usage: RGBApng2Palpng [-v] -lut=<ColorMap file (must contain RGBA)> -fill=<LUT index value> -of=<output palette PNG file> <input RGBA PNG file>\n"); exit(-1); } for (j=1; j<argc; j++) if ( strcmp(argv[j], "-v") == 0 ) { fprintf(stderr, "Verbose mode requested.\n"); verbose = TRUE; } for (j=1; j<argc; j++) { if (strstr(argv[j], "-of=") == argv[j] ) { if ( sscanf(argv[j], "-of=%s", filename2) != 1 ) { fprintf(stderr, "Cannot read output file\n"); exit(-1); } if (verbose) fprintf(stderr, "Output file: %s\n", filename2); } else if (strstr(argv[j], "-lut=") == argv[j] ) { if ( sscanf(argv[j], "-lut=%s", lutname) != 1 ) { fprintf(stderr, "Cannot parse LUT name\n"); exit(-1); } if (verbose) fprintf(stderr, "Color LUT: %s\n", lutname); colorstyle = COLOR; } else if (strstr(argv[j], "-fill=") == argv[j] ) { if (sscanf(argv[j], "-fill=%d", &userfill) != 1) { fprintf(stderr, "Cannot read user fill value\n"); exit(-1); } if ( userfill < 0 || userfill > 255 ) { fprintf(stderr, "User fill value must be between 0 and 255\n"); exit(-1); } if (verbose) fprintf(stderr, "User fill value: %d\n", userfill); } else if ( strlen(filename2) == 0 && strcmp(argv[j], "-") == 0 ) { strcpy(filename2, "stdout"); if (verbose) fprintf(stderr, "Output file: %s\n", filename2); } else if ( strcmp(argv[j], "-v") != 0 ) { strcpy(filename1, argv[j]); if (verbose) fprintf(stderr, "Input file: %s\n", filename1); } } if ( strlen(filename1) == 0 || strlen(filename2) == 0 || strlen(lutname) == 0 || userfill < 0 ) { fprintf(stderr, "Unable to get all arguments\n"); exit(-1); } if ((fp = fopen(filename1, "rb")) == NULL) { fprintf(stderr, "Unable to open input file: %s\n", filename1); exit(-1); } in_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (in_png_ptr == NULL) { fclose(fp); fprintf(stderr, "Could not allocate PNG read struct\n"); return (-1); } in_info_ptr = png_create_info_struct(in_png_ptr); if (in_info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&in_png_ptr, png_infopp_NULL, png_infopp_NULL); fprintf(stderr, "Could not allocate input PNG info struct\n"); return (-1); } if (setjmp(png_jmpbuf(in_png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&in_png_ptr, &in_info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (-1); } /* Set up the input control if you are using standard C streams */ png_init_io(in_png_ptr, fp); png_read_info(in_png_ptr, in_info_ptr); png_get_IHDR(in_png_ptr, in_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); if (verbose) { fprintf(stderr, "Width: %d\n", width); fprintf(stderr, "Height: %d\n", height); fprintf(stderr, "Bit Depth: %d\n", bit_depth); switch(color_type) { case 0: fprintf(stderr, "Color Type: Gray (0)\n"); break; case 3: fprintf(stderr, "Color Type: Palette (3)\n"); break; case 2: fprintf(stderr, "Color Type: RGB (2)\n"); break; case 6: fprintf(stderr, "Color Type: RGB Alpha (6)\n"); break; case 4: fprintf(stderr, "Color Type: Gray Alpha (4)\n"); break; default: fprintf(stderr, "Unknown Color Type: %d\n", color_type); } switch(interlace_type) { case 0: fprintf(stderr, "Interlace Type: None (0)\n"); break; case 1: fprintf(stderr, "Interlace Type: Adam7 (1)\n"); break; default: fprintf(stderr, "Unknown Interlace Type: %d\n", interlace_type); } } rowbytes = png_get_rowbytes(in_png_ptr, in_info_ptr); if ( verbose ) fprintf(stderr, "Number of bytes per row: %d\n", rowbytes); if ((image_data = (byte *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL); exit(-1); } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL); free(image_data); image_data = NULL; exit(-1); } for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(in_png_ptr, row_pointers); imgarr = (byte *) malloc(height * width * sizeof(byte)); png_palette = (png_colorp)malloc( 256 * sizeof( png_color) ); dest_pal = png_palette; if (colorstyle == GRAYSCALE) for (j=0; j<256; j++) { dest_pal->red = dest_pal->green = dest_pal->blue = j; dest_pal++; redarr[j] = greenarr[j] = bluearr[j] = j; alphaarr[j] = 255; } else { if ( (lut = fopen(lutname, "r")) != NULL ) { if (strlen(lutname) > 4 && ((!strcmp(lutname + strlen(lutname) - 4, ".xml")))) { fprintf(stderr, "Opening colormap file %s\n", lutname); if (lut) { int size = 1024, pos; int c; int j = 0; char *buffer = (char *)malloc(size); const char *entry_key = "ColorMapEntry"; const char *rgb_key = "rgb="; const char *transparent_key = "transparent="; const char *true_str = "\"true\""; do { // read all lines in file pos = 0; do { // read one line c = fgetc(lut); if(c != EOF) buffer[pos++] = (char)c; if(pos >= size - 1) { // increase buffer length - leave room for 0 size *=2; buffer = (char*)realloc(buffer, size); } } while(c != EOF && c != '\n'); buffer[pos] = 0; char *entry = strstr(buffer,entry_key); char *rgb = strstr(buffer,rgb_key); char *transparent = strstr(buffer,transparent_key); // GIBS colormap RGB values if (rgb != NULL && entry != NULL) { char rgb_string[11]; int rgb_length = strlen(rgb); int rgb_pos = pos - rgb_length; memcpy(rgb_string, &buffer[rgb_pos+5], 11); rgb_string[11] = '\0'; // break rgb string into int values int rgb_array[3]; int i = 0; char *rgb_values = strtok(rgb_string, ","); while (rgb_values != NULL) { rgb_array[i++] = strtol(rgb_values,NULL,10); rgb_values = strtok(NULL, ","); } red = rgb_array[0]; green = rgb_array[1]; blue = rgb_array[2]; dest_pal->red = red; dest_pal->green = green; dest_pal->blue = blue; alpha = strstr(transparent, true_str) != NULL ? 0 : 255; dest_pal++; redarr[j] = red; greenarr[j] = green; bluearr[j] = blue; alphaarr[j] = alpha; if ( verbose ) fprintf(stderr, "RGBA: %d %d %d %d \n", redarr[j], greenarr[j] , bluearr[j], alphaarr[j]); j++; } } while(c != EOF);; fclose(lut); free(buffer); } } else { for (j=0; j<256; j++) if ( fscanf(lut, "%d %d %d %d", &red, &green, &blue, &alpha) != 4 ) { fprintf(stderr, "Cannot read color index %d in LUT file\n", j); exit(-1); } else { dest_pal->red = red; dest_pal->green = green; dest_pal->blue = blue; dest_pal++; redarr[j] = red; greenarr[j] = green; bluearr[j] = blue; alphaarr[j] = alpha; } fclose(lut); } } else { fprintf(stderr, "Cannot open LUT file %s.\n", lutname); exit(-1); } } png_trans = (unsigned char *)malloc(256 * sizeof(unsigned char)); for (j=0; j<256; j++) { png_trans[j] = alphaarr[j]; } switch(color_type) { case(PNG_COLOR_TYPE_GRAY): bytesperpixel = 1; break; case(PNG_COLOR_TYPE_PALETTE): bytesperpixel = 1; break; case(PNG_COLOR_TYPE_RGB): bytesperpixel = 3; break; case(PNG_COLOR_TYPE_RGB_ALPHA): bytesperpixel = 4; break; case(PNG_COLOR_TYPE_GRAY_ALPHA): bytesperpixel = 2; break; default: fprintf(stderr, "Unknown Color Type: %d\n", color_type); exit(-1); } if ( color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA ) { fprintf(stderr, "Color Type must be RGB or RGBA.\n"); exit(-1); } if ( verbose ) fprintf(stderr, "Bytes per Pixel: %d\n", bytesperpixel); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { idx = i*width+j; red = image_data[i*width*bytesperpixel+j*bytesperpixel]; green = image_data[i*width*bytesperpixel+j*bytesperpixel+1]; blue = image_data[i*width*bytesperpixel+j*bytesperpixel+2]; found = FALSE; for (k = 0; k < 256; k++) { if ( red == redarr[k] && green == greenarr[k] && blue == bluearr[k] ) { imgarr[idx] = (unsigned char) k; found = TRUE; break; } } if ( !found ) { imgarr[idx] = (unsigned char) userfill; found = FALSE; if ( num_not_found < MAX_NOT_FOUND ) { for (k = 0; k < num_not_found; k++) { if ( red == rednotfound[k] && green == greennotfound[k] && blue == bluenotfound[k] ) { found = TRUE; break; } } if ( !found ) { rednotfound[num_not_found] = red; greennotfound[num_not_found] = green; bluenotfound[num_not_found] = blue; num_not_found++; } } } } } if ( num_not_found > 0 ) { return_code = num_not_found; fprintf(stderr, "%d Colors in image not found in color table\n", num_not_found); for (k = 0; k < num_not_found; k++) { fprintf(stderr, "%3d %3d %3d\n", rednotfound[k], greennotfound[k], bluenotfound[k]); } } // Done with the read, clean up free(row_pointers); row_pointers = NULL; png_read_end(in_png_ptr, NULL); free(image_data); image_data = NULL; fclose(fp); // Start the write if (strcmp(filename2, "stdout") == 0) fd = stdout; else if ( (fd = fopen(filename2, "wb")) == NULL ) { fprintf(stderr, "Cannot open file %s.\n", filename2); exit(-1); } // Initialize write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fprintf(stderr, "Could not allocate PNG write struct\n"); exit(-1); } // Initialize info structure info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fprintf(stderr, "Could not allocate PNG info struct\n"); exit(-1); } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG init_io\n"); exit(-1); } png_init_io(png_ptr, fd); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set header\n"); exit(-1); } // Write header (8 bit colour depth) png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set pallette\n"); exit(-1); } png_set_PLTE(png_ptr, info_ptr, png_palette, 256); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG set transparency\n"); exit(-1); } png_set_tRNS(png_ptr, info_ptr, png_trans, 256, NULL); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write info\n"); exit(-1); } png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write row\n"); exit(-1); } for (k=0; k<height; k++) { idx = k * width; png_write_row(png_ptr, &imgarr[idx]); } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during PNG write end\n"); exit(-1); } // End write png_write_end(png_ptr, NULL); fclose(fd); free(imgarr); free(png_palette); free(png_trans); if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return return_code; }
struct IplImage *ipl_readimg(char *path, int mode) { FILE *f; unsigned char head[8]; int numb = 8, w, h, nchans = 3, y; size_t sznumb; struct IplImage *res; png_bytep* rows; png_structp pngp; png_infop infop; if (!(f = fopen(path, "rb"))) { perror("error opening file\n"); return NULL; } sznumb = fread(head, sizeof(char), numb, f); if (png_sig_cmp(head, 0, 8)) { perror("is not png"); fclose(f); return NULL; } if (!(pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) { perror("can't create read struct"); fclose(f); return NULL; } if (!(infop = png_create_info_struct(pngp))) { perror("can't create info"); png_destroy_read_struct(&pngp, NULL, NULL); fclose(f); return NULL; } if (setjmp(png_jmpbuf(pngp))) { perror("error in jumpbuf"); png_destroy_read_struct(&pngp, &infop, NULL); fclose(f); return NULL; } png_init_io(pngp, f); png_set_sig_bytes(pngp, sznumb); png_read_info(pngp, infop); png_set_strip_alpha(pngp); png_set_strip_16(pngp); if (mode) { nchans = 3; png_set_palette_to_rgb(pngp); } else { nchans = 1; png_set_rgb_to_gray(pngp, 1, 0.0f, 0.0f); png_set_expand_gray_1_2_4_to_8(pngp); } png_set_interlace_handling(pngp); png_read_update_info(pngp, infop); w = png_get_image_width(pngp, infop); h = png_get_image_height(pngp, infop); rows = (png_bytep *)malloc(sizeof(png_bytep) * h); for (y = 0; y < h; y++) { rows[y] = (png_byte *)malloc(png_get_rowbytes(pngp, infop)); } png_read_image(pngp, rows); res = (struct IplImage *)malloc(sizeof(struct IplImage)); res->width = w; res->height = h; res->nchans = nchans; res->data = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 3); for (y = 0; y < h; y++) memcpy(&(res->data[nchans * y * w]), rows[y], sizeof(png_byte) * png_get_rowbytes(pngp, infop)); for (y = 0; y < h; y++) free(rows[y]); free(rows); fclose(f); return res; }
int png_include_image (pdf_ximage *ximage, FILE *png_file) { pdf_obj *stream; pdf_obj *stream_dict; pdf_obj *colorspace, *mask, *intent; png_bytep stream_data_ptr; int trans_type; ximage_info info; /* Libpng stuff */ png_structp png_ptr; png_infop png_info_ptr; png_byte bpc, color_type; png_uint_32 width, height, rowbytes; pdf_ximage_init_image_info(&info); stream = NULL; stream_dict = NULL; colorspace = mask = intent = NULL; rewind (png_file); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, warn); if (png_ptr == NULL || (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) { WARN("%s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return -1; } #if PNG_LIBPNG_VER >= 10603 /* ignore possibly incorrect CMF bytes */ png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON); #endif /* Inititializing file IO. */ png_init_io (png_ptr, png_file); /* Read PNG info-header and get some info. */ png_read_info(png_ptr, png_info_ptr); color_type = png_get_color_type (png_ptr, png_info_ptr); width = png_get_image_width (png_ptr, png_info_ptr); height = png_get_image_height(png_ptr, png_info_ptr); bpc = png_get_bit_depth (png_ptr, png_info_ptr); /* We do not need 16-bpc color. Ask libpng to convert down to 8-bpc. */ if (bpc > 8) { png_set_strip_16(png_ptr); bpc = 8; } /* Ask libpng to gamma-correct. * It is wrong to assume screen gamma value 2.2 but... * We do gamma correction here only when uncalibrated color space is used. */ if (!png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_cHRM) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) && png_get_valid(png_ptr, png_info_ptr, PNG_INFO_gAMA)) { double G = 1.0; png_get_gAMA (png_ptr, png_info_ptr, &G); png_set_gamma(png_ptr, 2.2, G); } trans_type = check_transparency(png_ptr, png_info_ptr); /* check_transparency() does not do updata_info() */ png_read_update_info(png_ptr, png_info_ptr); rowbytes = png_get_rowbytes(png_ptr, png_info_ptr); /* Values listed below will not be modified in the remaining process. */ info.width = width; info.height = height; info.bits_per_component = bpc; if (compat_mode) info.xdensity = info.ydensity = 72.0 / 100.0; else { png_uint_32 xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr); png_uint_32 yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr); if (xppm > 0) info.xdensity = 72.0 / 0.0254 / xppm; if (yppm > 0) info.ydensity = 72.0 / 0.0254 / yppm; } stream = pdf_new_stream (STREAM_COMPRESS); stream_dict = pdf_stream_dict(stream); stream_data_ptr = (png_bytep) NEW(rowbytes*height, png_byte); read_image_data(png_ptr, stream_data_ptr, height, rowbytes); /* Non-NULL intent means there is valid sRGB chunk. */ intent = get_rendering_intent(png_ptr, png_info_ptr); if (intent) pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: colorspace = create_cspace_Indexed(png_ptr, png_info_ptr); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: /* Color-key masking */ mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: /* Soft mask */ mask = create_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, width, height); break; default: /* Nothing to be done here. * No tRNS chunk or image already composited with background color. */ break; } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalRGB(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceRGB"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; /* rowbytes changes 4 to 3 at here */ case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 3; break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalGray(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceGray"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 1; break; default: WARN("%s: Unknown PNG colortype %d.", PNG_DEBUG_STR, color_type); } pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace); pdf_add_stream(stream, stream_data_ptr, rowbytes*height); RELEASE(stream_data_ptr); if (mask) { if (trans_type == PDF_TRANS_TYPE_BINARY) pdf_add_dict(stream_dict, pdf_new_name("Mask"), mask); else if (trans_type == PDF_TRANS_TYPE_ALPHA) { pdf_add_dict(stream_dict, pdf_new_name("SMask"), pdf_ref_obj(mask)); pdf_release_obj(mask); } else { WARN("%s: Unknown transparency type...???", PNG_DEBUG_STR); pdf_release_obj(mask); } } /* Finally read XMP Metadata * See, XMP Specification Part 3, Storage in Files * http://www.adobe.com/jp/devnet/xmp.html * * We require libpng version >= 1.6.14 since prior versions * of libpng had a bug that incorrectly treat the compression * flag of iTxt chunks. */ #if PNG_LIBPNG_VER >= 10614 if (pdf_get_version() >= 4) { png_textp text_ptr; pdf_obj *XMP_stream, *XMP_stream_dict; int i, num_text; int have_XMP = 0; num_text = png_get_text(png_ptr, png_info_ptr, &text_ptr, NULL); for (i = 0; i < num_text; i++) { if (!memcmp(text_ptr[i].key, "XML:com.adobe.xmp", 17)) { /* XMP found */ if (text_ptr[i].compression != PNG_ITXT_COMPRESSION_NONE || text_ptr[i].itxt_length == 0) WARN("%s: Invalid value(s) in iTXt chunk for XMP Metadata.", PNG_DEBUG_STR); else if (have_XMP) WARN("%s: Multiple XMP Metadata. Don't know how to treat it.", PNG_DEBUG_STR); else { /* We compress XMP metadata for included images here. * It is not recommended to compress XMP metadata for PDF documents but * we compress XMP metadata for included images here to avoid confusing * application programs that only want PDF document global XMP metadata * and scan for that. */ XMP_stream = pdf_new_stream(STREAM_COMPRESS); XMP_stream_dict = pdf_stream_dict(XMP_stream); pdf_add_dict(XMP_stream_dict, pdf_new_name("Type"), pdf_new_name("Metadata")); pdf_add_dict(XMP_stream_dict, pdf_new_name("Subtype"), pdf_new_name("XML")); pdf_add_stream(XMP_stream, text_ptr[i].text, text_ptr[i].itxt_length); pdf_add_dict(stream_dict, pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream)); pdf_release_obj(XMP_stream); have_XMP = 1; } } } } #endif /* PNG_LIBPNG_VER */ png_read_end(png_ptr, NULL); /* Cleanup */ if (png_info_ptr) png_destroy_info_struct(png_ptr, &png_info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); pdf_ximage_set_image(ximage, &info, stream); return 0; }
static HPDF_STATUS LoadPngData (HPDF_Dict image, HPDF_Xref xref, HPDF_Stream png_data, HPDF_BOOL delayed_loading) { HPDF_STATUS ret = HPDF_OK; 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; } /* 16bit images are not supported. */ if (info_ptr->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 & info_ptr->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)info_ptr->width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)info_ptr->height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)info_ptr->bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, info_ptr->width * info_ptr->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, info_ptr->width * info_ptr->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)info_ptr->width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)info_ptr->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 & info_ptr->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)info_ptr->width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)info_ptr->height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)info_ptr->bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, info_ptr->width * info_ptr->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, info_ptr->width * info_ptr->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 += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)info_ptr->width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)info_ptr->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 (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ret = CreatePallet(image, png_ptr, info_ptr); else if (info_ptr->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)info_ptr->width) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)info_ptr->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; }