| /* demand hints |
| * |
| * Copyright: The National Gallery, 1993 |
| * Written on: 6/9/93 |
| * Modified on : |
| * 2/3/98 JC |
| * - IM_ANY added |
| * 19/5/06 |
| * - minor change to rules: don't force ANY on no-input operations ... |
| * fails for image import |
| * 1/12/06 |
| * - build parent/child links as well |
| * 8/10/09 |
| * - gtkdoc comments |
| * 5/3/10 |
| * - move link maintenance to im_demand_hint |
| * 8/3/10 |
| * - rename parent/child as downstream/upstream, much clearer! |
| */ |
| |
| /* |
| |
| 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 <stdarg.h> |
| |
| #include <vips/vips.h> |
| #include <vips/internal.h> |
| #include <vips/debug.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| /* Max number of images we can handle. |
| */ |
| #define MAX_IMAGES (1000) |
| |
| /* Make a upstream/downstream link. upstream is one of downstream's inputs. |
| */ |
| static void |
| im__link_make( IMAGE *im_up, IMAGE *im_down ) |
| { |
| g_assert( im_up ); |
| g_assert( im_down ); |
| |
| im_up->downstream = g_slist_prepend( im_up->downstream, im_down ); |
| im_down->upstream = g_slist_prepend( im_down->upstream, im_up ); |
| |
| /* Propogate the progress indicator. |
| */ |
| if( im_up->progress && !im_down->progress ) |
| im_down->progress = im_up->progress; |
| } |
| |
| static void * |
| im__link_break( IMAGE *im_up, IMAGE *im_down ) |
| { |
| g_assert( im_up ); |
| g_assert( im_down ); |
| g_assert( g_slist_find( im_up->downstream, im_down ) ); |
| g_assert( g_slist_find( im_down->upstream, im_up ) ); |
| |
| im_up->downstream = g_slist_remove( im_up->downstream, im_down ); |
| im_down->upstream = g_slist_remove( im_down->upstream, im_up ); |
| |
| /* Unlink the progress chain. |
| */ |
| if( im_down->progress && im_down->progress == im_up->progress ) |
| im_down->progress = NULL; |
| |
| return( NULL ); |
| } |
| |
| static void * |
| im__link_break_rev( IMAGE *im_down, IMAGE *im_up ) |
| { |
| return( im__link_break( im_up, im_down ) ); |
| } |
| |
| /* An IMAGE is going ... break all links. |
| */ |
| void |
| im__link_break_all( IMAGE *im ) |
| { |
| im_slist_map2( im->upstream, |
| (VSListMap2Fn) im__link_break, im, NULL ); |
| im_slist_map2( im->downstream, |
| (VSListMap2Fn) im__link_break_rev, im, NULL ); |
| |
| g_assert( !im->upstream ); |
| g_assert( !im->downstream ); |
| } |
| |
| static void * |
| im__link_mapp( IMAGE *im, VSListMap2Fn fn, int *serial, void *a, void *b ) |
| { |
| void *res; |
| |
| /* Loop? |
| */ |
| if( im->serial == *serial ) |
| return( NULL ); |
| im->serial = *serial; |
| |
| if( (res = fn( im, a, b )) ) |
| return( res ); |
| |
| return( im_slist_map4( im->downstream, |
| (VSListMap4Fn) im__link_mapp, fn, serial, a, b ) ); |
| } |
| |
| /* Apply a function to an image and all downstream images, direct and indirect. |
| */ |
| void * |
| im__link_map( IMAGE *im, VSListMap2Fn fn, void *a, void *b ) |
| { |
| static int serial = 0; |
| |
| serial += 1; |
| return( im__link_mapp( im, fn, &serial, a, b ) ); |
| } |
| |
| /* Given two im_demand_type, return the most restrictive. |
| */ |
| static im_demand_type |
| find_least( im_demand_type a, im_demand_type b ) |
| { |
| return( (im_demand_type) IM_MIN( (int) a, (int) b ) ); |
| } |
| |
| /** |
| * im_demand_hint_array: |
| * @im: image to set hint for |
| * @hint: hint for this image |
| * @in: array of input images to this operation |
| * |
| * Operations can set demand hints, that is, hints to the VIPS IO system about |
| * the type of region geometry this operation works best with. For example, |
| * operations which transform coordinates will usually work best with |
| * %IM_SMALLTILE, operations which work on local windows of pixels will like |
| * %IM_FATSTRIP. |
| * |
| * VIPS uses the list of input images to build the tree of operations it needs |
| * for the cache invalidation system. You have to call this function, or its |
| * varargs friend im_demand_hint(). |
| * |
| * See also: im_demand_hint(), im_generate(). |
| * |
| * Returns: 0 on success, or -1 on error. |
| */ |
| int |
| im_demand_hint_array( IMAGE *im, VipsDemandStyle hint, IMAGE **in ) |
| { |
| int i, len, nany; |
| |
| /* How many input images are there? And how many are IM_ANY? |
| */ |
| for( i = 0, len = 0, nany = 0; in[i]; i++, len++ ) |
| if( in[i]->dhint == IM_ANY ) |
| nany++; |
| |
| if( len == 0 ) |
| /* No input images? Just set the requested hint. We don't |
| * force ANY, since the operation might be something like |
| * tiled read of an EXR image, where we certainly don't want |
| * ANY. |
| */ |
| ; |
| else if( nany == len ) |
| /* Special case: if all the inputs are IM_ANY, then output can |
| * be IM_ANY regardless of what this function wants. |
| */ |
| hint = IM_ANY; |
| else |
| /* Find the most restrictive of all the hints available to us. |
| */ |
| for( i = 0; i < len; i++ ) |
| hint = find_least( hint, in[i]->dhint ); |
| |
| im->dhint = hint; |
| |
| #ifdef DEBUG |
| printf( "im_demand_hint_array: set dhint for \"%s\" to %s\n", |
| im->filename, im_dhint2char( im->dhint ) ); |
| #endif /*DEBUG*/ |
| |
| /* im depends on all these ims. |
| */ |
| for( i = 0; i < len; i++ ) |
| im__link_make( in[i], im ); |
| |
| /* Set a flag on the image to say we remember to call this thing. |
| * im_generate() and friends check this. |
| */ |
| im->hint_set = TRUE; |
| |
| return( 0 ); |
| } |
| |
| /** |
| * im_demand_hint: |
| * @im: image to set hint for |
| * @hint: hint for this image |
| * @Varargs: %NULL-terminated list of input images to this operation |
| * |
| * Build an array and call im_demand_hint_array(). |
| * |
| * See also: im_demand_hint(), im_generate(). |
| * |
| * Returns: 0 on success, or -1 on error. |
| */ |
| int |
| im_demand_hint( IMAGE *im, VipsDemandStyle hint, ... ) |
| { |
| va_list ap; |
| int i; |
| IMAGE *ar[MAX_IMAGES]; |
| |
| va_start( ap, hint ); |
| for( i = 0; i < MAX_IMAGES && (ar[i] = va_arg( ap, IMAGE * )); i++ ) |
| ; |
| va_end( ap ); |
| if( i == MAX_IMAGES ) { |
| im_error( "im_demand_hint", |
| "%s", _( "too many images" ) ); |
| return( -1 ); |
| } |
| |
| return( im_demand_hint_array( im, hint, ar ) ); |
| } |