From 57cf9011e71b426f1e1e18d2ec562710bacc11c2 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 9 Apr 2012 18:03:17 +0100 Subject: [PATCH] fix openslide read previously it returned Cairo-style pre-multiplied argb, now it always unpacks to png-style rgba for you there was no real use for the coded form and it was annoying to have to call im_argb2rgba() explicitly --- ChangeLog | 2 + libvips/colour/Makefile.am | 1 - libvips/colour/colour_dispatch.c | 20 ----- libvips/colour/im_argb2rgba.c | 110 ----------------------- libvips/deprecated/deprecated_dispatch.c | 20 +++++ libvips/deprecated/vips7compat.c | 8 ++ libvips/foreign/openslide2vips.c | 98 ++++++++++++-------- libvips/include/vips/colour.h | 1 - libvips/include/vips/header.h | 8 -- libvips/include/vips/vips7compat.h | 1 + 10 files changed, 91 insertions(+), 178 deletions(-) delete mode 100644 libvips/colour/im_argb2rgba.c diff --git a/ChangeLog b/ChangeLog index 86d32188..f0cb18ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ 6/4/12 started 7.28.3 - vips_divide() failed for int arguments - fix warning for unused vips7 gvalue argument +- fix openslide read: always return png-style rgba, im_argb2rgba() becomes a + NOP 13/3/12 started 7.28.2 - xres/yres tiffsave args were broken diff --git a/libvips/colour/Makefile.am b/libvips/colour/Makefile.am index 465fa53b..9fe708c6 100644 --- a/libvips/colour/Makefile.am +++ b/libvips/colour/Makefile.am @@ -6,7 +6,6 @@ libcolour_la_SOURCES = \ colour_dispatch.c \ derived.c \ im_icc_transform.c \ - im_argb2rgba.c \ im_LCh2Lab.c \ im_LCh2UCS.c \ im_Lab2LCh.c \ diff --git a/libvips/colour/colour_dispatch.c b/libvips/colour/colour_dispatch.c index eb4663ae..4534bd2d 100644 --- a/libvips/colour/colour_dispatch.c +++ b/libvips/colour/colour_dispatch.c @@ -640,25 +640,6 @@ static im_function rad2float_desc = { one_in_one_out /* Arg list */ }; -/* Call im_argb2rgba() via arg vector. - */ -static int -argb2rgba_vec( im_object *argv ) -{ - return( im_argb2rgba( argv[0], argv[1] ) ); -} - -/* Description of im_argb2rgba. - */ -static im_function argb2rgba_desc = { - "im_argb2rgba", /* Name */ - "convert pre-multipled argb to png-style rgba", /* Description */ - IM_FN_PIO, /* Flags */ - argb2rgba_vec, /* Dispatch function */ - IM_NUMBER( one_in_one_out ), /* Size of arg list */ - one_in_one_out /* Arg list */ -}; - /* Call im_float2rad() via arg vector. */ static int @@ -1204,7 +1185,6 @@ static im_function *colour_list[] = { &disp2Lab_desc, &disp2XYZ_desc, &float2rad_desc, - &argb2rgba_desc, &icc_ac2rc_desc, &icc_export_depth_desc, &icc_import_desc, diff --git a/libvips/colour/im_argb2rgba.c b/libvips/colour/im_argb2rgba.c deleted file mode 100644 index 90c3eac3..00000000 --- a/libvips/colour/im_argb2rgba.c +++ /dev/null @@ -1,110 +0,0 @@ -/* Convert pre-multipled argb to rgba - * - * 11/12/11 - * - from im_rad2float.c - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#include - -static void -argb2rgba( guint32 *in, VipsPel *out, int n, void *_bg ) -{ - guint32 bg = GPOINTER_TO_UINT( _bg ); - - int i; - - for( i = 0; i < n; i++ ) { - guint32 x = in[i]; - guint8 a = x >> 24; - - /* Convert from ARGB to RGBA and undo premultiplication. - */ - if( a != 0 ) { - out[0] = 255 * ((x >> 16) & 255) / a; - out[1] = 255 * ((x >> 8) & 255) / a; - out[2] = 255 * (x & 255) / a; - } - else { - /* Use background color. - */ - out[0] = (bg >> 16) & 255; - out[1] = (bg >> 8) & 255; - out[2] = bg & 255; - } - out[3] = a; - - out += 4; - } -} - -/** - * im_argb2rgba: - * @in: input image - * @out: output image - * - * Convert Cairo-style pre-multiplied argb to png-style rgba. Background - * pixels are painted with the metadata item "background-rgb". - * - * See also: im_openslide2vips(). - * - * Returns: 0 on success, -1 on error. - */ -int -im_argb2rgba( VipsImage *in, IMAGE *out ) -{ - guint32 bg; - - /* check for RAD coding - if( in->Coding != IM_CODING_RAD ) { - im_error( "im_rad2float", "%s", _( "not a RAD image" ) ); - return( -1 ); - } - */ - - if( im_cp_desc( out, in ) ) - return( -1 ); - out->Coding = IM_CODING_NONE; - - if( vips_image_get_int( in, VIPS_META_BACKGROUND_RGB, (int *) &bg ) ) - bg = 0xffffff; - - if( im_wrapone( in, out, - (im_wrapone_fn) argb2rgba, GUINT_TO_POINTER( bg ), NULL ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/deprecated/deprecated_dispatch.c b/libvips/deprecated/deprecated_dispatch.c index 2992f7b4..2bbeb062 100644 --- a/libvips/deprecated/deprecated_dispatch.c +++ b/libvips/deprecated/deprecated_dispatch.c @@ -2188,10 +2188,30 @@ static im_function ifthenelse_desc = { ifthenelse_args /* Arg list */ }; +/* Call im_argb2rgba() via arg vector. + */ +static int +argb2rgba_vec( im_object *argv ) +{ + return( im_argb2rgba( argv[0], argv[1] ) ); +} + +/* Description of im_argb2rgba. + */ +static im_function argb2rgba_desc = { + "im_argb2rgba", /* Name */ + "convert pre-multipled argb to png-style rgba", /* Description */ + IM_FN_PIO, /* Flags */ + argb2rgba_vec, /* Dispatch function */ + IM_NUMBER( one_in_one_out ), /* Size of arg list */ + one_in_one_out /* Arg list */ +}; + /* Package up all these functions. */ static im_function *deprecated_list[] = { + &argb2rgba_desc, &flood_copy_desc, &flood_blob_copy_desc, &flood_other_copy_desc, diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index b2fd04c4..b6398056 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -2098,3 +2098,11 @@ im_cache( VipsImage *in, VipsImage *out, return( vips_sink_screen( in, out, NULL, width, height, max, 0, NULL, NULL ) ); } + +int +im_argb2rgba( VipsImage *in, VipsImage *out ) +{ + /* No longer exists, just a null op. + */ + return( im_copy( in, out ) ); +} diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index 0d257336..6cfe15d7 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -26,6 +26,9 @@ * - turn into a set of read fns ready to be called from a class * 28/2/12 * - convert "layer" to "level" where externally visible + * 9/4/12 + * - move argb2rgba back in here, we don't have a use for coded pixels + * - small cleanups */ /* @@ -83,8 +86,9 @@ typedef struct { /* Only valid if associated == NULL. */ - int32_t layer; + int32_t level; double downsample; + uint32_t bg; } ReadSlide; int @@ -138,7 +142,7 @@ check_associated_image( openslide_t *osr, const char *name ) static ReadSlide * readslide_new( const char *filename, VipsImage *out, - int layer, const char *associated ) + int level, const char *associated ) { ReadSlide *rslide; int64_t w, h; @@ -150,7 +154,7 @@ readslide_new( const char *filename, VipsImage *out, g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), rslide ); - rslide->layer = layer; + rslide->level = level; rslide->associated = g_strdup( associated ); rslide->osr = openslide_open( filename ); @@ -160,8 +164,8 @@ readslide_new( const char *filename, VipsImage *out, return( NULL ); } - if( layer < 0 || - layer >= openslide_get_layer_count( rslide->osr ) ) { + if( level < 0 || + level >= openslide_get_layer_count( rslide->osr ) ) { vips_error( "openslide2vips", "%s", _( "invalid slide level" ) ); return( NULL ); @@ -180,23 +184,17 @@ readslide_new( const char *filename, VipsImage *out, } else { openslide_get_layer_dimensions( rslide->osr, - layer, &w, &h ); + level, &w, &h ); rslide->downsample = openslide_get_layer_downsample( - rslide->osr, layer ); - vips_image_set_int( out, "slide-level", layer ); + rslide->osr, level ); + vips_image_set_int( out, "slide-level", level ); vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); } - /* This tag is used by argb2rgba() to paint fully-transparent pixels. - */ - background = openslide_get_property_value( rslide->osr, - OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR ); - if( background != NULL ) - vips_image_set_int( out, - VIPS_META_BACKGROUND_RGB, - strtoul( background, NULL, 16 ) ); - else - vips_image_set_int( out, VIPS_META_BACKGROUND_RGB, 0xffffff ); + rslide->bg = 0xffffff; + if( (background = openslide_get_property_value( rslide->osr, + OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) ) + rslide->bg = strtoul( background, NULL, 16 ); if( w < 0 || h < 0 || rslide->downsample < 0 ) { vips_error( "openslide2vips", _( "getting dimensions: %s" ), @@ -228,11 +226,11 @@ readslide_new( const char *filename, VipsImage *out, int vips__openslide_read_header( const char *filename, VipsImage *out, - int layer, char *associated ) + int level, char *associated ) { ReadSlide *rslide; - if( !(rslide = readslide_new( filename, out, layer, associated )) ) + if( !(rslide = readslide_new( filename, out, level, associated )) ) return( -1 ); return( 0 ); @@ -243,30 +241,31 @@ vips__openslide_generate( VipsRegion *out, void *seq, void *_rslide, void *unused, gboolean *stop ) { ReadSlide *rslide = _rslide; + uint32_t bg = rslide->bg; VipsRect *r = &out->valid; + int n = r->width * r->height; + uint32_t *buf = (uint32_t *) VIPS_REGION_ADDR( out, r->left, r->top ); const char *error; - int x, y; + int i; VIPS_DEBUG_MSG( "vips__openslide_generate: %dx%d @ %dx%d\n", r->width, r->height, r->left, r->top ); - /* Fill in tile-sized chunks. Some versions of OpenSlide can fail for - * very large requests. + /* We're inside a cache, so requests should always be TILE_WIDTH by + * TILE_HEIGHT pixels and on a tile boundary. */ - for( y = 0; y < r->height; y += TILE_HEIGHT ) - for( x = 0; x < r->width; x += TILE_WIDTH ) { - int w = VIPS_MIN( TILE_WIDTH, r->width - x ); - int h = VIPS_MIN( TILE_HEIGHT, r->height - y ); + g_assert( (r->left % TILE_WIDTH) == 0 ); + g_assert( (r->height % TILE_HEIGHT) == 0 ); + g_assert( r->width <= TILE_WIDTH ); + g_assert( r->height <= TILE_HEIGHT ); - openslide_read_region( rslide->osr, - (uint32_t *) VIPS_REGION_ADDR( out, - r->left + x, r->top + y ), - (r->left + x) * rslide->downsample, - (r->top + y) * rslide->downsample, - rslide->layer, - w, h ); - } + openslide_read_region( rslide->osr, + buf, + r->left * rslide->downsample, + r->top * rslide->downsample, + rslide->level, + r->width, r->height ); error = openslide_get_error( rslide->osr ); if( error ) { @@ -276,18 +275,41 @@ vips__openslide_generate( VipsRegion *out, return( -1 ); } + /* Convert from ARGB to RGBA and undo premultiplication. + */ + for( i = 0; i < n; i++ ) { + uint32_t x = buf[i]; + uint8_t a = x >> 24; + VipsPel *out = (VipsPel *) (buf + i); + + if( a != 0 ) { + out[0] = 255 * ((x >> 16) & 255) / a; + out[1] = 255 * ((x >> 8) & 255) / a; + out[2] = 255 * (x & 255) / a; + out[3] = a; + } + else { + /* Use background color. + */ + out[0] = (bg >> 16) & 255; + out[1] = (bg >> 8) & 255; + out[2] = bg & 255; + out[3] = 0; + } + } + return( 0 ); } int -vips__openslide_read( const char *filename, VipsImage *out, int layer ) +vips__openslide_read( const char *filename, VipsImage *out, int level ) { ReadSlide *rslide; VipsImage *raw; VipsImage *t; VIPS_DEBUG_MSG( "vips__openslide_read: %s %d\n", - filename, layer ); + filename, level ); /* Tile cache: keep enough for two complete rows of tiles. OpenSlide * has its own tile cache, but it's not large enough for a complete @@ -296,7 +318,7 @@ vips__openslide_read( const char *filename, VipsImage *out, int layer ) raw = vips_image_new(); vips_object_local( out, raw ); - if( !(rslide = readslide_new( filename, raw, layer, NULL )) ) + if( !(rslide = readslide_new( filename, raw, level, NULL )) ) return( -1 ); if( vips_image_generate( raw, diff --git a/libvips/include/vips/colour.h b/libvips/include/vips/colour.h index 6f6ea93d..802101ce 100644 --- a/libvips/include/vips/colour.h +++ b/libvips/include/vips/colour.h @@ -146,7 +146,6 @@ float im_col_dE00( int im_LCh2Lab( VipsImage *in, VipsImage *out ); int im_LabQ2XYZ( VipsImage *in, VipsImage *out ); int im_rad2float( VipsImage *in, VipsImage *out ); -int im_argb2rgba( VipsImage *in, VipsImage *out ); int im_float2rad( VipsImage *in, VipsImage *out ); int im_LCh2UCS( VipsImage *in, VipsImage *out ); int im_Lab2LCh( VipsImage *in, VipsImage *out ); diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index dcee0143..65cdc0d8 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -77,14 +77,6 @@ extern "C" { */ #define VIPS_META_RESOLUTION_UNIT "resolution-unit" -/** - * VIPS_META_BACKGROUND_RGB: - * - * The OpenSlide load operator uses this to note the colour to use to paint - * transparent pixels in pre-multiplied ARGB format. See im_argb2rgba(). - */ -#define VIPS_META_BACKGROUND_RGB "background-rgb" - guint64 vips_format_sizeof( VipsBandFormat format ); int vips_image_get_width( const VipsImage *image ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index a661710e..3765bf48 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -648,6 +648,7 @@ int im_mask2vips( DOUBLEMASK *in, VipsImage *out ); int im_bandmean( VipsImage *in, VipsImage *out ); int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb ); +int im_argb2rgba( VipsImage *in, VipsImage *out ); /* ruby-vips uses this */