| /* Write an image to a memory buffer. |
| * |
| * 16/4/10 |
| * - from vips_sink() |
| */ |
| |
| /* |
| |
| 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 VIPS_DEBUG |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /*HAVE_CONFIG_H*/ |
| #include <vips/intl.h> |
| |
| #include <stdio.h> |
| #include <stdlib.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*/ |
| |
| /* Per-call state. |
| */ |
| typedef struct _Sink { |
| VipsImage *im; |
| |
| /* A big region for the image memory. All the threads write to this. |
| */ |
| REGION *all; |
| |
| /* The position we're at in the image. |
| */ |
| int x; |
| int y; |
| |
| /* The tilesize we've picked. |
| */ |
| int tile_width; |
| int tile_height; |
| int nlines; |
| } Sink; |
| |
| static void |
| sink_free( Sink *sink ) |
| { |
| IM_FREEF( im_region_free, sink->all ); |
| } |
| |
| static int |
| sink_init( Sink *sink, VipsImage *im ) |
| { |
| Rect all; |
| |
| sink->im = im; |
| sink->x = 0; |
| sink->y = 0; |
| |
| all.left = 0; |
| all.top = 0; |
| all.width = im->Xsize; |
| all.height = im->Ysize; |
| |
| if( !(sink->all = im_region_create( im )) || |
| im_region_image( sink->all, &all ) ) { |
| sink_free( sink ); |
| return( -1 ); |
| } |
| |
| vips_get_tile_size( im, |
| &sink->tile_width, &sink->tile_height, &sink->nlines ); |
| |
| return( 0 ); |
| } |
| |
| static int |
| sink_allocate( VipsThreadState *state, void *a, gboolean *stop ) |
| { |
| Sink *sink = (Sink *) a; |
| |
| Rect image, tile; |
| |
| /* Is the state x/y OK? New line or maybe all done. |
| */ |
| if( sink->x >= sink->im->Xsize ) { |
| sink->x = 0; |
| sink->y += sink->tile_height; |
| |
| if( sink->y >= sink->im->Ysize ) { |
| *stop = TRUE; |
| |
| return( 0 ); |
| } |
| } |
| |
| /* x, y and buf are good: save params for thread. |
| */ |
| image.left = 0; |
| image.top = 0; |
| image.width = sink->im->Xsize; |
| image.height = sink->im->Ysize; |
| tile.left = sink->x; |
| tile.top = sink->y; |
| tile.width = sink->tile_width; |
| tile.height = sink->tile_height; |
| im_rect_intersectrect( &image, &tile, &state->pos ); |
| |
| /* Move state on. |
| */ |
| sink->x += sink->tile_width; |
| |
| return( 0 ); |
| } |
| |
| static int |
| sink_work( VipsThreadState *state, void *a ) |
| { |
| Sink *sink = (Sink *) a; |
| |
| if( im_prepare_to( state->reg, sink->all, |
| &state->pos, state->pos.left, state->pos.top ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| static int |
| sink_progress( void *a ) |
| { |
| Sink *sink = (Sink *) a; |
| |
| VIPS_DEBUG_MSG( "sink_progress: %d x %d\n", |
| sink->tile_width, sink->tile_height ); |
| |
| /* Trigger any eval callbacks on our source image and |
| * check for errors. |
| */ |
| if( im__handle_eval( sink->im, |
| sink->tile_width, sink->tile_height ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /** |
| * vips_sink_memory: |
| * @im: generate this image to memory |
| * |
| * Loops over an image, generating it to a memory buffer attached to the |
| * image. |
| * |
| * See also: vips_sink(), vips_get_tile_size(). |
| * |
| * Returns: 0 on success, or -1 on error. |
| */ |
| int |
| vips_sink_memory( VipsImage *im ) |
| { |
| Sink sink; |
| int result; |
| |
| g_assert( !im_image_sanity( im ) ); |
| |
| /* We don't use this, but make sure it's set in case any old binaries |
| * are expecting it. |
| */ |
| im->Bbits = im_bits_of_fmt( im->BandFmt ); |
| |
| if( sink_init( &sink, im ) ) |
| return( -1 ); |
| |
| if( im__start_eval( im ) ) { |
| sink_free( &sink ); |
| return( -1 ); |
| } |
| |
| result = vips_threadpool_run( im, |
| vips_thread_state_new, |
| sink_allocate, |
| sink_work, |
| sink_progress, |
| &sink ); |
| |
| im__end_eval( im ); |
| |
| sink_free( &sink ); |
| |
| return( result ); |
| } |