Merge remote-tracking branch 'origin/master' into format-hacking

also, start adding openslide.c to foreign

Conflicts:
	ChangeLog
	TODO
	libvips/iofuncs/image.c
This commit is contained in:
John Cupitt 2011-12-11 15:54:08 +00:00
commit 7fe4843250
27 changed files with 1122 additions and 40 deletions

View File

@ -56,6 +56,7 @@
- edvips can change vips header byte ordering - edvips can change vips header byte ordering
- "header" is terse by default - "header" is terse by default
- "header" outputs filenames if working on many files - "header" outputs filenames if working on many files
- added openslide support (Benjamin Gilbert)
12/10/11 started 7.26.6 12/10/11 started 7.26.6
- NOCACHE was not being set correctly on OS X causing performance - NOCACHE was not being set correctly on OS X causing performance

4
README
View File

@ -140,6 +140,10 @@ OpenEXR
if available, libvips will directly read (but not write, sadly) if available, libvips will directly read (but not write, sadly)
OpenEXR images OpenEXR images
OpenSlide
if available, libvips can load OpenSlide-supported virtual slide
files: Aperio, Hamamatsu VMS and VMU, MIRAX, and Trestle
swig swig
python python
python-dev python-dev

26
TODO
View File

@ -1,9 +1,3 @@
- do we need vips_object_unref_outputs() in more places? check all calls to
_build()
- how about - how about
vips max add[babe.jpg,babe2.jpg] vips max add[babe.jpg,babe2.jpg]
@ -15,6 +9,26 @@
- add ".ndpi" to openslide suffs? though we don't really use suffs for loaders
- check lazy load hint bug in format-hacking branch
- everywhere must set dhint in header load
- openslide sets a g_log() handler, argh, must just set temp
- make an argb coding type, add to nip2 and known coding
- "background-rgb" should be a macro
- nip2 should use zooming support, if possible
- what should we do? - what should we do?

View File

@ -438,6 +438,20 @@ if test x"$with_OpenEXR" != "xno"; then
]) ])
fi fi
# OpenSlide
AC_ARG_WITH([openslide],
AS_HELP_STRING([--without-openslide], [build without OpenSlide (default: test)]))
if test x"$with_openslide" != "xno"; then
PKG_CHECK_MODULES(OPENSLIDE, openslide >= 3.2.0,
[AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.2.0 installed.])
with_openslide=yes
PACKAGES_USED="$PACKAGES_USED openslide"],
[AC_MSG_WARN([OpenSlide >= 3.2.0 not found; disabling virtual slide support])
with_openslide=no
])
fi
# matio # matio
AC_ARG_WITH([matio], AC_ARG_WITH([matio],
AS_HELP_STRING([--without-matio], [build without matio (default: test)])) AS_HELP_STRING([--without-matio], [build without matio (default: test)]))
@ -598,14 +612,14 @@ fi
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS and VIPS_CXX_LIBS # Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS and VIPS_CXX_LIBS
# sort includes to get longer, more specific dirs first # sort includes to get longer, more specific dirs first
# helps, for example, selecting graphicsmagick over imagemagick # helps, for example, selecting graphicsmagick over imagemagick
VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $FFTW3_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $OPENEXR_CFLAGS $ORC_CFLAGS VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $FFTW3_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS
do do
echo $i echo $i
done | sort -ru` done | sort -ru`
VIPS_CFLAGS=`echo $VIPS_CFLAGS` VIPS_CFLAGS=`echo $VIPS_CFLAGS`
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS" VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
VIPS_INCLUDES="$PNG_INCLUDES $TIFF_INCLUDES $ZIP_INCLUDES $JPEG_INCLUDES $FFTW_INCLUDES $LCMS_INCLUDES" VIPS_INCLUDES="$PNG_INCLUDES $TIFF_INCLUDES $ZIP_INCLUDES $JPEG_INCLUDES $FFTW_INCLUDES $LCMS_INCLUDES"
VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $FFTW3_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $OPENEXR_LIBS $CFITSIO_LIBS $MATIO_LIBS $EXIF_LIBS -lm" VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $FFTW3_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
# we need this to generate paths in swig/python/setup.py.in # we need this to generate paths in swig/python/setup.py.in
AC_SUBST(top_srcdir) AC_SUBST(top_srcdir)
@ -682,6 +696,7 @@ accelerate loops with orc: $with_orc
(requires orc-0.4.11 or later) (requires orc-0.4.11 or later)
ICC profile support with lcms: $with_lcms (version $with_lcms_ver) ICC profile support with lcms: $with_lcms (version $with_lcms_ver)
file import with OpenEXR: $with_OpenEXR file import with OpenEXR: $with_OpenEXR
file import with OpenSlide: $with_openslide
file import with matio: $with_matio file import with matio: $with_matio
file import with cfitsio: $with_cfitsio file import with cfitsio: $with_cfitsio
text rendering with pangoft2: $with_pangoft2 text rendering with pangoft2: $with_pangoft2

View File

@ -50,8 +50,8 @@
*/ */
/* /*
*/
#define VIPS_DEBUG #define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
@ -159,7 +159,7 @@ vips_measure_build( VipsObject *object )
* measure on IM_TYPE_LAB images). * measure on IM_TYPE_LAB images).
*/ */
if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 ) if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 )
im_warn( "im_measure", vips_warn( "VipsMeasure",
_( "patch %d x %d, band %d: " _( "patch %d x %d, band %d: "
"avg = %g, sdev = %g" ), "avg = %g, sdev = %g" ),
i, j, avg, dev ); i, j, avg, dev );

View File

@ -56,8 +56,8 @@
*/ */
/* /*
*/
#define VIPS_DEBUG #define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>

View File

@ -6,6 +6,7 @@ libcolour_la_SOURCES = \
colour_dispatch.c \ colour_dispatch.c \
derived.c \ derived.c \
im_icc_transform.c \ im_icc_transform.c \
im_argb2rgba.c \
im_LCh2Lab.c \ im_LCh2Lab.c \
im_LCh2UCS.c \ im_LCh2UCS.c \
im_Lab2LCh.c \ im_Lab2LCh.c \

View File

@ -640,6 +640,25 @@ static im_function rad2float_desc = {
one_in_one_out /* Arg list */ 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. /* Call im_float2rad() via arg vector.
*/ */
static int static int
@ -1185,6 +1204,7 @@ static im_function *colour_list[] = {
&disp2Lab_desc, &disp2Lab_desc,
&disp2XYZ_desc, &disp2XYZ_desc,
&float2rad_desc, &float2rad_desc,
&argb2rgba_desc,
&icc_ac2rc_desc, &icc_ac2rc_desc,
&icc_export_depth_desc, &icc_export_depth_desc,
&icc_import_desc, &icc_import_desc,

View File

@ -0,0 +1,110 @@
/* 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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
static void
argb2rgba( guint32 *in, PEL *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( IMAGE *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( im_meta_get_int( in, "background-rgb", (int *) &bg ) )
bg = 0xffffff;
if( im_wrapone( in, out,
(im_wrapone_fn) argb2rgba, GUINT_TO_POINTER( bg ), NULL ) )
return( -1 );
return( 0 );
}

View File

@ -133,7 +133,7 @@ vips_flip_horizontal_gen( VipsRegion *or, void *seq, void *a, void *b,
VipsRegion *ir = (VipsRegion *) seq; VipsRegion *ir = (VipsRegion *) seq;
VipsRect *r = &or->valid; VipsRect *r = &or->valid;
VipsRect in; VipsRect in;
char *p, *q; PEL *p, *q;
int x, y, z; int x, y, z;
int le = r->left; int le = r->left;

View File

@ -85,8 +85,8 @@ line_shrink_gen( REGION *or, void *seq, void *a, void *b )
/* Loop down the region. /* Loop down the region.
*/ */
for( y = to; y < bo; y++ ) { for( y = to; y < bo; y++ ) {
char *q = IM_REGION_ADDR( or, le, y ); PEL *q = IM_REGION_ADDR( or, le, y );
char *p; PEL *p;
/* Loop across the region, in owidth sized pieces. /* Loop across the region, in owidth sized pieces.
*/ */
@ -149,8 +149,8 @@ point_shrink_gen( REGION *or, void *seq, void *a, void *b )
/* Loop down the region. /* Loop down the region.
*/ */
for( y = to; y < bo; y++ ) { for( y = to; y < bo; y++ ) {
char *q = IM_REGION_ADDR( or, le, y ); PEL *q = IM_REGION_ADDR( or, le, y );
char *p; PEL *p;
/* Loop across the region, in owidth sized pieces. /* Loop across the region, in owidth sized pieces.
*/ */

377
libvips/foreign/openslide.c Normal file
View File

@ -0,0 +1,377 @@
/* Read a virtual microscope slide using OpenSlide.
*
* Benjamin Gilbert
*
* Copyright (c) 2011 Carnegie Mellon University
*
* 26/11/11
* - initial version
* 27/11/11
* - fix black background in transparent areas
* - no need to set *stop on fill_region() error return
* - add OpenSlide properties to image metadata
* - consolidate setup into one function
* - support reading arbitrary layers
* - use VIPS_ARRAY()
* - add helper to copy a line of pixels
* - support reading associated images
* 7/12/11
* - redirect OpenSlide error logging to vips_error()
* 8/12/11
* - add more exposition to documentation
* 9/12/11
* - unpack to a tile cache
* 11/12/11
* - move argb->rgba into conversion
* - turn into a set of read fns ready to be called from a class
*/
/*
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
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <vips/vips.h>
#include <vips/debug.h>
#include <openslide.h>
#include "openslide.h"
/* We run our own tile cache. The OpenSlide one can't always keep enough for a
* complete lines of pixels.
*/
#define TILE_WIDTH (256)
#define TILE_HEIGHT (256)
typedef struct {
openslide_t *osr;
const char *associated;
/* Only valid if associated == NULL.
*/
int32_t layer;
double downsample;
} ReadSlide;
int
vips__openslide_isslide( const char *filename )
{
openslide_t *osr;
const char *vendor;
int ok;
ok = 1;
osr = openslide_open( filename );
if( osr != NULL ) {
/* If this is a generic tiled TIFF image, decline to support
* it, since im_tiff2vips can do better.
*/
vendor = openslide_get_property_value( osr,
OPENSLIDE_PROPERTY_NAME_VENDOR );
if( vendor == NULL ||
strcmp( vendor, "generic-tiff" ) == 0 )
ok = 0;
openslide_close( osr );
}
else
ok = 0;
VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok );
return( ok );
}
static void
readslide_destroy_cb( VipsImage *image, ReadSlide *rslide )
{
VIPS_FREEF( openslide_close, rslide->osr );
}
static int
check_associated_image( openslide_t *osr, const char *name )
{
const char * const *associated;
for( associated = openslide_get_associated_image_names( osr );
*associated != NULL; associated++ )
if( strcmp( *associated, name ) == 0 )
return( 0 );
vips_error( "im_openslide2vips",
"%s", _( "invalid associated image name" ) );
return( -1 );
}
static ReadSlide *
readslide_new( const char *filename, VipsImage *out )
{
ReadSlide *rslide;
char name[FILENAME_MAX];
char mode[FILENAME_MAX];
char *endp;
int64_t w, h;
const char *background;
const char * const *properties;
char *associated;
rslide = VIPS_NEW( out, ReadSlide );
memset( rslide, 0, sizeof( *rslide ) );
g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ),
rslide );
vips_filename_split( filename, name, mode );
rslide->osr = openslide_open( name );
if( rslide->osr == NULL ) {
vips_error( "im_openslide2vips",
"%s", _( "failure opening slide" ) );
return( NULL );
}
/* Parse optional mode.
*/
rslide->layer = strtol( mode, &endp, 10 );
if( *mode != 0 && *endp == 0 ) {
/* Mode specifies slide layer.
*/
if( rslide->layer < 0 || rslide->layer >=
openslide_get_layer_count( rslide->osr ) ) {
vips_error( "im_openslide2vips",
"%s", _( "invalid slide layer" ) );
return( NULL );
}
}
else if( *mode != 0 ) {
/* Mode specifies associated image.
*/
if ( check_associated_image( rslide->osr, mode ) )
return( NULL );
rslide->associated = vips_strdup( VIPS_OBJECT( out ), mode );
}
if( rslide->associated ) {
openslide_get_associated_image_dimensions( rslide->osr,
rslide->associated, &w, &h );
vips_image_set_string( out, "slide-associated-image",
rslide->associated );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
}
else {
openslide_get_layer_dimensions( rslide->osr, rslide->layer,
&w, &h );
rslide->downsample = openslide_get_layer_downsample(
rslide->osr, rslide->layer );
vips_image_set_int( out, "slide-layer", rslide->layer );
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 )
im_meta_set_int( out,
"background-rgb", strtoul( background, NULL, 16 ) );
else
im_meta_set_int( out, "background-rgb", 0xffffff );
if( w < 0 || h < 0 || rslide->downsample < 0 ) {
vips_error( "im_openslide2vips", _( "getting dimensions: %s" ),
openslide_get_error( rslide->osr ) );
return( NULL );
}
if( w > INT_MAX ||
h > INT_MAX ) {
vips_error( "im_openslide2vips",
"%s", _( "image dimensions overflow int" ) );
return( NULL );
}
vips_image_init_fields( out, (int) w, (int) h, 4, VIPS_FORMAT_UCHAR,
VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 );
for( properties = openslide_get_property_names( rslide->osr );
*properties != NULL; properties++ )
vips_image_set_string( out, *properties,
openslide_get_property_value( rslide->osr,
*properties ) );
associated = g_strjoinv( ", ", (char **)
openslide_get_associated_image_names( rslide->osr ) );
vips_image_set_string( out, "slide-associated-images", associated );
g_free( associated );
return( rslide );
}
int
vips__openslide_read_header( const char *filename, VipsImage *out,
int layer, char *associated )
{
ReadSlide *rslide;
if( !(rslide = readslide_new( filename, out, layer, associated )) )
return( -1 );
return( 0 );
}
static int
fill_region( VipsRegion *out, void *seq, void *_rslide, void *unused,
gboolean *stop )
{
ReadSlide *rslide = _rslide;
VipsRect *r = &out->valid;
const char *error;
int x, y;
VIPS_DEBUG_MSG( "fill_region: %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 dimensions.
*/
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 );
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 );
}
error = openslide_get_error( rslide->osr );
if( error ) {
vips_error( "im_openslide2vips",
_( "reading region: %s" ), error );
return( -1 );
}
return( 0 );
}
int
vips__openslide_read_file( const char *filename, VipsImage *out, int layer )
{
ReadSlide *rslide;
VipsImage *raw;
VIPS_DEBUG_MSG( "vips__openslide_read_file: %s %d\n",
filename, layer );
/* Tile cache: keep enough for two complete rows of tiles.
* This lets us do (smallish) area ops, like im_conv(), while
* still only hitting each tile once.
*/
if( !(raw = im_open_local( out, "cache", "p" )) )
return( -1 );
if( !(rslide = readslide_new( filename, raw, layer, NULL )) )
return( -1 );
if( vips_image_pio_output( raw ) ||
vips_image_generate( raw,
NULL, fill_region, NULL, rslide, NULL ) )
return( -1 );
/* Copy to out, adding a cache. Enough tiles for a complete row, plus
* 50%.
*/
if( im_tile_cache( raw, out,
TILE_WIDTH, TILE_HEIGHT,
1.5 * (1 + raw->Xsize / TILE_WIDTH) ) )
return( -1 );
return( 0 );
}
int
vips__openslide_read_associated( const char *filename, VipsImage *out,
const char *associated )
{
ReadSlide *rslide;
VipsImage *raw;
uint32_t *buf;
int64_t w, h;
int y;
const char *error;
VIPS_DEBUG_MSG( "vips__openslide_read_associated: %s %s\n",
filename, associated );
/* Tile cache: keep enough for two complete rows of tiles.
* This lets us do (smallish) area ops, like im_conv(), while
* still only hitting each tile once.
*/
if( !(raw = im_open_local( out, "cache", "p" )) )
return( -1 );
if( !(rslide = readslide_new( filename, raw, 0, associated )) )
return( -1 );
openslide_get_associated_image_dimensions( rslide->osr,
rslide->associated, &w, &h );
if( w == -1 ||
h == -1 ) {
vips_error( "im_openslide2vips",
_( "getting dimensions: %s" ),
openslide_get_error( rslide->osr ) );
return( -1 );
}
buf = VIPS_ARRAY( out, w * h, uint32_t );
openslide_read_associated_image( rslide->osr, rslide->associated, buf );
error = openslide_get_error( rslide->osr );
if( error ) {
vips_error( "im_openslide2vips",
_( "reading associated image: %s" ), error );
return( -1 );
}
if( vips_image_wio_output( out ) )
return( -1 );
for( y = 0; y < h; y++ )
if( vips_image_write_line( out, y, (PEL *) (buf + y * w) ) )
return( -1 );
return( 0 );
}

View File

@ -0,0 +1,47 @@
/* common defs for jpeg read/write
*/
/*
Copyright (C) 1991-2005 The National Gallery
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU 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
*/
#ifndef VIPS_OPENSLIDE_H
#define VIPS_OPENSLIDE_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
int vips__openslide_isslide( const char *filename );
int vips__openslide_read_header( const char *filename, VipsImage *out );
int vips__openslide_read_file( const char *filename, VipsImage *out );
int vips__openslide_read_associated( const char *filename, VipsImage *out,
const char *associated );
#ifdef __cplusplus
}
#endif /*__cplusplus*/
#endif /*VIPS_OPENSLIDE_H*/

View File

@ -22,6 +22,7 @@ libformat_la_SOURCES = \
im_vips2raw.c \ im_vips2raw.c \
matlab.c \ matlab.c \
fits.c \ fits.c \
radiance.c radiance.c \
openslide.c
INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

View File

@ -57,7 +57,7 @@
* transparently supported by im_open(). * transparently supported by im_open().
* *
* VIPS comes with VipsFormat for TIFF, JPEG, PNG, Analyze, PPM, OpenEXR, CSV, * VIPS comes with VipsFormat for TIFF, JPEG, PNG, Analyze, PPM, OpenEXR, CSV,
* Matlab, Radiance, RAW, VIPS and one that wraps libMagick. * Matlab, Radiance, RAW, VIPS and ones that wrap libMagick and OpenSlide.
*/ */
/** /**
@ -464,6 +464,10 @@ im__format_init( void )
extern GType vips_format_exr_get_type(); extern GType vips_format_exr_get_type();
vips_format_exr_get_type(); vips_format_exr_get_type();
#endif /*HAVE_OPENEXR*/ #endif /*HAVE_OPENEXR*/
#ifdef HAVE_OPENSLIDE
extern GType vips_format_openslide_get_type();
vips_format_openslide_get_type();
#endif /*HAVE_OPENSLIDE*/
#ifdef HAVE_MATIO #ifdef HAVE_MATIO
extern GType vips_format_mat_get_type(); extern GType vips_format_mat_get_type();
vips_format_mat_get_type(); vips_format_mat_get_type();

469
libvips/format/openslide.c Normal file
View File

@ -0,0 +1,469 @@
/* Read a virtual microscope slide using OpenSlide.
*
* Benjamin Gilbert
*
* Copyright (c) 2011 Carnegie Mellon University
*
* 26/11/11
* - initial version
* 27/11/11
* - fix black background in transparent areas
* - no need to set *stop on fill_region() error return
* - add OpenSlide properties to image metadata
* - consolidate setup into one function
* - support reading arbitrary layers
* - use VIPS_ARRAY()
* - add helper to copy a line of pixels
* - support reading associated images
* 7/12/11
* - redirect OpenSlide error logging to vips_error()
* 8/12/11
* - add more exposition to documentation
* 9/12/11
* - unpack to a tile cache
* 11/12/11
* - move argb->rgba into conversion
*/
/*
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
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifdef HAVE_OPENSLIDE
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <vips/vips.h>
#include <vips/debug.h>
#include <openslide.h>
/* We run our own tile cache. The OpenSlide one can't always keep enough for a
* complete lines of pixels.
*/
#define TILE_WIDTH (256)
#define TILE_HEIGHT (256)
typedef struct {
openslide_t *osr;
const char *associated;
/* Only valid if associated == NULL.
*/
int32_t layer;
double downsample;
} ReadSlide;
static void
readslide_destroy_cb( VipsImage *image, ReadSlide *rslide )
{
VIPS_FREEF( openslide_close, rslide->osr );
}
static int
check_associated_image( openslide_t *osr, const char *name )
{
const char * const *associated;
for( associated = openslide_get_associated_image_names( osr );
*associated != NULL; associated++ )
if( strcmp( *associated, name ) == 0 )
return( 0 );
vips_error( "im_openslide2vips",
"%s", _( "invalid associated image name" ) );
return( -1 );
}
static ReadSlide *
readslide_new( const char *filename, VipsImage *out )
{
ReadSlide *rslide;
char name[FILENAME_MAX];
char mode[FILENAME_MAX];
char *endp;
int64_t w, h;
const char *background;
const char * const *properties;
char *associated;
rslide = VIPS_NEW( out, ReadSlide );
memset( rslide, 0, sizeof( *rslide ) );
g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ),
rslide );
vips_filename_split( filename, name, mode );
rslide->osr = openslide_open( name );
if( rslide->osr == NULL ) {
vips_error( "im_openslide2vips",
"%s", _( "failure opening slide" ) );
return( NULL );
}
/* Parse optional mode.
*/
rslide->layer = strtol( mode, &endp, 10 );
if( *mode != 0 && *endp == 0 ) {
/* Mode specifies slide layer.
*/
if( rslide->layer < 0 || rslide->layer >=
openslide_get_layer_count( rslide->osr ) ) {
vips_error( "im_openslide2vips",
"%s", _( "invalid slide layer" ) );
return( NULL );
}
}
else if( *mode != 0 ) {
/* Mode specifies associated image.
*/
if ( check_associated_image( rslide->osr, mode ) )
return( NULL );
rslide->associated = vips_strdup( VIPS_OBJECT( out ), mode );
}
if( rslide->associated ) {
openslide_get_associated_image_dimensions( rslide->osr,
rslide->associated, &w, &h );
vips_image_set_string( out, "slide-associated-image",
rslide->associated );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
}
else {
openslide_get_layer_dimensions( rslide->osr, rslide->layer,
&w, &h );
rslide->downsample = openslide_get_layer_downsample(
rslide->osr, rslide->layer );
vips_image_set_int( out, "slide-layer", rslide->layer );
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 )
im_meta_set_int( out,
"background-rgb", strtoul( background, NULL, 16 ) );
else
im_meta_set_int( out, "background-rgb", 0xffffff );
if( w < 0 || h < 0 || rslide->downsample < 0 ) {
vips_error( "im_openslide2vips", _( "getting dimensions: %s" ),
openslide_get_error( rslide->osr ) );
return( NULL );
}
if( w > INT_MAX ||
h > INT_MAX ) {
vips_error( "im_openslide2vips",
"%s", _( "image dimensions overflow int" ) );
return( NULL );
}
vips_image_init_fields( out, (int) w, (int) h, 4, VIPS_FORMAT_UCHAR,
VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 );
for( properties = openslide_get_property_names( rslide->osr );
*properties != NULL; properties++ )
vips_image_set_string( out, *properties,
openslide_get_property_value( rslide->osr,
*properties ) );
associated = g_strjoinv( ", ", (char **)
openslide_get_associated_image_names( rslide->osr ) );
vips_image_set_string( out, "slide-associated-images", associated );
g_free( associated );
return( rslide );
}
static int
fill_region( VipsRegion *out, void *seq, void *_rslide, void *unused,
gboolean *stop )
{
ReadSlide *rslide = _rslide;
VipsRect *r = &out->valid;
const char *error;
int x, y;
VIPS_DEBUG_MSG( "fill_region: %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 dimensions.
*/
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 );
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 );
}
error = openslide_get_error( rslide->osr );
if( error ) {
vips_error( "im_openslide2vips",
_( "reading region: %s" ), error );
return( -1 );
}
return( 0 );
}
static int
fill_associated( VipsImage *out, ReadSlide *rslide )
{
uint32_t *buf;
int64_t w, h;
int y;
const char *error;
openslide_get_associated_image_dimensions( rslide->osr,
rslide->associated, &w, &h );
if( w == -1 ||
h == -1 ) {
vips_error( "im_openslide2vips",
_( "getting dimensions: %s" ),
openslide_get_error( rslide->osr ) );
return( -1 );
}
buf = VIPS_ARRAY( out, w * h, uint32_t );
openslide_read_associated_image( rslide->osr, rslide->associated, buf );
error = openslide_get_error( rslide->osr );
if( error ) {
vips_error( "im_openslide2vips",
_( "reading associated image: %s" ), error );
return( -1 );
}
if( vips_image_wio_output( out ) )
return( -1 );
for( y = 0; y < h; y++ )
if( vips_image_write_line( out, y, (PEL *) (buf + y * w) ) )
return( -1 );
return( 0 );
}
static int
openslide2vips_header( const char *filename, VipsImage *out )
{
ReadSlide *rslide;
if( !(rslide = readslide_new( filename, out )) )
return( -1 );
return( 0 );
}
/**
* im_openslide2vips:
* @filename: file to load
* @out: image to write to
*
* Read a virtual slide supported by the OpenSlide library into a VIPS image.
* OpenSlide supports images in Aperio, Hamamatsu VMS, Hamamatsu VMU, MIRAX,
* and Trestle formats. It also supports generic tiled TIFF images, but
* im_openslide2vips() does not.
*
* To facilitate zooming, virtual slide formats include multiple scaled-down
* versions of the high-resolution image. These are typically called
* "levels", though OpenSlide and im_openslide2vips() call them "layers".
* By default, im_openslide2vips() reads the highest-resolution layer
* (layer 0). To read a different layer, specify the layer number as part
* of the filename (for example, "CMU-1.mrxs:3").
*
* In addition to the slide image itself, virtual slide formats sometimes
* include additional images, such as a scan of the slide's barcode.
* OpenSlide calls these "associated images". To read an associated image,
* specify the image's name as part of the filename (for example,
* "CMU-1.mrxs:label"). A slide's associated images are listed in the
* "slide-associated-images" metadata item.
*
* See also: #VipsFormat
*
* Returns: 0 on success, -1 on error.
*/
static int
im_openslide2vips( const char *filename, VipsImage *out )
{
ReadSlide *rslide;
VipsImage *raw;
VIPS_DEBUG_MSG( "im_openslide2vips: %s\n", filename );
/* Tile cache: keep enough for two complete rows of tiles.
* This lets us do (smallish) area ops, like im_conv(), while
* still only hitting each tile once.
*/
if( !(raw = im_open_local( out, "cache", "p" )) )
return( -1 );
if( !(rslide = readslide_new( filename, raw )) )
return( -1 );
if( rslide->associated ) {
VIPS_DEBUG_MSG( "fill_associated:\n" );
if( fill_associated( raw, rslide ) )
return( -1 );
}
else {
if( vips_image_pio_output( raw ) ||
vips_image_generate( raw,
NULL, fill_region, NULL, rslide, NULL ) )
return( -1 );
}
/* Copy to out, adding a cache. Enough tiles for two complete
* rows.
*/
if( im_tile_cache( raw, out,
TILE_WIDTH, TILE_HEIGHT,
2 * (1 + raw->Xsize / TILE_WIDTH) ) )
return( -1 );
return( 0 );
}
static int
isslide( const char *filename )
{
openslide_t *osr;
const char *vendor;
int ok;
ok = 1;
osr = openslide_open( filename );
if( osr != NULL ) {
/* If this is a generic tiled TIFF image, decline to support
* it, since im_tiff2vips can do better.
*/
vendor = openslide_get_property_value( osr,
OPENSLIDE_PROPERTY_NAME_VENDOR );
if( vendor == NULL ||
strcmp( vendor, "generic-tiff" ) == 0 )
ok = 0;
openslide_close( osr );
}
else
ok = 0;
VIPS_DEBUG_MSG( "isslide: %s - %d\n", filename, ok );
return( ok );
}
static VipsFormatFlags
slide_flags( const char *filename )
{
char name[FILENAME_MAX];
char mode[FILENAME_MAX];
char *endp;
vips_filename_split( filename, name, mode );
strtol( mode, &endp, 10 );
if( *mode == 0 ||
*endp == 0 )
/* Slide layer or no mode specified.
*/
return( VIPS_FORMAT_PARTIAL );
else
/* Associated image specified.
*/
return( 0 );
}
static void
error_handler( const char *domain, GLogLevelFlags level, const char *message,
void *data )
{
vips_error( "im_openslide2vips", "%s", message );
}
/* openslide format adds no new members.
*/
typedef VipsFormat VipsFormatOpenslide;
typedef VipsFormatClass VipsFormatOpenslideClass;
static const char *slide_suffs[] = {
".svs", /* Aperio */
".vms", ".vmu", /* Hamamatsu */
".mrxs", /* MIRAX */
".tif", /* Trestle */
NULL
};
static void
vips_format_openslide_class_init( VipsFormatOpenslideClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFormatClass *format_class = (VipsFormatClass *) class;
object_class->nickname = "openslide";
object_class->description = _( "OpenSlide-supported" );
format_class->is_a = isslide;
format_class->header = openslide2vips_header;
format_class->load = im_openslide2vips;
format_class->get_flags = slide_flags;
format_class->suffs = slide_suffs;
/* Some TIFF files are virtual slides with odd vendor extensions
* (or outright format violations!). Ensure we look at them before
* im_tiff2vips does. OpenSlide tries very hard to reject files it
* doesn't understand, so this should be safe.
*/
format_class->priority = 100;
g_log_set_handler( "Openslide",
G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
error_handler, NULL );
}
static void
vips_format_openslide_init( VipsFormatOpenslide *object )
{
}
G_DEFINE_TYPE( VipsFormatOpenslide, vips_format_openslide, VIPS_TYPE_FORMAT );
#endif /*HAVE_OPENSLIDE*/

View File

@ -171,7 +171,7 @@ find_hist( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
/* Accumulate! /* Accumulate!
*/ */
for( y = to; y < bo; y++ ) { for( y = to; y < bo; y++ ) {
char *line = IM_REGION_ADDR( reg, le, y ); PEL *line = IM_REGION_ADDR( reg, le, y );
switch( im->BandFmt ) { switch( im->BandFmt ) {
case IM_BANDFMT_UCHAR: case IM_BANDFMT_UCHAR:

View File

@ -142,6 +142,7 @@ float im_col_dE00(
int im_LCh2Lab( VipsImage *in, VipsImage *out ); int im_LCh2Lab( VipsImage *in, VipsImage *out );
int im_LabQ2XYZ( VipsImage *in, VipsImage *out ); int im_LabQ2XYZ( VipsImage *in, VipsImage *out );
int im_rad2float( 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_float2rad( VipsImage *in, VipsImage *out );
int im_LCh2UCS( VipsImage *in, VipsImage *out ); int im_LCh2UCS( VipsImage *in, VipsImage *out );
int im_Lab2LCh( VipsImage *in, VipsImage *out ); int im_Lab2LCh( VipsImage *in, VipsImage *out );

View File

@ -77,7 +77,7 @@ extern "C" {
*/ */
#define VIPS_META_RESOLUTION_UNIT "resolution-unit" #define VIPS_META_RESOLUTION_UNIT "resolution-unit"
int vips_format_sizeof( VipsBandFormat format ); guint64 vips_format_sizeof( VipsBandFormat format );
int vips_image_get_width( const VipsImage *image ); int vips_image_get_width( const VipsImage *image );
int vips_image_get_height( const VipsImage *image ); int vips_image_get_height( const VipsImage *image );

View File

@ -282,7 +282,7 @@ typedef struct _VipsImage {
*/ */
char *Hist; /* don't use, see vips_image_get_history() */ char *Hist; /* don't use, see vips_image_get_history() */
char *filename; /* pointer to copy of filename */ char *filename; /* pointer to copy of filename */
char *data; /* start of image data for WIO */ PEL *data; /* start of image data for WIO */
int kill; /* set to non-zero to block eval */ int kill; /* set to non-zero to block eval */
/* Everything below this private and only used internally by /* Everything below this private and only used internally by
@ -292,7 +292,7 @@ typedef struct _VipsImage {
char *mode; /* mode string passed to _new() */ char *mode; /* mode string passed to _new() */
VipsImageType dtype; /* descriptor type */ VipsImageType dtype; /* descriptor type */
int fd; /* file descriptor */ int fd; /* file descriptor */
char *baseaddr; /* pointer to the start of an mmap file */ void *baseaddr; /* pointer to the start of an mmap file */
size_t length; /* size of mmap area */ size_t length; /* size of mmap area */
guint32 magic; /* magic from header, endian-ness of image */ guint32 magic; /* magic from header, endian-ness of image */
@ -316,8 +316,11 @@ typedef struct _VipsImage {
/* Part of mmap() read ... the sizeof() the header we skip from the /* Part of mmap() read ... the sizeof() the header we skip from the
* file start. Usually VIPS_SIZEOF_HEADER, but can be something else * file start. Usually VIPS_SIZEOF_HEADER, but can be something else
* for binary file read. * for binary file read.
*
* gint64 so that we can guarantee to work even on systems with
* strange ideas about large files.
*/ */
int sizeof_header; guint64 sizeof_header;
/* If this is a large disc image, don't map the whole thing, instead /* If this is a large disc image, don't map the whole thing, instead
* have a set of windows shared between the regions active on the * have a set of windows shared between the regions active on the
@ -372,7 +375,6 @@ typedef struct _VipsImage {
*/ */
gboolean delete_on_close; gboolean delete_on_close;
char *delete_on_close_filename; char *delete_on_close_filename;
} VipsImage; } VipsImage;
typedef struct _VipsImageClass { typedef struct _VipsImageClass {
@ -443,7 +445,7 @@ extern const size_t vips__image_sizeof_bandformat[];
(X), (Y), \ (X), (Y), \
0, 0, \ 0, 0, \
(I)->Xsize, \ (I)->Xsize, \
(I)->Ysize ), abort(), (char *) NULL) \ (I)->Ysize ), abort(), (PEL *) NULL) \
) )
#else /*!VIPS_DEBUG*/ #else /*!VIPS_DEBUG*/
#define VIPS_IMAGE_ADDR( I, X, Y ) \ #define VIPS_IMAGE_ADDR( I, X, Y ) \
@ -468,7 +470,7 @@ VipsImage *vips_image_new( void );
VipsImage *vips_image_new_mode( const char *filename, const char *mode ); VipsImage *vips_image_new_mode( const char *filename, const char *mode );
VipsImage *vips_image_new_from_file( const char *filename ); VipsImage *vips_image_new_from_file( const char *filename );
VipsImage *vips_image_new_from_file_raw( const char *filename, VipsImage *vips_image_new_from_file_raw( const char *filename,
int xsize, int ysize, int bands, int offset ); int xsize, int ysize, int bands, guint64 offset );
VipsImage *vips_image_new_from_memory( void *buffer, VipsImage *vips_image_new_from_memory( void *buffer,
int xsize, int ysize, int bands, VipsBandFormat bandfmt ); int xsize, int ysize, int bands, VipsBandFormat bandfmt );
VipsImage *vips_image_new_array( int xsize, int ysize ); VipsImage *vips_image_new_array( int xsize, int ysize );

View File

@ -168,6 +168,19 @@ extern int _vips__argument_id;
pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ pspec, (FLAGS), (PRIORITY), (OFFSET) ); \
} }
#define VIPS_ARG_UINT64( CLASS, NAME, PRIORITY, LONG, DESC, \
FLAGS, OFFSET, MIN, MAX, VALUE ) { \
GParamSpec *pspec; \
\
pspec = g_param_spec_uint64( (NAME), (LONG), (DESC), \
(MIN), (MAX), (VALUE), \
G_PARAM_READWRITE );\
g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
_vips__argument_id++, pspec ); \
vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
pspec, (FLAGS), (PRIORITY), (OFFSET) ); \
}
#define VIPS_ARG_ENUM( CLASS, NAME, PRIORITY, LONG, DESC, \ #define VIPS_ARG_ENUM( CLASS, NAME, PRIORITY, LONG, DESC, \
FLAGS, OFFSET, TYPE, VALUE ) { \ FLAGS, OFFSET, TYPE, VALUE ) { \
GParamSpec *pspec; \ GParamSpec *pspec; \

View File

@ -66,9 +66,9 @@ typedef struct {
int top; /* Area of image we have mapped, in pixels */ int top; /* Area of image we have mapped, in pixels */
int height; int height;
char *data; /* First pixel of line 'top' */ PEL *data; /* First pixel of line 'top' */
PEL *baseaddr; /* Base of window */ void *baseaddr; /* Base of window */
size_t length; /* Size of window */ size_t length; /* Size of window */
} VipsWindow; } VipsWindow;
@ -106,7 +106,7 @@ typedef struct {
VipsRect area; /* Area this pixel buffer covers */ VipsRect area; /* Area this pixel buffer covers */
gboolean done; /* Calculated and in cache */ gboolean done; /* Calculated and in cache */
VipsBufferCache *cache; VipsBufferCache *cache;
char *buf; /* Private malloc() area */ PEL *buf; /* Private malloc() area */
size_t bsize; /* Size of private malloc() */ size_t bsize; /* Size of private malloc() */
} VipsBuffer; } VipsBuffer;

View File

@ -69,7 +69,7 @@ typedef struct _VipsRegion {
*/ */
/*< private >*/ /*< private >*/
RegionType type; /* What kind of attachment */ RegionType type; /* What kind of attachment */
char *data; /* Off here to get data */ PEL *data; /* Off here to get data */
int bpl; /* Bytes-per-line for data */ int bpl; /* Bytes-per-line for data */
void *seq; /* Sequence we are using to fill region */ void *seq; /* Sequence we are using to fill region */
@ -150,7 +150,7 @@ int vips_region_prepare_many( VipsRegion **reg, VipsRect *r );
(R)->valid.left, \ (R)->valid.left, \
(R)->valid.top, \ (R)->valid.top, \
(R)->valid.width, \ (R)->valid.width, \
(R)->valid.height ), abort(), (char *) NULL) \ (R)->valid.height ), abort(), (PEL *) NULL) \
) )
#else /*DEBUG*/ #else /*DEBUG*/
#define VIPS_REGION_ADDR( R, X, Y ) \ #define VIPS_REGION_ADDR( R, X, Y ) \

View File

@ -186,8 +186,11 @@ static HeaderField old_double_field[] = {
/* This is used by (eg.) VIPS_IMAGE_SIZEOF_ELEMENT() to calculate object /* This is used by (eg.) VIPS_IMAGE_SIZEOF_ELEMENT() to calculate object
* size. * size.
*
* It needs to be guint64 and not size_t since we use this as the basis for
* image address calcs and they have to be 64-bit, even on 32-bit machines.
*/ */
const size_t vips__image_sizeof_bandformat[] = { const guint64 vips__image_sizeof_bandformat[] = {
sizeof( unsigned char ), /* VIPS_FORMAT_UCHAR */ sizeof( unsigned char ), /* VIPS_FORMAT_UCHAR */
sizeof( signed char ), /* VIPS_FORMAT_CHAR */ sizeof( signed char ), /* VIPS_FORMAT_CHAR */
sizeof( unsigned short ), /* VIPS_FORMAT_USHORT */ sizeof( unsigned short ), /* VIPS_FORMAT_USHORT */
@ -202,7 +205,7 @@ const size_t vips__image_sizeof_bandformat[] = {
/* Return number of bytes for a band format, or -1 on error. /* Return number of bytes for a band format, or -1 on error.
*/ */
int guint64
vips_format_sizeof( VipsBandFormat format ) vips_format_sizeof( VipsBandFormat format )
{ {
return( (format < 0 || format > VIPS_FORMAT_DPCOMPLEX) ? return( (format < 0 || format > VIPS_FORMAT_DPCOMPLEX) ?

View File

@ -566,7 +566,7 @@ vips_image_build( VipsObject *object )
const char *mode = image->mode; const char *mode = image->mode;
guint32 magic; guint32 magic;
size_t sizeof_image; guint64 sizeof_image;
VIPS_DEBUG_MSG( "vips_image_build: %p\n", image ); VIPS_DEBUG_MSG( "vips_image_build: %p\n", image );
@ -905,7 +905,7 @@ vips_image_class_init( VipsImageClass *class )
G_STRUCT_OFFSET( VipsImage, dhint ), G_STRUCT_OFFSET( VipsImage, dhint ),
VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_SMALLTILE ); VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_SMALLTILE );
VIPS_ARG_INT( class, "sizeof_header", 16, VIPS_ARG_UINT64( class, "sizeof_header", 16,
_( "Size of header" ), _( "Size of header" ),
_( "Offset in bytes from start of file" ), _( "Offset in bytes from start of file" ),
VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT,
@ -1395,7 +1395,7 @@ vips_image_new_from_file( const char *filename )
*/ */
VipsImage * VipsImage *
vips_image_new_from_file_raw( const char *filename, vips_image_new_from_file_raw( const char *filename,
int xsize, int ysize, int bands, int offset ) int xsize, int ysize, int bands, guint64 offset )
{ {
VipsImage *image; VipsImage *image;

View File

@ -934,8 +934,8 @@ vips_region_copy( VipsRegion *reg, VipsRegion *dest, VipsRect *r, int x, int y )
{ {
int z; int z;
int len = VIPS_IMAGE_SIZEOF_PEL( reg->im ) * r->width; int len = VIPS_IMAGE_SIZEOF_PEL( reg->im ) * r->width;
char *p = VIPS_REGION_ADDR( reg, r->left, r->top ); PEL *p = VIPS_REGION_ADDR( reg, r->left, r->top );
char *q = VIPS_REGION_ADDR( dest, x, y ); PEL *q = VIPS_REGION_ADDR( dest, x, y );
int plsk = VIPS_REGION_LSKIP( reg ); int plsk = VIPS_REGION_LSKIP( reg );
int qlsk = VIPS_REGION_LSKIP( dest ); int qlsk = VIPS_REGION_LSKIP( dest );
@ -1092,7 +1092,7 @@ vips_region_prepare_to_generate( VipsRegion *reg,
VipsRegion *dest, VipsRect *r, int x, int y ) VipsRegion *dest, VipsRect *r, int x, int y )
{ {
IMAGE *im = reg->im; IMAGE *im = reg->im;
char *p; PEL *p;
if( !im->generate_fn ) { if( !im->generate_fn ) {
vips_error( "vips_region_prepare_to", vips_error( "vips_region_prepare_to",

View File

@ -245,7 +245,7 @@ vips_window_set( VipsWindow *window, int top, int height )
window->baseaddr = baseaddr; window->baseaddr = baseaddr;
window->length = pagelength; window->length = pagelength;
window->data = (char *) baseaddr + (start - pagestart); window->data = (PEL *) baseaddr + (start - pagestart);
window->top = top; window->top = top;
window->height = height; window->height = height;