//.........这里部分代码省略.........
}
info_ptr = png_create_info_struct (png_ptr);
if ( setjmp (png_jmpbuf (png_ptr)) )
{
return 0;
}
// We've read the signature
offset += SIGNATURE_LEN;
// Setup reading information, and read header
png_set_read_fn (png_ptr, (png_voidp)this, &user_read_data);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
// This generic "ignore all, except required chunks" requires 1.6.0 or newer"
png_set_keep_unknown_chunks (png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, -1);
#endif
png_set_sig_bytes (png_ptr, SIGNATURE_LEN);
png_read_info (png_ptr, info_ptr);
png_uint_32 width_;
png_uint_32 height_;
int depth;
int colortype;
png_get_IHDR (png_ptr, info_ptr, &width_, &height_, &depth, &colortype, NULL, NULL, NULL);
// While modern OpenGL can handle non-PoT textures, it's faster to handle only PoT
// so that the graphics driver doesn't have to fiddle about with the texture when uploading.
if ( !IsPowerOfTwo (width_) || !IsPowerOfTwo (height_) )
{
ri->Printf (PRINT_ERROR, "Width or height is not a power-of-two.\n");
return 0;
}
// This function is equivalent to using what used to be LoadPNG32. LoadPNG8 also existed,
// but this only seemed to be used by the RMG system which does not work in JKA. If this
// does need to be re-implemented, then colortype should be PNG_COLOR_TYPE_PALETTE or
// PNG_COLOR_TYPE_GRAY.
if ( colortype != PNG_COLOR_TYPE_RGB && colortype != PNG_COLOR_TYPE_RGBA )
{
ri->Printf (PRINT_ERROR, "Image is not 24-bit or 32-bit.");
return 0;
}
// Read the png data
if ( colortype == PNG_COLOR_TYPE_RGB )
{
// Expand RGB -> RGBA
png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
}
png_read_update_info (png_ptr, info_ptr);
// We always assume there are 4 channels. RGB channels are expanded to RGBA when read.
byte *tempData = (byte *)ri->Z_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse, 4);
if ( !tempData )
{
ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
return 0;
}
// Dynamic array of row pointers, with 'height' elements, initialized to NULL.
byte **row_pointers = (byte **)ri->Hunk_AllocateTempMemory (sizeof (byte *) * height_);
if ( !row_pointers )
{
ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
ri->Z_Free (tempData);
return 0;
}
// Re-set the jmp so that these new memory allocations can be reclaimed
if ( setjmp (png_jmpbuf (png_ptr)) )
{
ri->Hunk_FreeTempMemory (row_pointers);
ri->Z_Free (tempData);
return 0;
}
for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 )
{
row_pointers[i] = tempData + j * width_;
}
png_read_image (png_ptr, row_pointers);
// Finish reading
png_read_end (png_ptr, NULL);
ri->Hunk_FreeTempMemory (row_pointers);
// Finally assign all the parameters
*data = tempData;
*width = width_;
*height = height_;
return 1;
}
//.........这里部分代码省略.........
/* The call to png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk). REQUIRED
*/
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
/**** Set up the data transformations you want. Note that these are all
**** optional. Only call them if you want/need them. Many of the
**** transformations only work on specific types of images, and many
**** are mutually exclusive.
****/
/* tell libpng to strip 16 bit/color files down to 8 bits/color */
png_set_strip_16(png_ptr);
/* strip alpha bytes from the input data without combining with th
* 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_expand(png_ptr);
/* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
/* 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_expand(png_ptr);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
/* png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); */
png_read_update_info(png_ptr, info_ptr);
channels = png_get_channels(png_ptr, info_ptr);
/* allocate the memory to hold the image using the fields of info_ptr. */
bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);
buffer = (unsigned char*) malloc(bytes_per_row*height);
format = channels;
row_pointers = (png_bytepp) malloc(height*sizeof(png_bytep));
for (y = 0; y < height; y++) {
row_pointers[height-y-1] = buffer + y*bytes_per_row;
}
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, info_ptr);
free(row_pointers);
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
/* close the file */
fclose(fp);
/* that's it */
if (buffer) {
*width_ret = width;
*height_ret = height;
switch(format) {
case 1:
*type_ret = GL_LUMINANCE;
break;
case 2:
*type_ret = GL_LUMINANCE_ALPHA;
break;
case 3:
*type_ret = GL_RGB;
break;
case 4:
*type_ret = GL_RGBA;
break;
}
pngerror = ERR_NO_ERROR;
}
else {
pngerror = ERR_MEM;
}
return buffer;
}
//.........这里部分代码省略.........
SkAutoLockPixels alp(*decodedBitmap);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
}
/* Turn on interlace handling. REQUIRED if you are not using
* png_read_image(). To see how to handle interlacing passes,
* see the png_read_row() method below:
*/
const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
png_set_interlace_handling(png_ptr) : 1;
/* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (ie you selected such a transform above).
*/
png_read_update_info(png_ptr, info_ptr);
if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
for (int i = 0; i < number_passes; i++) {
for (png_uint_32 y = 0; y < origHeight; y++) {
uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
}
}
} else {
SkScaledBitmapSampler::SrcConfig sc;
int srcBytesPerPixel = 4;
if (colorTable != NULL) {
sc = SkScaledBitmapSampler::kIndex;
srcBytesPerPixel = 1;
} else if (hasAlpha) {
sc = SkScaledBitmapSampler::kRGBA;
} else {
sc = SkScaledBitmapSampler::kRGBX;
}
/* We have to pass the colortable explicitly, since we may have one
even if our decodedBitmap doesn't, due to the request that we
upscale png's palette to a direct model
*/
SkAutoLockColors ctLock(colorTable);
if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
return false;
}
const int height = decodedBitmap->height();
if (number_passes > 1) {
SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
uint8_t* base = (uint8_t*)storage.get();
size_t rb = origWidth * srcBytesPerPixel;
for (int i = 0; i < number_passes; i++) {
uint8_t* row = base;
for (png_uint_32 y = 0; y < origHeight; y++) {
uint8_t* bmRow = row;
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
row += rb;
}
}
// now sample it
base += sampler.srcY0() * rb;
for (int y = 0; y < height; y++) {
reallyHasAlpha |= sampler.next(base);
base += sampler.srcDY() * rb;
}
} else {
SkAutoMalloc storage(origWidth * srcBytesPerPixel);
uint8_t* srcRow = (uint8_t*)storage.get();
skip_src_rows(png_ptr, srcRow, sampler.srcY0());
for (int y = 0; y < height; y++) {
uint8_t* tmp = srcRow;
png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
reallyHasAlpha |= sampler.next(srcRow);
if (y < height - 1) {
skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
}
}
// skip the rest of the rows (if any)
png_uint_32 read = (height - 1) * sampler.srcDY() +
sampler.srcY0() + 1;
SkASSERT(read <= origHeight);
skip_src_rows(png_ptr, srcRow, origHeight - read);
}
}
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
if (0 != theTranspColor) {
reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
}
decodedBitmap->setIsOpaque(!reallyHasAlpha);
return true;
}
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;
}
请发表评论