more vipsimage hacking
Moved all of im_close.c and im_open.c into the image.c class file, various small cleanups.
This commit is contained in:
parent
cbc366cd7d
commit
62836151d4
2
TODO
2
TODO
@ -1,5 +1,5 @@
|
||||
|
||||
- _build() for "t" / "p" / "w" sould do setupout / generate / etc.?
|
||||
- image.c has far too many includes
|
||||
|
||||
|
||||
|
||||
|
@ -241,6 +241,11 @@ typedef struct _VipsImage {
|
||||
*/
|
||||
gboolean hint_set;
|
||||
|
||||
/* The pre/post/close callbacks are all fire-once.
|
||||
*/
|
||||
gboolean preclose;
|
||||
gboolean close;
|
||||
gboolean postclose;
|
||||
} VipsImage;
|
||||
|
||||
typedef struct _VipsImageClass {
|
||||
@ -251,33 +256,33 @@ typedef struct _VipsImageClass {
|
||||
|
||||
/* Evaluation is starting.
|
||||
*/
|
||||
int (*evalstart)( VipsImage *image );
|
||||
void (*preeval)( VipsImage *image );
|
||||
|
||||
/* Evaluation progress.
|
||||
*/
|
||||
int (*eval)( VipsImage *image, VipsProgress *progress );
|
||||
void (*eval)( VipsImage *image, VipsProgress *progress );
|
||||
|
||||
/* Evaluation is ending.
|
||||
*/
|
||||
int (*evalend)( VipsImage *image );
|
||||
void (*posteval)( VipsImage *image );
|
||||
|
||||
/* Just before image close, everything is still alive.
|
||||
*/
|
||||
int (*preclose)( VipsImage *image );
|
||||
void (*preclose)( VipsImage *image );
|
||||
|
||||
/* Image close, time to free stuff.
|
||||
*/
|
||||
int (*preclose)( VipsImage *image );
|
||||
void (*close)( VipsImage *image );
|
||||
|
||||
/* Post-close, everything is dead, except the VipsImage pointer.
|
||||
* Useful for eg. deleting the file associated with a temp image.
|
||||
*/
|
||||
int (*postclose)( VipsImage *image );
|
||||
void (*postclose)( VipsImage *image );
|
||||
|
||||
/* An image has been written to.
|
||||
* Used by eg. im_open("x.jpg", "w") to do the final write to jpeg.
|
||||
*/
|
||||
int (*written)( VipsImage *image );
|
||||
void (*written)( VipsImage *image );
|
||||
|
||||
/* An image has been modified in some way and downstream caches all
|
||||
* need dropping.
|
||||
|
@ -241,6 +241,8 @@ VipsObject *vips_object_new( GType type,
|
||||
VipsObject *vips_object_new_from_string( const char *base, const char *str );
|
||||
void vips_object_to_string( VipsObject *object, VipsBuf *buf );
|
||||
|
||||
void *vips_object_map( VSListMap2Fn fn, void *a, void *b );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -13,19 +13,16 @@ libiofuncs_la_SOURCES = \
|
||||
image.c \
|
||||
vips.c \
|
||||
im_binfile.c \
|
||||
im_close.c \
|
||||
im_cp_desc.c \
|
||||
im_demand_hint.c \
|
||||
im_generate.c \
|
||||
im_histlin.c \
|
||||
im_image.c \
|
||||
im_mapfile.c \
|
||||
im_open.c \
|
||||
im_partial.c \
|
||||
im_prepare.c \
|
||||
im_setbuf.c \
|
||||
im_setupout.c \
|
||||
im_unmapfile.c \
|
||||
im_guess_prefix.c \
|
||||
sinkmemory.c \
|
||||
sinkscreen.c \
|
||||
|
@ -1,319 +0,0 @@
|
||||
/* im_close.c --- close an image
|
||||
*
|
||||
* Copyright: Nicos Dessipris
|
||||
* Written on: 12/04/1990
|
||||
* Modified on :
|
||||
* 24/7/92 JC
|
||||
* - im_update_descfile code tidied up
|
||||
* - free on NULL string when junking Hist fixed
|
||||
* - now calls im_unmapfile
|
||||
* - better behaviour if image has been opened and closed with
|
||||
* no im_setupout call
|
||||
* - better behaviour for half-made IMAGE descriptors
|
||||
* 15/4/93 JC
|
||||
* - additions for freeing partial images
|
||||
* 29/4/93 JC
|
||||
* - close callback list added
|
||||
* 10/5/93 JC
|
||||
* - im__close() added
|
||||
* 9/11/93 JC
|
||||
* - im_update_descfile -> write_descfile
|
||||
* - if Hist is NULL, no longer makes up and writes .desc file
|
||||
* 16/8/94 JC
|
||||
* - evalend callbacks added
|
||||
* - ANSIfied
|
||||
* 24/10/95 JC
|
||||
* - now tracks open images ... see also im_init() and debug.c
|
||||
* 11/7/00 JC
|
||||
* - SETBUF_FOREIGN added
|
||||
* 16/1/04 JC
|
||||
* - frees as much as possible on im_close() failure
|
||||
* 6/6/05 Markus Wollgarten
|
||||
* - free Meta on close
|
||||
* 30/6/05 JC
|
||||
* - actually, free Meta on final close, so we carry meta over on an
|
||||
* im__close()/im_openin() pair (eg. see im_pincheck())
|
||||
* 11/7/05
|
||||
* - call im__writehist() to send history to XML after image data
|
||||
* 3/1/07
|
||||
* - free history_list
|
||||
* 7/11/07
|
||||
* - added preclose, removed evalend triggers
|
||||
* 23/7/08
|
||||
* - im__close() will no longer free regions
|
||||
* 9/8/08
|
||||
* - lock global image list (thanks Lee)
|
||||
* 8/9/09
|
||||
* - move close callbacks *after* we have released resources --- we
|
||||
* can now write close callbacks that unlink() temporary files
|
||||
* - use preclose callbacks if you want to run before resources are
|
||||
* released
|
||||
* 6/10/09
|
||||
* - gtkdoc comment
|
||||
* 10/1/09
|
||||
* - added postclose
|
||||
* 14/1/09
|
||||
* - added written
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG_IO
|
||||
#define DEBUG_NEW
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif /*HAVE_UNISTD_H*/
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif /*HAVE_IO_H*/
|
||||
#include <assert.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/thread.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Maximum file name length.
|
||||
*/
|
||||
#define NAMELEN 1024
|
||||
|
||||
/* Free any resources owned by this descriptor. The descriptor is left as if a
|
||||
* call to im_init had just happened - ie. the filename is set, but no other
|
||||
* resources are attached. Information is lost if this is a im_setbuf()
|
||||
* image! On an error, return non-zero and leave the image in an indeterminate
|
||||
* state. Too hard to recover gracefully.
|
||||
*/
|
||||
int
|
||||
im__close( IMAGE *im )
|
||||
{
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
|
||||
/* No action for NULL image.
|
||||
*/
|
||||
if( !im )
|
||||
return( result );
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: starting for %s ..\n", im->filename );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
/* Trigger all pre-close fns.
|
||||
*/
|
||||
result |= im__trigger_callbacks( im->preclosefns );
|
||||
IM_FREEF( im_slist_free_all, im->preclosefns );
|
||||
|
||||
/* Should be no regions defined on the image. im_close() ought to put
|
||||
* us into a zombie state if there are, im__close() should not be
|
||||
* called on images with running regions.
|
||||
*/
|
||||
if( im->regions ) {
|
||||
GSList *p;
|
||||
|
||||
printf( "** im__close: leaked regions!\n" );
|
||||
for( p = im->regions; p; p = p->next )
|
||||
im_region_print( (REGION *) p->data );
|
||||
}
|
||||
|
||||
/* That should mean we have no windows.
|
||||
*/
|
||||
if( im->windows ) {
|
||||
GSList *p;
|
||||
|
||||
printf( "** im__close: leaked windows!\n" );
|
||||
for( p = im->windows; p; p = p->next )
|
||||
im_window_print( (im_window_t *) p->data );
|
||||
}
|
||||
|
||||
/* Junk generate functions.
|
||||
*/
|
||||
im->start = NULL;
|
||||
im->generate = NULL;
|
||||
im->stop = NULL;
|
||||
|
||||
/* No more upstream/downstream links.
|
||||
*/
|
||||
im__link_break_all( im );
|
||||
|
||||
/* What resources are associated with this IMAGE descriptor?
|
||||
*/
|
||||
if( im->baseaddr ) {
|
||||
/* MMAP file.
|
||||
*/
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: unmapping file ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
if( im_unmapfile( im ) )
|
||||
return( -1 );
|
||||
im->data = NULL;
|
||||
}
|
||||
|
||||
/* Is there a file descriptor?
|
||||
*/
|
||||
if( im->fd != -1 ) {
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: closing output file ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
if( im->dtype == IM_OPENOUT && im__writehist( im ) )
|
||||
result = -1;
|
||||
if( close( im->fd ) == -1 ) {
|
||||
im_error( "im_close", _( "unable to close fd for %s" ),
|
||||
im->filename );
|
||||
result = -1;
|
||||
}
|
||||
im->fd = -1;
|
||||
}
|
||||
|
||||
/* Any image data?
|
||||
*/
|
||||
if( im->data ) {
|
||||
/* Buffer image. Only free stuff we know we allocated.
|
||||
*/
|
||||
if( im->dtype == IM_SETBUF ) {
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: freeing buffer ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
im_free( im->data );
|
||||
im->dtype = IM_NONE;
|
||||
}
|
||||
|
||||
im->data = NULL;
|
||||
}
|
||||
|
||||
/* Junk all callbacks, perform close callbacks.
|
||||
*/
|
||||
IM_FREEF( im_slist_free_all, im->evalstartfns );
|
||||
IM_FREEF( im_slist_free_all, im->evalfns );
|
||||
IM_FREEF( im_slist_free_all, im->evalendfns );
|
||||
IM_FREEF( im_slist_free_all, im->invalidatefns );
|
||||
IM_FREEF( im_slist_free_all, im->writtenfns );
|
||||
result |= im__trigger_callbacks( im->closefns );
|
||||
IM_FREEF( im_slist_free_all, im->closefns );
|
||||
|
||||
/* Reset other state.
|
||||
*/
|
||||
im->dtype = IM_NONE;
|
||||
im->dhint = IM_SMALLTILE;
|
||||
im->kill = 0;
|
||||
im->close_pending = 0;
|
||||
im->sizeof_header = IM_SIZEOF_HEADER;
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: final success for %s (%p)\n",
|
||||
im->filename, im );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_close:
|
||||
* @im: image to close
|
||||
*
|
||||
* Frees all resources associated with @im.
|
||||
*
|
||||
* If there are open #REGION s on @im, close is delayed until the last region
|
||||
* is freed.
|
||||
*
|
||||
* See also: im_open().
|
||||
*
|
||||
* Returns: 0 on success and 1 on error.
|
||||
*/
|
||||
int
|
||||
im_close( IMAGE *im )
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
/* No action for NULL image.
|
||||
*/
|
||||
if( !im )
|
||||
return( result );
|
||||
|
||||
if( im->regions ) {
|
||||
/* There are regions left on this image.
|
||||
* Set close_pending and return. The image will be then
|
||||
* be closed when the last region is freed
|
||||
* (see im_region_free()).
|
||||
*/
|
||||
#ifdef DEBUG_NEW
|
||||
printf( "im_close: pending close for 0x%p, \"%s\"\n",
|
||||
im, im->filename );
|
||||
#endif /*DEBUG_NEW*/
|
||||
|
||||
im->close_pending = 1;
|
||||
}
|
||||
else if( !im->closing ) {
|
||||
/* Is this descriptor currently being closed somewhere else?
|
||||
* This prevents infinite descent if a close callback
|
||||
* includes an im_close for this image.
|
||||
*/
|
||||
im->closing = 1;
|
||||
|
||||
if( im__close( im ) )
|
||||
result = -1;
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
printf( "im_close: freeing IMAGE 0x%p, \"%s\"\n",
|
||||
im, im->filename );
|
||||
#endif /*DEBUG_NEW*/
|
||||
|
||||
/* Final cleanup.
|
||||
*/
|
||||
result |= im__trigger_callbacks( im->postclosefns );
|
||||
IM_FREEF( im_slist_free_all, im->postclosefns );
|
||||
IM_FREEF( g_mutex_free, im->sslock );
|
||||
IM_FREE( im->filename );
|
||||
IM_FREE( im->Hist );
|
||||
IM_FREEF( im__gslist_gvalue_free, im->history_list );
|
||||
im__meta_destroy( im );
|
||||
g_mutex_lock( im__global_lock );
|
||||
im__open_images = g_slist_remove( im__open_images, im );
|
||||
g_mutex_unlock( im__global_lock );
|
||||
im__time_destroy( im );
|
||||
IM_FREE( im );
|
||||
}
|
||||
|
||||
return( result );
|
||||
}
|
@ -1,709 +0,0 @@
|
||||
/* @(#) im_open: vips front end to file open functions
|
||||
ARGS: filename and mode which is one of:
|
||||
"r" read by mmap (im_mmapin)
|
||||
"rw" read and write by mmap (im_mmapinrw)
|
||||
"w" write for write (im_writeline)
|
||||
"t" for temporary memory image
|
||||
"p" for partial memory image
|
||||
RETURNS: IMAGE pointer or 0 on error
|
||||
Copyright: Kirk Martinez 29/5/92
|
||||
|
||||
Modified:
|
||||
* 8/8/94 JC
|
||||
* - ANSIfied
|
||||
* - im_open_local added
|
||||
* 16/8/94 JC
|
||||
* - im_malloc() added
|
||||
* 22/11/94 JC & KM
|
||||
* - tiff added
|
||||
* 1/2/95 JC
|
||||
* - tiff removed again!
|
||||
* - now just im_istiff(), im_tiff2vips() and im_vips2tiff()
|
||||
* - applications have responsibility for making the translation
|
||||
* 26/3/96 JC
|
||||
* - im_open_local() now closes on close, not evalend
|
||||
* 14/11/96 JC
|
||||
* - tiff and jpeg added again
|
||||
* - open for read used im_istiff() and im_isjpeg() to switch
|
||||
* - open for write looks at suffix
|
||||
* 23/4/97 JC
|
||||
* - im_strdup() now allows NULL IMAGE parameter
|
||||
* - subsample parameter added to im_tiff2vips()
|
||||
* 29/10/98 JC
|
||||
* - byte-swap stuff added
|
||||
* 16/6/99 JC
|
||||
* - 8x byte swap added for double/double complex
|
||||
* - better error message if file does not exist
|
||||
* - ignore case when testing suffix for save
|
||||
* - fix im_mmapinrw() return test to stop coredump in edvips if
|
||||
* unwritable
|
||||
* 2/11/99 JC
|
||||
* - malloc/strdup stuff moved to memory.c
|
||||
* 5/8/00 JC
|
||||
* - fixes for im_vips2tiff() changes
|
||||
* 13/10/00 JC
|
||||
* - ooops, missing 'else'
|
||||
* 22/11/00 JC
|
||||
* - ppm read/write added
|
||||
* 12/2/01 JC
|
||||
* - im__image_sanity() added
|
||||
* 16/5/01 JC
|
||||
* - now allows RW for non-native byte order, provided it's an 8-bit
|
||||
* image
|
||||
* 11/7/01 JC
|
||||
* - im_tiff2vips() no longer has subsample option
|
||||
* 25/3/02 JC
|
||||
* - better im_open() error message
|
||||
* 12/12/02 JC
|
||||
* - sanity no longer returns errors, just warns
|
||||
* 28/12/02 HB
|
||||
* - Added PNG support
|
||||
* 6/5/03 JC
|
||||
* - added im_open_header() (from header.c)
|
||||
* 22/5/03 JC
|
||||
* - im__skip_dir() knows about ':' in filenames for vips2tiff etc.
|
||||
* 27/11/03 JC
|
||||
* - im_image_sanity() now insists x/y/bands all >0
|
||||
* 6/1/04 JC
|
||||
* - moved util funcs out to util.c
|
||||
* 18/2/04 JC
|
||||
* - added an im_init_world() to help old progs
|
||||
* 16/4/04
|
||||
* - oop, im_open() didn't know about input options in filenames
|
||||
* 2/11/04
|
||||
* - im_open( "r" ) is now lazier ... for non-VIPS formats, we delay
|
||||
* read until the first ->generate()
|
||||
* - so im_open_header() is now a no-op
|
||||
* 22/6/05
|
||||
* - if TIFF open fails, try going through libmagick
|
||||
* 4/8/05
|
||||
* - added analyze read
|
||||
* 30/9/05
|
||||
* - oops, lazy read error recovery didn't clear a pointer
|
||||
* 1/5/06
|
||||
* - added OpenEXR read
|
||||
* 9/6/06
|
||||
* - added CSV read/write
|
||||
* 20/9/06
|
||||
* - test for NULL filename/mode, common if you forget to check argc
|
||||
* (thanks bruno)
|
||||
* 7/11/07
|
||||
* - use preclose, not evalend, for delayed save
|
||||
* - add simple cmd-line progress feedback
|
||||
* 9/8/08
|
||||
* - lock global image list (thanks lee)
|
||||
* 25/5/08
|
||||
* - break file format stuff out to the new pluggable image format system
|
||||
* 14/1/09
|
||||
* - write to non-vips formats with a "written" callback
|
||||
* 29/7/10
|
||||
* - disc open threshold stuff, open to disc mode
|
||||
* 27/10/10
|
||||
* - oops, guess_size was unnecessary
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/debug.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Progress feedback. Only really useful for testing, tbh.
|
||||
*/
|
||||
int im__progress = 0;
|
||||
|
||||
/* A string giving the image size (in bytes of uncompressed image) above which
|
||||
* we decompress to disc on open. Can be eg. "12m" for 12 megabytes.
|
||||
*/
|
||||
char *im__disc_threshold = NULL;
|
||||
|
||||
/* Delayed save: if we write to (eg.) TIFF, actually do the write
|
||||
* to a "p" and on "written" do im_vips2tiff() or whatever. Track save
|
||||
* parameters here.
|
||||
*/
|
||||
typedef struct {
|
||||
int (*save_fn)(); /* Save function */
|
||||
IMAGE *im; /* Image to save */
|
||||
char *filename; /* Save args */
|
||||
} SaveBlock;
|
||||
|
||||
/* From "written" callback: invoke a delayed save.
|
||||
*/
|
||||
static int
|
||||
invoke_sb( SaveBlock *sb )
|
||||
{
|
||||
if( sb->save_fn( sb->im, sb->filename ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Attach a SaveBlock to an image.
|
||||
*/
|
||||
static int
|
||||
attach_sb( IMAGE *out, int (*save_fn)(), const char *filename )
|
||||
{
|
||||
SaveBlock *sb = IM_NEW( out, SaveBlock );
|
||||
|
||||
if( !sb )
|
||||
return( -1 );
|
||||
sb->im = out;
|
||||
sb->save_fn = save_fn;
|
||||
sb->filename = im_strdup( out, filename );
|
||||
|
||||
if( im_add_written_callback( out,
|
||||
(im_callback_fn) invoke_sb, (void *) sb, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Lazy open: init a descriptor from a filename (just read the header) but
|
||||
* delay actually decoding pixels until the first call to a start function.
|
||||
*/
|
||||
|
||||
/* What we track during a delayed open.
|
||||
*/
|
||||
typedef struct _Lazy {
|
||||
IMAGE *out;
|
||||
VipsFormatClass *format;/* Read in pixels with this */
|
||||
gboolean disc; /* Read via disc requested */
|
||||
IMAGE *im; /* The real decompressed image */
|
||||
} Lazy;
|
||||
|
||||
static int
|
||||
lazy_free( Lazy *lazy )
|
||||
{
|
||||
IM_FREEF( im_close, lazy->im );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static Lazy *
|
||||
lazy_new( IMAGE *out, VipsFormatClass *format, gboolean disc )
|
||||
{
|
||||
Lazy *lazy;
|
||||
|
||||
if( !(lazy = IM_NEW( out, Lazy )) )
|
||||
return( NULL );
|
||||
lazy->out = out;
|
||||
lazy->format = format;
|
||||
lazy->disc = disc;
|
||||
lazy->im = NULL;
|
||||
|
||||
if( im_add_close_callback( out,
|
||||
(im_callback_fn) lazy_free, lazy, NULL ) ) {
|
||||
lazy_free( lazy );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( lazy );
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char unit;
|
||||
int multiplier;
|
||||
} Unit;
|
||||
|
||||
static size_t
|
||||
parse_size( const char *size_string )
|
||||
{
|
||||
static Unit units[] = {
|
||||
{ 'k', 1024 },
|
||||
{ 'm', 1024 * 1024 },
|
||||
{ 'g', 1024 * 1024 * 1024 }
|
||||
};
|
||||
|
||||
size_t size;
|
||||
int n;
|
||||
int i, j;
|
||||
char *unit;
|
||||
|
||||
/* An easy way to alloc a buffer large enough.
|
||||
*/
|
||||
unit = g_strdup( size_string );
|
||||
n = sscanf( size_string, "%d %s", &i, unit );
|
||||
if( n > 0 )
|
||||
size = i;
|
||||
if( n > 1 ) {
|
||||
for( j = 0; j < IM_NUMBER( units ); j++ )
|
||||
if( tolower( unit[0] ) == units[j].unit ) {
|
||||
size *= units[j].multiplier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free( unit );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "parse_size: parsed \"%s\" as %zd\n", size_string, size );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( size );
|
||||
}
|
||||
|
||||
static size_t
|
||||
disc_threshold( void )
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
static size_t threshold;
|
||||
|
||||
if( !done ) {
|
||||
const char *env;
|
||||
|
||||
done = TRUE;
|
||||
|
||||
/* 100mb default.
|
||||
*/
|
||||
threshold = 100 * 1024 * 1024;
|
||||
|
||||
if( (env = g_getenv( "IM_DISC_THRESHOLD" )) )
|
||||
threshold = parse_size( env );
|
||||
|
||||
if( im__disc_threshold )
|
||||
threshold = parse_size( im__disc_threshold );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "disc_threshold: %zd bytes\n", threshold );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
|
||||
return( threshold );
|
||||
}
|
||||
|
||||
static IMAGE *
|
||||
lazy_image( Lazy *lazy )
|
||||
{
|
||||
IMAGE *im;
|
||||
|
||||
/* We open to disc if:
|
||||
* - 'disc' is set
|
||||
* - disc_threshold() has not been set to zero
|
||||
* - the format does not support lazy read
|
||||
* - the image will be more than a megabyte, uncompressed
|
||||
*/
|
||||
im = NULL;
|
||||
if( lazy->disc &&
|
||||
disc_threshold() &&
|
||||
!(vips_format_get_flags( lazy->format, lazy->out->filename ) &
|
||||
VIPS_FORMAT_PARTIAL) ) {
|
||||
size_t size = IM_IMAGE_SIZEOF_LINE( lazy->out ) *
|
||||
lazy->out->Ysize;
|
||||
|
||||
if( size > disc_threshold() ) {
|
||||
if( !(im = im__open_temp( "%s.v" )) )
|
||||
return( NULL );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "lazy_image: opening to disc file \"%s\"\n",
|
||||
im->filename );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, fall back to a "p".
|
||||
*/
|
||||
if( !im &&
|
||||
!(im = im_open( lazy->out->filename, "p" )) )
|
||||
return( NULL );
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Our start function ... do the lazy open, if necessary, and return a region
|
||||
* on the new image.
|
||||
*/
|
||||
static void *
|
||||
open_lazy_start( IMAGE *out, void *a, void *dummy )
|
||||
{
|
||||
Lazy *lazy = (Lazy *) a;
|
||||
|
||||
if( !lazy->im ) {
|
||||
if( !(lazy->im = lazy_image( lazy )) ||
|
||||
lazy->format->load( lazy->out->filename, lazy->im ) ||
|
||||
im_pincheck( lazy->im ) ) {
|
||||
IM_FREEF( im_close, lazy->im );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
return( im_region_create( lazy->im ) );
|
||||
}
|
||||
|
||||
/* Just copy.
|
||||
*/
|
||||
static int
|
||||
open_lazy_generate( REGION *or, void *seq, void *a, void *b )
|
||||
{
|
||||
REGION *ir = (REGION *) seq;
|
||||
|
||||
Rect *r = &or->valid;
|
||||
|
||||
/* Ask for input we need.
|
||||
*/
|
||||
if( im_prepare( ir, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Attach output region to that.
|
||||
*/
|
||||
if( im_region_region( or, ir, r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Lazy open ... init the header with the first OpenLazyFn, delay actually
|
||||
* decoding pixels with the second OpenLazyFn until the first generate().
|
||||
*/
|
||||
static int
|
||||
open_lazy( VipsFormatClass *format, gboolean disc, IMAGE *out )
|
||||
{
|
||||
Lazy *lazy;
|
||||
|
||||
if( !(lazy = lazy_new( out, format, disc )) )
|
||||
return( -1 );
|
||||
|
||||
/* Read header fields to init the return image. THINSTRIP since this is
|
||||
* probably a disc file. We can't tell yet whether we will be opening
|
||||
* to memory, sadly, so we can't suggest ANY.
|
||||
*/
|
||||
if( format->header( out->filename, out ) ||
|
||||
im_demand_hint( out, IM_THINSTRIP, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Then 'start' creates the real image and 'gen' paints 'out' with
|
||||
* pixels from the real image on demand.
|
||||
*/
|
||||
if( im_generate( out,
|
||||
open_lazy_start, open_lazy_generate, im_stop_one,
|
||||
lazy, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static IMAGE *
|
||||
open_sub( VipsFormatClass *format, const char *filename, gboolean disc )
|
||||
{
|
||||
IMAGE *im;
|
||||
|
||||
/* This is the 'im' we return which, when read from, will trigger the
|
||||
* actual load.
|
||||
*/
|
||||
if( !(im = im_open( filename, "p" )) ||
|
||||
open_lazy( format, disc, im ) ) {
|
||||
im_close( im );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Progress feedback.
|
||||
*/
|
||||
|
||||
/* What we track during an eval.
|
||||
*/
|
||||
typedef struct {
|
||||
IMAGE *im;
|
||||
|
||||
int last_percent; /* The last %complete we displayed */
|
||||
} Progress;
|
||||
|
||||
int
|
||||
evalstart_cb( Progress *progress )
|
||||
{
|
||||
int tile_width;
|
||||
int tile_height;
|
||||
int nlines;
|
||||
|
||||
progress->last_percent = 0;
|
||||
|
||||
vips_get_tile_size( progress->im, &tile_width, &tile_height, &nlines );
|
||||
printf( _( "%s %s: %d threads, %d x %d tiles, groups of %d scanlines" ),
|
||||
g_get_prgname(), progress->im->filename,
|
||||
im_concurrency_get(),
|
||||
tile_width, tile_height, nlines );
|
||||
printf( "\n" );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
eval_cb( Progress *progress )
|
||||
{
|
||||
IMAGE *im = progress->im;
|
||||
|
||||
if( im->time->percent != progress->last_percent ) {
|
||||
printf( _( "%s %s: %d%% complete" ),
|
||||
g_get_prgname(), im->filename, im->time->percent );
|
||||
printf( "\r" );
|
||||
fflush( stdout );
|
||||
|
||||
progress->last_percent = im->time->percent;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
evalend_cb( Progress *progress )
|
||||
{
|
||||
IMAGE *im = progress->im;
|
||||
|
||||
/* Spaces at end help to erase the %complete message we overwrite.
|
||||
*/
|
||||
printf( _( "%s %s: done in %ds \n" ),
|
||||
g_get_prgname(), im->filename, im->time->run );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_open:
|
||||
* @filename: file to open
|
||||
* @mode: mode to open with
|
||||
*
|
||||
* im_open() examines the mode string, and creates an appropriate #IMAGE.
|
||||
*
|
||||
* <itemizedlist>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"r"</emphasis>
|
||||
* opens the named file for reading. If the file is not in the native
|
||||
* VIPS format for your machine, im_open() automatically converts the
|
||||
* file for you in memory.
|
||||
*
|
||||
* For some large files (eg. TIFF) this may
|
||||
* not be what you want, it can fill memory very quickly. Instead, you
|
||||
* can either use "rd" mode (see below), or you can use the lower-level
|
||||
* API and control the loading process yourself. See
|
||||
* #VipsFormat.
|
||||
*
|
||||
* im_open() can read files in most formats.
|
||||
*
|
||||
* Note that <emphasis>"r"</emphasis> mode works in at least two stages.
|
||||
* It should return quickly and let you check header fields. It will
|
||||
* only actually read in pixels when you first access them.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"rd"</emphasis>
|
||||
* opens the named file for reading. If the uncompressed image is larger
|
||||
* than a threshold and the file format does not support random access,
|
||||
* rather than uncompressing to memory, im_open() will uncompress to a
|
||||
* temporary disc file. This file will be automatically deleted when the
|
||||
* IMAGE is closed.
|
||||
*
|
||||
* See im_system_image() for an explanation of how VIPS selects a
|
||||
* location for the temporary file.
|
||||
*
|
||||
* The disc threshold can be set with the "--vips-disc-threshold"
|
||||
* command-line argument, or the IM_DISC_THRESHOLD environment variable.
|
||||
* The value is a simple integer, but can take a unit postfix of "k",
|
||||
* "m" or "g" to indicate kilobytes, megabytes or gigabytes.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* |[
|
||||
* vips --vips-disc-threshold "500m" im_copy fred.tif fred.v
|
||||
* ]|
|
||||
*
|
||||
* will copy via disc if "fred.tif" is more than 500 Mbytes
|
||||
* uncompressed. The default threshold is 100MB.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"w"</emphasis>
|
||||
* opens the named file for writing. It looks at the file name
|
||||
* suffix to determine the type to write -- for example:
|
||||
*
|
||||
* |[
|
||||
* im_open( "fred.tif", "w" )
|
||||
* ]|
|
||||
*
|
||||
* will write in TIFF format.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"t"</emphasis>
|
||||
* creates a temporary memory buffer image.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"p"</emphasis>
|
||||
* creates a "glue" descriptor you can use to join two image
|
||||
* processing operations together.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"rw"</emphasis>
|
||||
* opens the named file for reading and writing. This will only work for
|
||||
* VIPS files in a format native to your machine. It is only for
|
||||
* paintbox-type applications.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* </itemizedlist>
|
||||
*
|
||||
* See also: im_close(), #VipsFormat
|
||||
*
|
||||
* Returns: the image descriptor on success and NULL on error.
|
||||
*/
|
||||
IMAGE *
|
||||
im_open( const char *filename, const char *mode )
|
||||
{
|
||||
IMAGE *im;
|
||||
VipsFormatClass *format;
|
||||
|
||||
/* Pass in a nonsense name for argv0 ... this init world is only here
|
||||
* for old programs which are missing an im_init_world() call. We must
|
||||
* have threads set up before we can process.
|
||||
*/
|
||||
if( im_init_world( "vips" ) )
|
||||
im_error_clear();
|
||||
|
||||
if( !filename || !mode ) {
|
||||
im_error( "im_open", "%s", _( "NULL filename or mode" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
we can't use the vips handler in the format system, since we
|
||||
want to be able to open the image directly rather than
|
||||
copying to an existing descriptor
|
||||
|
||||
if we don't do this, things like paintbox apps won't work
|
||||
|
||||
*/
|
||||
|
||||
switch( mode[0] ) {
|
||||
case 'r':
|
||||
if( (format = vips_format_for_file( filename )) ) {
|
||||
if( strcmp( VIPS_OBJECT_CLASS( format )->nickname,
|
||||
"vips" ) == 0 ) {
|
||||
if( !(im = im_open_vips( filename )) )
|
||||
return( NULL );
|
||||
}
|
||||
else if( !(im = open_sub( format, filename,
|
||||
mode[1] == 'd' )) )
|
||||
return( NULL );
|
||||
}
|
||||
else
|
||||
return( NULL );
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if( (format = vips_format_for_name( filename )) ) {
|
||||
if( strcmp( VIPS_OBJECT_CLASS( format )->nickname,
|
||||
"vips" ) == 0 )
|
||||
im = im_openout( filename );
|
||||
else {
|
||||
if( !(im = im_open( filename, "p" )) )
|
||||
return( NULL );
|
||||
if( attach_sb( im, format->save, filename ) ) {
|
||||
im_close( im );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char suffix[FILENAME_MAX];
|
||||
|
||||
im_filename_suffix( filename, suffix );
|
||||
im_error( "im_open",
|
||||
_( "unsupported filetype \"%s\"" ),
|
||||
suffix );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
im = im_setbuf( filename );
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
im = im_partial( filename );
|
||||
break;
|
||||
|
||||
default:
|
||||
im_error( "im_open", _( "bad mode \"%s\"" ), mode );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* Attach progress feedback, if required.
|
||||
*/
|
||||
if( im__progress || g_getenv( "IM_PROGRESS" ) ) {
|
||||
Progress *progress = IM_NEW( im, Progress );
|
||||
|
||||
progress->im = im;
|
||||
im_add_evalstart_callback( im,
|
||||
(im_callback_fn) evalstart_cb, progress, NULL );
|
||||
im_add_eval_callback( im,
|
||||
(im_callback_fn) eval_cb, progress, NULL );
|
||||
im_add_evalend_callback( im,
|
||||
(im_callback_fn) evalend_cb, progress, NULL );
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "im_open: success for %s (%p)\n", im->filename, im );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Just here for compatibility.
|
||||
*/
|
||||
IMAGE *
|
||||
im_open_header( const char *file )
|
||||
{
|
||||
return( im_open( file, "r" ) );
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/* @(#) Function which unmaps a file memory mapped by mapfile()
|
||||
* @(#) The argument baseaddress should be the pointer returned by mapfile();
|
||||
* @(#) The function finds the size of the file from
|
||||
* @(#)
|
||||
* @(#) int im_unmapfile(fd, baseaddress)
|
||||
* @(#) int fd;
|
||||
* @(#) char *baseaddress;
|
||||
* @(#)
|
||||
* @(#) Returns 0 on success and -1 on error.
|
||||
* @(#)
|
||||
* Copyright: Nicos Dessipris
|
||||
* Wriiten on: 13/02/1990
|
||||
* Updated on:
|
||||
* 18/4/97 JC
|
||||
* - ANSIfied
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <sys/types.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
int
|
||||
im_unmapfile( IMAGE *im )
|
||||
{
|
||||
if( im__munmap( im->baseaddr, im->length ) )
|
||||
return( -1 );
|
||||
im->baseaddr = NULL;
|
||||
im->length = 0;
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -45,7 +45,6 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
@ -319,70 +318,184 @@ enum {
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
/* Our signals.
|
||||
*/
|
||||
enum {
|
||||
SIG_PRECLOSE,
|
||||
SIG_CLOSE,
|
||||
SIG_POSTCLOSE,
|
||||
SIG_PREEVAL,
|
||||
SIG_EVAL,
|
||||
SIG_POSTEVAL,
|
||||
SIG_WRITTEN,
|
||||
SIG_LAST
|
||||
};
|
||||
|
||||
/* Progress feedback. Only really useful for testing, tbh.
|
||||
*/
|
||||
int im__progress = 0;
|
||||
|
||||
/* A string giving the image size (in bytes of uncompressed image) above which
|
||||
* we decompress to disc on open. Can be eg. "12m" for 12 megabytes.
|
||||
*/
|
||||
char *im__disc_threshold = NULL;
|
||||
|
||||
static guint vips_image_signals[SIG_LAST] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE( VipsImage, vips_image, VIPS_TYPE_OBJECT );
|
||||
|
||||
static int
|
||||
vips_image_preclose( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
if( !image->preclose ) {
|
||||
image->preclose = TRUE;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_preclose: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_PRECLOSE], 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vips_image_close( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
if( !image->close ) {
|
||||
image->close = TRUE;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_close: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_CLOSE], 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vips_image_postclose( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
if( !image->postclose ) {
|
||||
image->postclose = TRUE;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_postclose: " );
|
||||
vips_object_print( object );
|
||||
printf( "vips_image_postclose: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
|
||||
needs to be a true signal
|
||||
|
||||
finish removing im_close()
|
||||
|
||||
|
||||
|
||||
return( image_class->postclose( image ) );
|
||||
g_signal_emit( image, vips_image_signals[SIG_POSTCLOSE], 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vips_image_finalize( GObject *gobject )
|
||||
{
|
||||
VipsImage *image = VIPS_IMAGE( gobject );
|
||||
|
||||
/* Should be no regions defined on the image, since they all hold a
|
||||
* ref to their host image.
|
||||
*/
|
||||
g_assert( !image->regions );
|
||||
|
||||
/* Therefore there should be no windows.
|
||||
*/
|
||||
g_assert( !image->windows );
|
||||
|
||||
/* Junk generate functions.
|
||||
*/
|
||||
image->start = NULL;
|
||||
image->generate = NULL;
|
||||
image->stop = NULL;
|
||||
image->client1 = NULL;
|
||||
image->client2 = NULL;
|
||||
|
||||
/* No more upstream/downstream links.
|
||||
*/
|
||||
im__link_break_all( image );
|
||||
|
||||
/* Any file mapping?
|
||||
*/
|
||||
if( image->baseaddr ) {
|
||||
/* MMAP file.
|
||||
*/
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: unmapping file ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
im__munmap( image->baseaddr, image->length );
|
||||
image->baseaddr = NULL;
|
||||
image->length = 0;
|
||||
|
||||
/* This must have been a pointer to the mmap region, rather
|
||||
* than a setbuf.
|
||||
*/
|
||||
image->data = NULL;
|
||||
}
|
||||
|
||||
/* Is there a file descriptor?
|
||||
*/
|
||||
if( image->fd != -1 ) {
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: closing output file ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
|
||||
if( image->dtype == IM_OPENOUT )
|
||||
(void) im__writehist( image );
|
||||
if( close( im->fd ) == -1 )
|
||||
im_error( "im_close",
|
||||
_( "unable to close fd for %s" ),
|
||||
image->filename );
|
||||
im->fd = -1;
|
||||
}
|
||||
|
||||
/* Any image data?
|
||||
*/
|
||||
if( image->data ) {
|
||||
/* Buffer image. Only free stuff we know we allocated.
|
||||
*/
|
||||
if( image->dtype == IM_SETBUF ) {
|
||||
#ifdef DEBUG_IO
|
||||
printf( "im__close: freeing buffer ..\n" );
|
||||
#endif /*DEBUG_IO*/
|
||||
im_free( image->data );
|
||||
image->dtype = IM_NONE;
|
||||
}
|
||||
|
||||
image->data = NULL;
|
||||
}
|
||||
|
||||
vips_image_close( image );
|
||||
|
||||
VIPS_FREE( image->filename );
|
||||
VIPS_FREE( image->mode );
|
||||
|
||||
/* Use -1 rather than 0 for unset.
|
||||
*/
|
||||
if( image->fd != -1 ) {
|
||||
close( image->fd );
|
||||
image->fd = -1;
|
||||
}
|
||||
|
||||
VIPS_FREEF( g_mutex_free, image->sslock );
|
||||
|
||||
most of im__close() is below:
|
||||
VIPS_FREE( image->Hist );
|
||||
VIPS_FREEF( im__gslist_gvalue_free, image->history_list );
|
||||
im__meta_destroy( image );
|
||||
im__time_destroy( image );
|
||||
|
||||
result |= im__trigger_callbacks( im->postclosefns );
|
||||
IM_FREEF( im_slist_free_all, im->postclosefns );
|
||||
|
||||
IM_FREEF( g_mutex_free, im->sslock );
|
||||
IM_FREE( im->filename );
|
||||
IM_FREE( im->Hist );
|
||||
IM_FREEF( im__gslist_gvalue_free, im->history_list );
|
||||
im__meta_destroy( im );
|
||||
im__time_destroy( im );
|
||||
|
||||
g_mutex_lock( im__global_lock );
|
||||
im__open_images = g_slist_remove( im__open_images, im );
|
||||
g_mutex_unlock( im__global_lock );
|
||||
vips_image_postclose( image );
|
||||
|
||||
G_OBJECT_CLASS( vips_image_parent_class )->finalize( gobject );
|
||||
}
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
static void
|
||||
vips_image_dispose( GObject *gobject )
|
||||
{
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "vips_image_dispose: " );
|
||||
vips_object_print( VIPS_OBJECT( gobject ) );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
G_OBJECT_CLASS( vips_image_parent_class )->dispose( gobject );
|
||||
}
|
||||
@ -390,12 +503,53 @@ vips_image_dispose( GObject *gobject )
|
||||
static void
|
||||
vips_image_destroy( VipsObject *object )
|
||||
{
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "vips_image_destroy: " );
|
||||
vips_object_print( VIPS_OBJECT( gobject ) );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
vips_image_preclose( image );
|
||||
|
||||
VIPS_OBJECT_CLASS( vips_image_parent_class )->destroy( object );
|
||||
}
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
static void
|
||||
vips_image_info( VipsObject *object, VipsBuf *buf )
|
||||
{
|
||||
VipsImage *image = VIPS_IMAGE( object );
|
||||
|
||||
vips_buf_appendf( buf, "image->dtype = %d\n", image->dtype );
|
||||
vips_buf_appendf( buf, "image->demand = %s\n",
|
||||
VIPS_ENUM_STRING( VIPS_TYPE_DEMAND, image->demand ) );
|
||||
vips_buf_appendf( buf, "image->magic = 0x%x\n", image->magic );
|
||||
vips_buf_appendf( buf, "image->fd = %d\n", image->fd );
|
||||
vips_buf_appendf( buf, "image->baseaddr = %p\n", image->baseaddr );
|
||||
vips_buf_appendf( buf, "image->length = %#"
|
||||
G_GSIZE_MODIFIER "x\n", image->length );
|
||||
vips_buf_appendf( buf, "image->data = %p\n", image->data );
|
||||
vips_buf_appendf( buf, "image->sizeof_header = %d\n",
|
||||
image->sizeof_header );
|
||||
|
||||
VIPS_OBJECT_CLASS( parent_class )->info( object, buf );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_generate_caption( VipsObject *object, VipsBuf *buf )
|
||||
{
|
||||
VipsImage *image = VIPS_IMAGE( object );
|
||||
|
||||
vips_buf_appendf( buf,
|
||||
ngettext(
|
||||
"%dx%d %s, %d band, %s",
|
||||
"%dx%d %s, %d bands, %s", image->bands ),
|
||||
vips_image_get_width( image ),
|
||||
vips_image_get_height( image ),
|
||||
VIPS_ENUM_NICK( VIPS_TYPE_FORMAT,
|
||||
vips_image_get_format( image ) ),
|
||||
vips_image_get_bands( image ),
|
||||
VIPS_ENUM_NICK( VIPS_TYPE_TYPE,
|
||||
vips_image_get_type( image ) ) );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips_format_is_vips( VipsFormatClass *format )
|
||||
@ -403,6 +557,339 @@ vips_format_is_vips( VipsFormatClass *format )
|
||||
return( strcmp( VIPS_OBJECT_CLASS( format )->nickname, "vips" ) == 0 );
|
||||
}
|
||||
|
||||
/* Lazy open.
|
||||
*/
|
||||
|
||||
/* What we track during a delayed open.
|
||||
*/
|
||||
typedef struct {
|
||||
VipsImage *out;
|
||||
|
||||
VipsFormatClass *format;/* Read in pixels with this */
|
||||
gboolean disc; /* Read via disc requested */
|
||||
VipsImage *image; /* The real decompressed image */
|
||||
} Lazy;
|
||||
|
||||
static void
|
||||
lazy_free( Lazy *lazy )
|
||||
{
|
||||
VIPS_UNREF( lazy->image );
|
||||
}
|
||||
|
||||
static Lazy *
|
||||
lazy_new( VipsImage *out, VipsFormatClass *format, gboolean disc )
|
||||
{
|
||||
Lazy *lazy;
|
||||
|
||||
if( !(lazy = IM_NEW( out, Lazy )) )
|
||||
return( NULL );
|
||||
lazy->out = out;
|
||||
lazy->format = format;
|
||||
lazy->disc = disc;
|
||||
lazy->image = NULL;
|
||||
g_signal_connect( out, "close", lazy_free, NULL );
|
||||
|
||||
return( lazy );
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char unit;
|
||||
int multiplier;
|
||||
} Unit;
|
||||
|
||||
static size_t
|
||||
parse_size( const char *size_string )
|
||||
{
|
||||
static Unit units[] = {
|
||||
{ 'k', 1024 },
|
||||
{ 'm', 1024 * 1024 },
|
||||
{ 'g', 1024 * 1024 * 1024 }
|
||||
};
|
||||
|
||||
size_t size;
|
||||
int n;
|
||||
int i, j;
|
||||
char *unit;
|
||||
|
||||
/* An easy way to alloc a buffer large enough.
|
||||
*/
|
||||
unit = g_strdup( size_string );
|
||||
n = sscanf( size_string, "%d %s", &i, unit );
|
||||
if( n > 0 )
|
||||
size = i;
|
||||
if( n > 1 ) {
|
||||
for( j = 0; j < IM_NUMBER( units ); j++ )
|
||||
if( tolower( unit[0] ) == units[j].unit ) {
|
||||
size *= units[j].multiplier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free( unit );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "parse_size: parsed \"%s\" as %zd\n", size_string, size );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( size );
|
||||
}
|
||||
|
||||
static size_t
|
||||
disc_threshold( void )
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
static size_t threshold;
|
||||
|
||||
if( !done ) {
|
||||
const char *env;
|
||||
|
||||
done = TRUE;
|
||||
|
||||
/* 100mb default.
|
||||
*/
|
||||
threshold = 100 * 1024 * 1024;
|
||||
|
||||
if( (env = g_getenv( "IM_DISC_THRESHOLD" )) )
|
||||
threshold = parse_size( env );
|
||||
|
||||
if( im__disc_threshold )
|
||||
threshold = parse_size( im__disc_threshold );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "disc_threshold: %zd bytes\n", threshold );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
|
||||
return( threshold );
|
||||
}
|
||||
|
||||
static VipsImage *
|
||||
lazy_image( Lazy *lazy )
|
||||
{
|
||||
VipsImage *image;
|
||||
|
||||
/* We open to disc if:
|
||||
* - 'disc' is set
|
||||
* - disc_threshold() has not been set to zero
|
||||
* - the format does not support lazy read
|
||||
* - the image will be more than a megabyte, uncompressed
|
||||
*/
|
||||
image = NULL;
|
||||
if( lazy->disc &&
|
||||
disc_threshold() &&
|
||||
!(vips_format_get_flags( lazy->format, lazy->out->filename ) &
|
||||
VIPS_FORMAT_PARTIAL) ) {
|
||||
size_t size = IM_IMAGE_SIZEOF_LINE( lazy->out ) *
|
||||
lazy->out->Ysize;
|
||||
|
||||
if( size > disc_threshold() ) {
|
||||
if( !(image = im__open_temp( "%s.v" )) )
|
||||
return( NULL );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "lazy_image: opening to disc file \"%s\"\n",
|
||||
image->filename );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, fall back to a "p".
|
||||
*/
|
||||
if( !image &&
|
||||
!(image = im_open( lazy->out->filename, "p" )) )
|
||||
return( NULL );
|
||||
|
||||
return( image );
|
||||
}
|
||||
|
||||
/* Our start function ... do the lazy open, if necessary, and return a region
|
||||
* on the new image.
|
||||
*/
|
||||
static void *
|
||||
open_lazy_start( VipsImage *out, void *a, void *dummy )
|
||||
{
|
||||
Lazy *lazy = (Lazy *) a;
|
||||
const char *filename = lazy->out->filename;
|
||||
|
||||
if( !lazy->image ) {
|
||||
if( !(lazy->image = lazy_image( lazy )) ||
|
||||
lazy->format->load( filename, lazy->image ) ||
|
||||
im_pincheck( lazy->image ) ) {
|
||||
VIPS_UNREF( lazy->image );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
return( im_region_create( lazy->image ) );
|
||||
}
|
||||
|
||||
/* Just copy.
|
||||
*/
|
||||
static int
|
||||
open_lazy_generate( REGION *or, void *seq, void *a, void *b )
|
||||
{
|
||||
REGION *ir = (REGION *) seq;
|
||||
|
||||
Rect *r = &or->valid;
|
||||
|
||||
/* Ask for input we need.
|
||||
*/
|
||||
if( im_prepare( ir, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Attach output region to that.
|
||||
*/
|
||||
if( im_region_region( or, ir, r, r->left, r->top ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Lazy open ... init the header with the first OpenLazyFn, delay actually
|
||||
* decoding pixels with the second OpenLazyFn until the first generate().
|
||||
*/
|
||||
static int
|
||||
vips_open_lazy( VipsImage *out,
|
||||
VipsFormatClass *format, gboolean disc, IMAGE *out )
|
||||
{
|
||||
Lazy *lazy;
|
||||
|
||||
if( !(lazy = lazy_new( out, format, disc )) )
|
||||
return( -1 );
|
||||
|
||||
/* Read header fields to init the return image. THINSTRIP since this is
|
||||
* probably a disc file. We can't tell yet whether we will be opening
|
||||
* to memory, sadly, so we can't suggest ANY.
|
||||
*/
|
||||
if( format->header( out->filename, out ) ||
|
||||
im_demand_hint( out, IM_THINSTRIP, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Then 'start' creates the real image and 'gen' paints 'out' with
|
||||
* pixels from the real image on demand.
|
||||
*/
|
||||
if( im_generate( out,
|
||||
open_lazy_start, open_lazy_generate, im_stop_one,
|
||||
lazy, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Lazy save.
|
||||
*/
|
||||
|
||||
/* If we write to (eg.) TIFF, actually do the write
|
||||
* to a "p" and on "written" do im_vips2tiff() or whatever. Track save
|
||||
* parameters here.
|
||||
*/
|
||||
typedef struct {
|
||||
int (*save_fn)(); /* Save function */
|
||||
char *filename; /* Save args */
|
||||
} SaveBlock;
|
||||
|
||||
/* From "written" callback: invoke a delayed save.
|
||||
*/
|
||||
static int
|
||||
vips_image_save_cb( VipsImage *image, SaveBlock *sb )
|
||||
{
|
||||
if( sb->save_fn( image, sb->filename ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_attach_save( VipsImage *image, int (*save_fn)(), const char *filename )
|
||||
{
|
||||
SaveBlock *sb;
|
||||
|
||||
if( (sb = IM_NEW( image, SaveBlock )) ) {
|
||||
sb->save_fn = save_fn;
|
||||
sb->filename = im_strdup( image, filename );
|
||||
g_signal_connect( image, "written", vips_image_save_cb, sb );
|
||||
}
|
||||
}
|
||||
|
||||
/* Progress feedback.
|
||||
*/
|
||||
|
||||
/* What we track during an eval.
|
||||
*/
|
||||
typedef struct {
|
||||
IMAGE *image;
|
||||
|
||||
int last_percent; /* The last %complete we displayed */
|
||||
} Progress;
|
||||
|
||||
static int
|
||||
vips_image_evalstart_cb( Progress *progress )
|
||||
{
|
||||
int tile_width;
|
||||
int tile_height;
|
||||
int nlines;
|
||||
|
||||
progress->last_percent = 0;
|
||||
|
||||
vips_get_tile_size( progress->im, &tile_width, &tile_height, &nlines );
|
||||
printf( _( "%s %s: %d threads, %d x %d tiles, groups of %d scanlines" ),
|
||||
g_get_prgname(), progress->im->filename,
|
||||
im_concurrency_get(),
|
||||
tile_width, tile_height, nlines );
|
||||
printf( "\n" );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_image_eval_cb( Progress *progress )
|
||||
{
|
||||
IMAGE *im = progress->im;
|
||||
|
||||
if( im->time->percent != progress->last_percent ) {
|
||||
printf( _( "%s %s: %d%% complete" ),
|
||||
g_get_prgname(), im->filename, im->time->percent );
|
||||
printf( "\r" );
|
||||
fflush( stdout );
|
||||
|
||||
progress->last_percent = im->time->percent;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_image_evalend_cb( Progress *progress )
|
||||
{
|
||||
IMAGE *im = progress->im;
|
||||
|
||||
/* Spaces at end help to erase the %complete message we overwrite.
|
||||
*/
|
||||
printf( _( "%s %s: done in %ds \n" ),
|
||||
g_get_prgname(), im->filename, im->time->run );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Attach progress feedback, if required.
|
||||
*/
|
||||
static void
|
||||
vips_image_add_progress( VipsImage *image )
|
||||
{
|
||||
if( im__progress ||
|
||||
g_getenv( "IM_PROGRESS" ) ) {
|
||||
|
||||
Progress *progress = IM_NEW( image, Progress );
|
||||
|
||||
progress->image = image;
|
||||
g_signal_connect( image, "evalstart",
|
||||
vips_image_evalstart_cb, progress );
|
||||
g_signal_connect( image, "eval",
|
||||
vips_image_eval_cb, progress );
|
||||
g_signal_connect( image, "evalend",
|
||||
vips_image_evalend_cb, progress );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vips_image_build( VipsObject *object )
|
||||
{
|
||||
@ -460,7 +947,8 @@ vips_image_build( VipsObject *object )
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( vips_open_sub( format, filename, mode[1] == 'd' ) )
|
||||
if( vips_open_lazy( image,
|
||||
format, filename, mode[1] == 'd' ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
@ -474,9 +962,8 @@ vips_image_build( VipsObject *object )
|
||||
}
|
||||
else {
|
||||
image->dtype = VIPS_IMAGE_TYPE_PARTIAL;
|
||||
if( vips_attach_save( image,
|
||||
format->save, filename ) )
|
||||
return( -1 );
|
||||
vips_attach_save( image,
|
||||
format->save, filename );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -506,52 +993,16 @@ vips_image_build( VipsObject *object )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
vips_image_add_progress( image );
|
||||
|
||||
#ifdef DEBUG_VIPS
|
||||
printf ("vips_image_build: ");
|
||||
printf( "vips_image_build: " );
|
||||
vips_object_dump( VIPS_OBJECT( image ) );
|
||||
#endif /*DEBUG_VIPS*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_info( VipsObject *object, VipsBuf *buf )
|
||||
{
|
||||
VipsImage *image = VIPS_IMAGE( object );
|
||||
|
||||
vips_buf_appendf( buf, "image->dtype = %d\n", image->dtype );
|
||||
vips_buf_appendf( buf, "image->demand = %s\n",
|
||||
VIPS_ENUM_STRING( VIPS_TYPE_DEMAND, image->demand ) );
|
||||
vips_buf_appendf( buf, "image->magic = 0x%x\n", image->magic );
|
||||
vips_buf_appendf( buf, "image->fd = %d\n", image->fd );
|
||||
vips_buf_appendf( buf, "image->baseaddr = %p\n", image->baseaddr );
|
||||
vips_buf_appendf( buf, "image->length = %#"
|
||||
G_GSIZE_MODIFIER "x\n", image->length );
|
||||
vips_buf_appendf( buf, "image->data = %p\n", image->data );
|
||||
vips_buf_appendf( buf, "image->sizeof_header = %d\n",
|
||||
image->sizeof_header );
|
||||
|
||||
VIPS_OBJECT_CLASS( parent_class )->info( object, buf );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_generate_caption( VipsObject *object, VipsBuf *buf )
|
||||
{
|
||||
VipsImage *image = VIPS_IMAGE( object );
|
||||
|
||||
vips_buf_appendf( buf,
|
||||
ngettext(
|
||||
"%dx%d %s, %d band, %s",
|
||||
"%dx%d %s, %d bands, %s", image->bands ),
|
||||
vips_image_get_width( image ),
|
||||
vips_image_get_height( image ),
|
||||
VIPS_ENUM_NICK( VIPS_TYPE_FORMAT,
|
||||
vips_image_get_format( image ) ),
|
||||
vips_image_get_bands( image ),
|
||||
VIPS_ENUM_NICK( VIPS_TYPE_TYPE,
|
||||
vips_image_get_type( image ) ) );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_class_init( VipsImageClass *class )
|
||||
{
|
||||
@ -568,15 +1019,11 @@ vips_image_class_init( VipsImageClass *class )
|
||||
im_error_clear();
|
||||
|
||||
gobject_class->finalize = vips_image_finalize;
|
||||
#ifdef VIPS_DEBUG
|
||||
gobject_class->dispose = vips_image_dispose;
|
||||
#endif /*VIPS_DEBUG*/
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
vobject_class->destroy = vips_image_destroy;
|
||||
#endif /*VIPS_DEBUG*/
|
||||
vobject_class->info = vips_image_info;
|
||||
vobject_class->generate_caption = vips_image_generate_caption;
|
||||
vobject_class->copy_attributes = vips_image_copy_attributes;
|
||||
@ -655,6 +1102,60 @@ vips_image_class_init( VipsImageClass *class )
|
||||
vips_object_class_install_argument( vobject_class, pspec,
|
||||
VIPS_ARGUMENT_NONE,
|
||||
G_STRUCT_OFFSET( VipsImage, demand ) );
|
||||
|
||||
/* Create signals.
|
||||
*/
|
||||
vips_image_signals[SIG_PRECLOSE] = g_signal_new( "preclose",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, preclose ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
vips_image_signals[SIG_CLOSE] = g_signal_new( "close",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, close ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
vips_image_signals[SIG_POSTCLOSE] = g_signal_new( "postclose",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, postclose ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
|
||||
vips_image_signals[SIG_PREEVAL] = g_signal_new( "preeval",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, preeval ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
vips_image_signals[SIG_EVAL] = g_signal_new( "eval",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, eval ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
vips_image_signals[SIG_POSTEVAL] = g_signal_new( "posteval",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET( VipsImageClass, posteval ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
|
||||
vips_image_signals[SIG_WRITTEN] = g_signal_new( "written",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET( VipsImageClass, written ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -671,10 +1172,6 @@ vips_image_init( VipsImage *image )
|
||||
image->fd = -1; /* since 0 is stdout */
|
||||
image->sizeof_header = VIPS_SIZEOF_HEADER;
|
||||
image->sslock = g_mutex_new ();
|
||||
|
||||
g_mutex_lock( im__global_lock );
|
||||
im__open_images = g_slist_prepend( im__open_images, image );
|
||||
g_mutex_unlock( im__global_lock );
|
||||
}
|
||||
|
||||
/* Set of access functions.
|
||||
@ -739,3 +1236,168 @@ vips_image_get_yoffset( VipsImage *image )
|
||||
{
|
||||
return( image->Yoffset );
|
||||
}
|
||||
|
||||
void
|
||||
vips_image_written( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_written: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_WRITTEN], 0 );
|
||||
}
|
||||
|
||||
void
|
||||
vips_image_preeval( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_preeval: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_PREEVAL], 0 );
|
||||
}
|
||||
|
||||
void
|
||||
vips_image_eval( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_eval: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_EVAL], 0 );
|
||||
}
|
||||
|
||||
void
|
||||
vips_image_posteval( VipsImage *image )
|
||||
{
|
||||
VipsImageClass *image_class = VIPS_IMAGE_GET_CLASS( image );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_image_posteval: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_POSTEVAL], 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_open:
|
||||
* @filename: file to open
|
||||
* @mode: mode to open with
|
||||
*
|
||||
* im_open() examines the mode string, and creates an appropriate #IMAGE.
|
||||
*
|
||||
* <itemizedlist>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"r"</emphasis>
|
||||
* opens the named file for reading. If the file is not in the native
|
||||
* VIPS format for your machine, im_open() automatically converts the
|
||||
* file for you in memory.
|
||||
*
|
||||
* For some large files (eg. TIFF) this may
|
||||
* not be what you want, it can fill memory very quickly. Instead, you
|
||||
* can either use "rd" mode (see below), or you can use the lower-level
|
||||
* API and control the loading process yourself. See
|
||||
* #VipsFormat.
|
||||
*
|
||||
* im_open() can read files in most formats.
|
||||
*
|
||||
* Note that <emphasis>"r"</emphasis> mode works in at least two stages.
|
||||
* It should return quickly and let you check header fields. It will
|
||||
* only actually read in pixels when you first access them.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"rd"</emphasis>
|
||||
* opens the named file for reading. If the uncompressed image is larger
|
||||
* than a threshold and the file format does not support random access,
|
||||
* rather than uncompressing to memory, im_open() will uncompress to a
|
||||
* temporary disc file. This file will be automatically deleted when the
|
||||
* IMAGE is closed.
|
||||
*
|
||||
* See im_system_image() for an explanation of how VIPS selects a
|
||||
* location for the temporary file.
|
||||
*
|
||||
* The disc threshold can be set with the "--vips-disc-threshold"
|
||||
* command-line argument, or the IM_DISC_THRESHOLD environment variable.
|
||||
* The value is a simple integer, but can take a unit postfix of "k",
|
||||
* "m" or "g" to indicate kilobytes, megabytes or gigabytes.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* |[
|
||||
* vips --vips-disc-threshold "500m" im_copy fred.tif fred.v
|
||||
* ]|
|
||||
*
|
||||
* will copy via disc if "fred.tif" is more than 500 Mbytes
|
||||
* uncompressed. The default threshold is 100MB.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"w"</emphasis>
|
||||
* opens the named file for writing. It looks at the file name
|
||||
* suffix to determine the type to write -- for example:
|
||||
*
|
||||
* |[
|
||||
* im_open( "fred.tif", "w" )
|
||||
* ]|
|
||||
*
|
||||
* will write in TIFF format.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"t"</emphasis>
|
||||
* creates a temporary memory buffer image.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"p"</emphasis>
|
||||
* creates a "glue" descriptor you can use to join two image
|
||||
* processing operations together.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>
|
||||
* <emphasis>"rw"</emphasis>
|
||||
* opens the named file for reading and writing. This will only work for
|
||||
* VIPS files in a format native to your machine. It is only for
|
||||
* paintbox-type applications.
|
||||
* </para>
|
||||
* </listitem>
|
||||
* </itemizedlist>
|
||||
*
|
||||
* See also: im_close(), #VipsFormat
|
||||
*
|
||||
* Returns: the image descriptor on success and NULL on error.
|
||||
*/
|
||||
VipsImage *
|
||||
im_open( const char *filename, const char *mode )
|
||||
{
|
||||
VipsImage *image;
|
||||
|
||||
image = VIPS_IMAGE( g_object_new( VIPS_IMAGE_TYPE, NULL ) );
|
||||
g_object_set( image,
|
||||
"filename", filename,
|
||||
"mode", mode,
|
||||
NULL );
|
||||
if( vips_object_build( image ) ) {
|
||||
VIPS_UNREF( image );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( image );
|
||||
}
|
||||
|
@ -56,6 +56,10 @@ enum {
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
/* Table of all objects, handy for debugging.
|
||||
*/
|
||||
static GHashTable *vips_object_all = NULL;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE( VipsObject, vips_object, G_TYPE_OBJECT );
|
||||
|
||||
int
|
||||
@ -348,6 +352,7 @@ vips_object_finalize( GObject *gobject )
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_hash_table_remove( vips_object_all, object );
|
||||
IM_FREEF( vips_argument_table_destroy, object->argument_table );
|
||||
|
||||
G_OBJECT_CLASS( vips_object_parent_class )->finalize( gobject );
|
||||
@ -707,6 +712,10 @@ vips_object_class_init( VipsObjectClass *object_class )
|
||||
|
||||
GParamSpec *pspec;
|
||||
|
||||
if( !vips_object_all )
|
||||
vips_object_all = g_hash_table_new(
|
||||
g_direct_hash, g_direct_equal );
|
||||
|
||||
gobject_class->dispose = vips_object_dispose;
|
||||
gobject_class->finalize = vips_object_finalize;
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
@ -762,6 +771,8 @@ vips_object_init( VipsObject *object )
|
||||
printf( "vips_object_init: " );
|
||||
vips_object_print( object );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
g_hash_table_insert( vips_object_all, object, object );
|
||||
}
|
||||
|
||||
/* Add a vipsargument ... automate some stuff with this.
|
||||
@ -1044,3 +1055,32 @@ vips_object_to_string( VipsObject *object, VipsBuf *buf )
|
||||
if( !first )
|
||||
vips_buf_appends( buf, ")" );
|
||||
}
|
||||
|
||||
typdef struct {
|
||||
VSListMap2Fn fn;
|
||||
void *a;
|
||||
void *b;
|
||||
void *result;
|
||||
} VipsObjectMapArgs;
|
||||
|
||||
static void
|
||||
vips_object_map_sub( VipsObject *object, VipsObjectMapArgs *args )
|
||||
{
|
||||
if( !args->result )
|
||||
args->result = fn( object, args->a, args->b );
|
||||
}
|
||||
|
||||
void *
|
||||
vips_object_map( VSListMap2Fn fn, void *a, void *b )
|
||||
{
|
||||
VipsObjectMapArgs args;
|
||||
|
||||
args.fn = fn;
|
||||
args.a = a;
|
||||
args.b = b;
|
||||
args.result = NULL;
|
||||
g_hash_table_foreach( vips_object_all,
|
||||
(GHFunc) vips_object_map_sub, &args );
|
||||
|
||||
return( args.result );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user