support libpng-1.5

libpng-1.5 removes some old API that libvips still used ... update png
read/write to support the new API
This commit is contained in:
John Cupitt 2011-03-17 14:17:03 +00:00
parent 73839df294
commit 9297a96ecf
4 changed files with 97 additions and 73 deletions

14
TODO
View File

@ -1,18 +1,4 @@
- png read/write needs redoing:
http://www.libpng.org/pub/png/src/libpng-1.4.x-to-1.5.x-summary.txt
... the ability to directly access
the main libpng control structures, png_struct and png_info, deprecated
in earlier versions of libpng, has been completely removed from
libpng 1.5.
argh
- add FITS and MATLAB write

View File

@ -18,6 +18,8 @@
* - gtkdoc
* 8/1/11
* - get png resolution (thanks Zhiyu Wu)
* 17/3/11
* - update for libpng-1.5 API changes
*/
/*
@ -154,7 +156,7 @@ read_new( const char *name, IMAGE *out )
/* Catch PNG errors from png_create_info_struct().
*/
if( setjmp( read->pPng->jmpbuf ) ) {
if( setjmp( png_jmpbuf( read->pPng ) ) ) {
read_destroy( read );
return( NULL );
}
@ -174,25 +176,25 @@ static int
png2vips_interlace( Read *read )
{
const int rowbytes = IM_IMAGE_SIZEOF_LINE( read->out );
const int height = png_get_image_height( read->pPng, read->pInfo );
int y;
if( !(read->row_pointer = IM_ARRAY( NULL,
read->pInfo->height, png_bytep )) )
if( !(read->row_pointer = IM_ARRAY( NULL, height, png_bytep )) )
return( -1 );
if( !(read->data = (png_bytep) im_malloc( NULL,
read->pInfo->height * rowbytes )) )
if( !(read->data = (png_bytep) im_malloc( NULL, height * rowbytes )) )
return( -1 );
for( y = 0; y < (int) read->pInfo->height; y++ )
for( y = 0; y < (int) height; y++ )
read->row_pointer[y] = read->data + y * rowbytes;
if( im_outcheck( read->out ) ||
im_setupout( read->out ) ||
setjmp( read->pPng->jmpbuf ) )
setjmp( png_jmpbuf( read->pPng ) ) )
return( -1 );
png_read_image( read->pPng, read->row_pointer );
for( y = 0; y < (int) read->pInfo->height; y++ )
for( y = 0; y < height; y++ )
if( im_writeline( y, read->out, read->row_pointer[y] ) )
return( -1 );
@ -206,16 +208,18 @@ static int
png2vips_noninterlace( Read *read )
{
const int rowbytes = IM_IMAGE_SIZEOF_LINE( read->out );
const int height = png_get_image_height( read->pPng, read->pInfo );
int y;
if( !(read->data = (png_bytep) im_malloc( NULL, rowbytes )) )
return( -1 );
if( im_outcheck( read->out ) ||
im_setupout( read->out ) ||
setjmp( read->pPng->jmpbuf ) )
setjmp( png_jmpbuf( read->pPng ) ) )
return( -1 );
for( y = 0; y < (int) read->pInfo->height; y++ ) {
for( y = 0; y < height; y++ ) {
png_read_row( read->pPng, read->data, NULL );
if( im_writeline( y, read->out, read->data ) )
@ -230,36 +234,58 @@ png2vips_noninterlace( Read *read )
static int
png2vips( Read *read, int header_only )
{
int bands, bpp, type;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
int num_trans;
png_color_8p sig_bit;
png_uint_32 res_x, res_y;
int unit_type;
int bands, bpp, type;
double Xres, Yres;
if( setjmp( read->pPng->jmpbuf ) )
if( setjmp( png_jmpbuf( read->pPng ) ) )
return( -1 );
png_init_io( read->pPng, read->fp );
png_read_info( read->pPng, read->pInfo );
png_get_IHDR( read->pPng, read->pInfo,
&width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL );
png_get_tRNS( read->pPng, read->pInfo, NULL, &num_trans, NULL );
png_get_sBIT( read->pPng, read->pInfo, &sig_bit );
/* png_get_channels() gives us 1 band for palette images ... so look
* at colour_type for output bands.
*/
switch( read->pInfo->color_type ) {
switch( color_type ) {
case PNG_COLOR_TYPE_PALETTE:
bands = 3;
/* Don't know if this is really correct. If there are
* transparent pixels, assume we're going to output RGBA.
*/
if( read->pInfo->num_trans )
if( num_trans )
bands = 4;
break;
case PNG_COLOR_TYPE_GRAY: bands = 1; break;
case PNG_COLOR_TYPE_GRAY_ALPHA: bands = 2; break;
case PNG_COLOR_TYPE_RGB: bands = 3; break;
case PNG_COLOR_TYPE_RGB_ALPHA: bands = 4; break;
case PNG_COLOR_TYPE_GRAY:
bands = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
bands = 2;
break;
case PNG_COLOR_TYPE_RGB:
bands = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
bands = 4;
break;
default:
im_error( "im_png2vips", "%s", _( "unsupported color type" ) );
@ -268,7 +294,7 @@ png2vips( Read *read, int header_only )
/* 8 or 16 bit.
*/
bpp = read->pInfo->bit_depth > 8 ? 2 : 1;
bpp = bit_depth > 8 ? 2 : 1;
if( bpp > 1 ) {
if( bands < 3 )
@ -285,27 +311,29 @@ png2vips( Read *read, int header_only )
/* Expand palette images.
*/
if( read->pInfo->color_type == PNG_COLOR_TYPE_PALETTE )
if( color_type == PNG_COLOR_TYPE_PALETTE )
png_set_expand( read->pPng );
/* Expand <8 bit images to full bytes.
*/
if( read->pInfo->bit_depth < 8 ) {
if( bit_depth < 8 ) {
png_set_packing( read->pPng );
png_set_shift( read->pPng, &(read->pInfo->sig_bit) );
png_set_shift( read->pPng, sig_bit );
}
/* If we're an INTEL byte order machine and this is 16bits, we need
* to swap bytes.
*/
if( read->pInfo->bit_depth > 8 && !im_amiMSBfirst() )
if( bit_depth > 8 && !im_amiMSBfirst() )
png_set_swap( read->pPng );
/* Get resolution. I'm not sure what we should do for UNKNOWN, since
* vips is always pixels/mm.
*/
png_get_pHYs( read->pPng, read->pInfo,
&res_x, &res_y, &unit_type );
unit_type = PNG_RESOLUTION_METER;
res_x = 1000;
res_y = 1000;
png_get_pHYs( read->pPng, read->pInfo, &res_x, &res_y, &unit_type );
switch( unit_type ) {
case PNG_RESOLUTION_METER:
Xres = res_x / 1000.0;
@ -320,8 +348,7 @@ png2vips( Read *read, int header_only )
/* Set VIPS header.
*/
im_initdesc( read->out,
read->pInfo->width, read->pInfo->height, bands,
im_initdesc( read->out, width, height, bands,
bpp == 1 ? IM_BBITS_BYTE : IM_BBITS_SHORT,
bpp == 1 ? IM_BANDFMT_UCHAR : IM_BANDFMT_USHORT,
IM_CODING_NONE, type,

View File

@ -21,6 +21,8 @@
* - added im_vips2bufpng()
* 8/1/11
* - set png resolution (thanks Zhiyu Wu)
* 17/3/11
* - update for libpng-1.5 API changes
*/
/*
@ -169,7 +171,7 @@ write_new( IMAGE *in )
/* Catch PNG errors from png_create_info_struct().
*/
if( setjmp( write->pPng->jmpbuf ) ) {
if( setjmp( png_jmpbuf( write->pPng ) ) ) {
write_destroy( write );
return( NULL );
}
@ -197,7 +199,7 @@ write_png_block( REGION *region, Rect *area, void *a )
/* Catch PNG errors. Yuk.
*/
if( setjmp( write->pPng->jmpbuf ) )
if( setjmp( png_jmpbuf( write->pPng ) ) )
return( -1 );
for( i = 0; i < area->height; i++ )
@ -216,6 +218,9 @@ write_vips( Write *write, int compress, int interlace )
{
IMAGE *in = write->in;
int bit_depth;
int color_type;
int interlace_type;
int i, nb_passes;
g_assert( in->BandFmt == IM_BANDFMT_UCHAR ||
@ -225,7 +230,7 @@ write_vips( Write *write, int compress, int interlace )
/* Catch PNG errors.
*/
if( setjmp( write->pPng->jmpbuf ) )
if( setjmp( png_jmpbuf( write->pPng ) ) )
return( -1 );
/* Check input image.
@ -242,21 +247,26 @@ write_vips( Write *write, int compress, int interlace )
*/
png_set_compression_level( write->pPng, compress );
write->pInfo->width = in->Xsize;
write->pInfo->height = in->Ysize;
write->pInfo->bit_depth = (in->BandFmt == IM_BANDFMT_UCHAR ? 8 : 16);
write->pInfo->gamma = (float) 1.0;
bit_depth = in->BandFmt == IM_BANDFMT_UCHAR ? 8 : 16;
switch( in->Bands ) {
case 1: write->pInfo->color_type = PNG_COLOR_TYPE_GRAY; break;
case 2: write->pInfo->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
case 3: write->pInfo->color_type = PNG_COLOR_TYPE_RGB; break;
case 4: write->pInfo->color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
case 3: color_type = PNG_COLOR_TYPE_RGB; break;
case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
default:
g_assert( 0 );
}
interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
png_set_IHDR( write->pPng, write->pInfo,
in->Xsize, in->Ysize, bit_depth, color_type, interlace_type,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
png_set_gAMA( write->pPng, write->pInfo, (float) 1.0 );
/* Set resolution. libpnbg uses pixels per meter.
*/
png_set_pHYs( write->pPng, write->pInfo,
@ -268,7 +278,7 @@ write_vips( Write *write, int compress, int interlace )
/* If we're an intel byte order CPU and this is a 16bit image, we need
* to swap bytes.
*/
if( write->pInfo->bit_depth > 8 && !im_amiMSBfirst() )
if( bit_depth > 8 && !im_amiMSBfirst() )
png_set_swap( write->pPng );
if( interlace )
@ -284,7 +294,7 @@ write_vips( Write *write, int compress, int interlace )
/* The setjmp() was held by our background writer: reset it.
*/
if( setjmp( write->pPng->jmpbuf ) )
if( setjmp( png_jmpbuf( write->pPng ) ) )
return( -1 );
png_write_end( write->pPng, write->pInfo );
@ -389,24 +399,24 @@ im_vips2png( IMAGE *in, const char *filename )
return( 0 );
}
typedef struct _PngWriteBuf {
typedef struct _WriteBuf {
char *buf;
size_t len;
size_t alloc;
} PngWriteBuf;
} WriteBuf;
static void
png_write_buf_free( PngWriteBuf *wbuf )
write_buf_free( WriteBuf *wbuf )
{
IM_FREE( wbuf );
}
static PngWriteBuf *
png_write_buf_new( void )
static WriteBuf *
write_buf_new( void )
{
PngWriteBuf *wbuf;
WriteBuf *wbuf;
if( !(wbuf = IM_NEW( NULL, PngWriteBuf )) )
if( !(wbuf = IM_NEW( NULL, WriteBuf )) )
return( NULL );
wbuf->buf = NULL;
@ -417,7 +427,7 @@ png_write_buf_new( void )
}
static void
png_write_buf_grow( PngWriteBuf *wbuf, size_t grow_len )
write_buf_grow( WriteBuf *wbuf, size_t grow_len )
{
size_t new_len = wbuf->len + grow_len;
@ -434,7 +444,7 @@ png_write_buf_grow( PngWriteBuf *wbuf, size_t grow_len )
*/
wbuf->buf = g_realloc( wbuf->buf, wbuf->alloc );
VIPS_DEBUG_MSG( "png_write_buf_grow: grown to %zd bytes\n",
VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n",
wbuf->alloc );
}
}
@ -442,13 +452,14 @@ png_write_buf_grow( PngWriteBuf *wbuf, size_t grow_len )
static void
user_write_data( png_structp png_ptr, png_bytep data, png_size_t length )
{
PngWriteBuf *wbuf = (PngWriteBuf *) png_ptr->io_ptr;
WriteBuf *wbuf = (WriteBuf *) png_get_io_ptr( png_ptr );
char *write_start;
png_write_buf_grow( wbuf, length );
write_buf_grow( wbuf, length );
write_start = wbuf->buf + wbuf->len;
png_memcpy( write_start, data, length );
memcpy( write_start, data, length );
wbuf->len += length;
@ -479,10 +490,10 @@ int
im_vips2bufpng( IMAGE *in, IMAGE *out,
int compression, int interlace, char **obuf, size_t *olen )
{
PngWriteBuf *wbuf;
WriteBuf *wbuf;
Write *write;
if( !(wbuf = png_write_buf_new()) ||
if( !(wbuf = write_buf_new()) ||
!(write = write_new( in )) )
return( -1 );
@ -492,7 +503,7 @@ im_vips2bufpng( IMAGE *in, IMAGE *out,
*/
if( write_vips( write, compression, interlace ) ) {
write_destroy( write );
png_write_buf_free( wbuf );
write_buf_free( wbuf );
im_error( "im_vips2bufpng",
"%s", _( "unable to write to buffer" ) );
@ -503,7 +514,7 @@ im_vips2bufpng( IMAGE *in, IMAGE *out,
*obuf = wbuf->buf;
*olen = wbuf->len;
png_write_buf_free( wbuf );
write_buf_free( wbuf );
if( out && im_add_close_callback( out,
(im_callback_fn) im_free, *obuf, NULL ) ) {

View File

@ -1207,13 +1207,13 @@ vips_image_class_init( VipsImageClass *class )
static void
vips_image_init( VipsImage *image )
{
/* Init to 0 is fine for most header fields.
*/
/* Default to native order.
*/
image->magic = im_amiMSBfirst() ? VIPS_MAGIC_SPARC : VIPS_MAGIC_INTEL;
image->Xres = 1.0;
image->Yres = 1.0;
image->fd = -1; /* since 0 is stdout */
image->sslock = g_mutex_new();