"Fossies" - the Fresh Open Source Software Archive

Member "vips-8.12.1/libvips/conversion/insert.c" (22 Nov 2021, 14288 Bytes) of package /linux/privat/vips-8.12.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "insert.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 8.12.0_vs_8.12.1.

    1 /* VipsInsert
    2  *
    3  * Copyright: 1990, J. Cupitt
    4  *
    5  * Author: J. Cupitt
    6  * Written on: 02/08/1990
    7  * Modified on : 
    8  * 31/8/93 JC
    9  *  - ANSIfied
   10  *  - Nicos' reformatting undone. Grr!
   11  * 22/12/94
   12  *  - modernised
   13  *  - now does IM_CODING_LABQ too
   14  * 22/6/95 JC
   15  *  - partialized
   16  * 10/2/02 JC
   17  *  - adapted for im_prepare_to() stuff
   18  * 14/4/04
   19  *  - sets Xoffset / Yoffset
   20  * 3/7/06
   21  *  - add sanity range checks
   22  * 24/3/09
   23  *  - added IM_CODING_RAD support
   24  * 30/1/10
   25  *  - cleanups
   26  *  - formatalike/bandalike
   27  *  - gtkdoc
   28  * 29/9/11
   29  *  - rewrite as a class
   30  *  - add expand, bg options
   31  * 5/11/21
   32  *  - add minimise for seq pipelines
   33  */
   34 
   35 /*
   36 
   37     This file is part of VIPS.
   38     
   39     VIPS is free software; you can redistribute it and/or modify
   40     it under the terms of the GNU Lesser General Public License as published by
   41     the Free Software Foundation; either version 2 of the License, or
   42     (at your option) any later version.
   43 
   44     This program is distributed in the hope that it will be useful,
   45     but WITHOUT ANY WARRANTY; without even the implied warranty of
   46     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   47     GNU Lesser General Public License for more details.
   48 
   49     You should have received a copy of the GNU Lesser General Public License
   50     along with this program; if not, write to the Free Software
   51     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   52     02110-1301  USA
   53 
   54  */
   55 
   56 /*
   57 
   58     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
   59 
   60  */
   61 
   62 /*
   63 #define VIPS_DEBUG
   64  */
   65 
   66 #ifdef HAVE_CONFIG_H
   67 #include <config.h>
   68 #endif /*HAVE_CONFIG_H*/
   69 #include <vips/intl.h>
   70 
   71 #include <stdio.h>
   72 #include <stdlib.h>
   73 #include <string.h>
   74 #include <math.h>
   75 
   76 #include <vips/vips.h>
   77 #include <vips/internal.h>
   78 #include <vips/debug.h>
   79 
   80 #include "pconversion.h"
   81 
   82 typedef struct _VipsInsert {
   83     VipsConversion parent_instance;
   84 
   85     /* Params.
   86      */
   87     VipsImage *main;
   88     VipsImage *sub;
   89     int x;
   90     int y;
   91     gboolean expand;
   92     VipsArrayDouble *background;
   93 
   94     /* Pixel we paint calculated from background.
   95      */
   96     VipsPel *ink;
   97 
   98     /* Inputs cast and banded up, plus a NULL at the end. main is 0, sub
   99      * is 1.
  100      */
  101     VipsImage *processed[3];
  102 
  103     /* Geometry.
  104      */
  105     VipsRect rout;      /* Output space */
  106     VipsRect rimage[2]; /* Position of input in output */
  107 
  108     /* TRUE if we've minimised an input.
  109      */
  110     gboolean minimised[2];
  111 
  112 } VipsInsert;
  113 
  114 typedef VipsConversionClass VipsInsertClass;
  115 
  116 G_DEFINE_TYPE( VipsInsert, vips_insert, VIPS_TYPE_CONVERSION );
  117 
  118 /* Trivial case: we just need pels from one of the inputs.
  119  *
  120  * Also used by vips_arrayjoin.
  121  */
  122 int
  123 vips__insert_just_one( VipsRegion *or, VipsRegion *ir, int x, int y )
  124 {
  125     VipsRect need;
  126 
  127     /* Find the part of pos we need.
  128      */
  129     need = or->valid;
  130     need.left -= x;
  131     need.top -= y;
  132     if( vips_region_prepare( ir, &need ) )
  133         return( -1 );
  134 
  135     /* Attach our output to it.
  136      */
  137     if( vips_region_region( or, ir, &or->valid, need.left, need.top ) )
  138         return( -1 );
  139 
  140     return( 0 );
  141 }
  142 
  143 /* Paste in parts of ir that fall within or --- ir is an input REGION for an 
  144  * image positioned at pos within or.
  145  *
  146  * Also used by vips_arrayjoin.
  147  */
  148 int
  149 vips__insert_paste_region( VipsRegion *or, VipsRegion *ir, VipsRect *pos )
  150 {
  151     VipsRect ovl;
  152 
  153     /* Does any of the sub-image appear in the area we have been asked
  154      * to make?
  155      */
  156     vips_rect_intersectrect( &or->valid, pos, &ovl );
  157     if( !vips_rect_isempty( &ovl ) ) {
  158         /* Find the part of in we need.
  159          */
  160         ovl.left -= pos->left;
  161         ovl.top -= pos->top;
  162 
  163         /* Paint this area of pixels into or.
  164          */
  165         if( vips_region_prepare_to( ir, or, &ovl, 
  166             ovl.left + pos->left, ovl.top + pos->top ) )
  167             return( -1 );
  168     }
  169 
  170     return( 0 );
  171 }
  172 
  173 static int
  174 vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
  175 {
  176     VipsRegion **ir = (VipsRegion **) seq;
  177     VipsRect *r = &or->valid;
  178     VipsInsert *insert = (VipsInsert *) b; 
  179     VipsConversion *conversion = VIPS_CONVERSION( insert );
  180 
  181     int i;
  182 
  183     /* Three cases:
  184      *
  185      * 1. If r is entirely within sub, we can just paint from sub.
  186      * 2. If r is entirely within main and does not touch sub, we can 
  187      *    paint from main.
  188      * 3. We must paint from both, and the background.
  189      */
  190     if( vips_rect_includesrect( &insert->rimage[1], r ) ) {
  191         /* Just the subimage.
  192          */
  193         if( vips__insert_just_one( or, ir[1],
  194             insert->rimage[1].left, insert->rimage[1].top ) )
  195             return( -1 );
  196     }
  197     else if( vips_rect_includesrect( &insert->rimage[0], r ) &&
  198         !vips_rect_overlapsrect( &insert->rimage[1], r ) ) {
  199         /* Just the main image.
  200          */
  201         if( vips__insert_just_one( or, ir[0],
  202             insert->rimage[0].left, insert->rimage[0].top ) )
  203             return( -1 );
  204     }
  205     else {
  206         /* Output requires both (or neither) input. If it is not 
  207          * entirely inside both the main and the sub, then there is 
  208          * going to be some background. 
  209          */
  210         vips_region_paint_pel( or, r, insert->ink );
  211 
  212         /* Paste the background first.
  213          */
  214         for( i = 0; i < 2; i++ ) 
  215             if( vips__insert_paste_region( or, ir[i], 
  216                 &insert->rimage[i] ) )
  217                 return( -1 );
  218     }
  219 
  220     /* See arrayjoin for almost this code again. Move into conversion.c?
  221      */
  222     if( vips_image_is_sequential( conversion->out ) )
  223         for( i = 0; i < 2; i++ ) {
  224             int bottom_edge = 
  225                 VIPS_RECT_BOTTOM( &insert->rimage[i] );
  226 
  227             /* 1024 is a generous margin. 256 is too small.
  228              */
  229             if( !insert->minimised[i] &&
  230                 r->top > bottom_edge + 1024 ) {
  231                 insert->minimised[i] = TRUE;
  232                 vips_image_minimise_all( insert->processed[i] );
  233             }
  234         }
  235 
  236     return( 0 );
  237 }
  238 
  239 /* Make a pair of vector constants into a set of formatted pixels. bands can
  240  * be 3 while n is 1, meaning expand the constant to the number of bands. 
  241  * imag can be NULL, meaning all zero for the imaginary component.
  242  */
  243 VipsPel *
  244 vips__vector_to_pels( const char *domain, 
  245     int bands, VipsBandFormat format, VipsCoding coding, 
  246     double *real, double *imag, int n )
  247 {
  248     /* Run our pipeline relative to this.
  249      */
  250     VipsImage *context = vips_image_new(); 
  251 
  252     VipsImage **t = (VipsImage **) 
  253         vips_object_local_array( VIPS_OBJECT( context ), 8 );
  254 
  255     VipsImage *in;
  256     double *ones;
  257     VipsPel *result;
  258     int i;
  259 
  260 #ifdef VIPS_DEBUG
  261     printf( "vips__vector_to_pels: starting\n" );
  262 #endif /*VIPS_DEBUG*/
  263 
  264     ones = VIPS_ARRAY( context, n, double );
  265     for( i = 0; i < n; i++ )
  266         ones[i] = 1.0;
  267 
  268     /* Make the real and imaginary parts.
  269      */
  270     if( vips_black( &t[0], 1, 1, "bands", bands, NULL ) ||
  271         vips_linear( t[0], &t[1], ones, real, n, NULL ) ) {
  272         g_object_unref( context );
  273         return( NULL );
  274     }
  275     in = t[1];
  276 
  277     if( imag ) { 
  278         if( vips_black( &t[2], 1, 1, "bands", bands, NULL ) ||
  279             vips_linear( t[2], &t[3], ones, imag, n, NULL ) ||
  280             vips_complexform( in, t[3], &t[4], NULL ) ) {
  281             g_object_unref( context );
  282             return( NULL );
  283         }
  284         in = t[4];
  285     }
  286 
  287     /* Cast to the output type and coding. 
  288      */
  289     if( vips_cast( in, &t[5], format, NULL ) ||
  290         vips_image_encode( t[5], &t[6], coding ) ) {
  291         g_object_unref( context );
  292         return( NULL );
  293     }
  294     in = t[6];
  295 
  296     /* Write to memory, copy to output buffer. 
  297      */
  298     vips_image_set_int( in, "hide-progress", 1 );
  299     if( !(t[7] = vips_image_new_memory()) ||
  300         vips_image_write( in, t[7] ) ) {
  301         g_object_unref( context );
  302         return( NULL );
  303     }
  304     in = t[7];
  305 
  306     if( !(result = 
  307         VIPS_ARRAY( NULL, VIPS_IMAGE_SIZEOF_PEL( in ), VipsPel )) ) {
  308         g_object_unref( context );
  309         return( NULL );
  310     }
  311 
  312     memcpy( result, in->data, VIPS_IMAGE_SIZEOF_PEL( in ) ); 
  313 
  314 #ifdef VIPS_DEBUG
  315 {
  316     int i;
  317 
  318     printf( "vips__vector_to_ink:\n" );
  319     printf( "\t(real, imag) = " ); 
  320     for( i = 0; i < n; i++ )
  321         printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 );
  322     printf( "\n" ); 
  323     printf( "\tink = " ); 
  324     for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( in ); i++ )
  325         printf( "%d ", result[i] );
  326     printf( "\n" ); 
  327 }
  328 #endif /*VIPS_DEBUG*/
  329 
  330     g_object_unref( context );
  331 
  332     return( result ); 
  333 }
  334 
  335 static void
  336 vips__vector_to_ink_cb( VipsObject *object, char *buf )
  337 {
  338     g_free( buf );
  339 }
  340 
  341 /* Calculate a pixel for an image from a vec of double. Valid while im is
  342  * valid. 
  343  */
  344 VipsPel *
  345 vips__vector_to_ink( const char *domain, 
  346     VipsImage *im, double *real, double *imag, int n )
  347 {
  348     int bands; 
  349     VipsBandFormat format;
  350     VipsPel *result;
  351 
  352     vips_image_decode_predict( im, &bands, &format );
  353 
  354     if( !(result = vips__vector_to_pels( domain, 
  355         bands, format, im->Coding, real, imag, n )) )
  356         return( NULL );
  357 
  358     g_signal_connect( im, "postclose", 
  359         G_CALLBACK( vips__vector_to_ink_cb ), result );
  360 
  361     return( result ); 
  362 }
  363 
  364 static int
  365 vips_insert_build( VipsObject *object )
  366 {
  367     VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
  368     VipsConversion *conversion = VIPS_CONVERSION( object );
  369     VipsInsert *insert = (VipsInsert *) object;
  370     VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 );
  371 
  372     if( VIPS_OBJECT_CLASS( vips_insert_parent_class )->build( object ) )
  373         return( -1 );
  374 
  375     if( vips_image_pio_input( insert->main ) || 
  376         vips_image_pio_input( insert->sub ) || 
  377         vips_check_bands_1orn( class->nickname, 
  378             insert->main, insert->sub ) ||
  379         vips_check_coding_known( class->nickname, insert->main ) ||
  380         vips_check_coding_same( class->nickname, 
  381             insert->main, insert->sub ) )
  382         return( -1 );
  383 
  384     /* Cast our input images up to a common format and bands.
  385      */
  386     if( vips__formatalike( insert->main, insert->sub, &t[0], &t[1] ) ||
  387         vips__bandalike( class->nickname, t[0], t[1], &t[2], &t[3] ) )
  388         return( -1 );
  389     insert->processed[0] = t[2];
  390     insert->processed[1] = t[3];
  391 
  392     /* Joins can get very wide (eg. consider joining a set of tiles
  393      * horizontally to make a large image), we don't want mem use to shoot
  394      * up. SMALLTILE will guarantee we keep small and local.
  395      */
  396     if( vips_image_pipeline_array( conversion->out, 
  397         VIPS_DEMAND_STYLE_SMALLTILE, insert->processed ) )
  398         return( -1 );
  399 
  400     /* Calculate geometry. 
  401      */
  402     insert->rimage[0].left = 0;
  403     insert->rimage[0].top = 0;
  404     insert->rimage[0].width = insert->processed[0]->Xsize;
  405     insert->rimage[0].height = insert->processed[0]->Ysize;
  406 
  407     insert->rimage[1].left = insert->x;
  408     insert->rimage[1].top = insert->y;
  409     insert->rimage[1].width = insert->processed[1]->Xsize;
  410     insert->rimage[1].height = insert->processed[1]->Ysize;
  411 
  412     if( insert->expand ) {
  413         /* Expand output to bounding box of these two.
  414          */
  415         vips_rect_unionrect( &insert->rimage[0], &insert->rimage[1], 
  416             &insert->rout );
  417 
  418         /* Translate origin to top LH corner of rout.
  419          */
  420         insert->rimage[0].left -= insert->rout.left;
  421         insert->rimage[0].top -= insert->rout.top;
  422         insert->rimage[1].left -= insert->rout.left;
  423         insert->rimage[1].top -= insert->rout.top;
  424         insert->rout.left = 0;
  425         insert->rout.top = 0;
  426     }
  427     else 
  428         insert->rout = insert->rimage[0];
  429 
  430     conversion->out->Xsize = insert->rout.width;
  431     conversion->out->Ysize = insert->rout.height;
  432 
  433     if( !(insert->ink = vips__vector_to_ink( 
  434         class->nickname, conversion->out,
  435         (double *) VIPS_ARRAY_ADDR( insert->background, 0 ), NULL, 
  436         VIPS_AREA( insert->background )->n )) )
  437         return( -1 );
  438 
  439     if( vips_image_generate( conversion->out,
  440         vips_start_many, vips_insert_gen, vips_stop_many, 
  441         insert->processed, insert ) )
  442         return( -1 );
  443 
  444     return( 0 );
  445 }
  446 
  447 static void
  448 vips_insert_class_init( VipsInsertClass *class )
  449 {
  450     GObjectClass *gobject_class = G_OBJECT_CLASS( class );
  451     VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
  452     VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
  453 
  454     VIPS_DEBUG_MSG( "vips_insert_class_init\n" );
  455 
  456     gobject_class->set_property = vips_object_set_property;
  457     gobject_class->get_property = vips_object_get_property;
  458 
  459     vobject_class->nickname = "insert";
  460     vobject_class->description = 
  461         _( "insert image @sub into @main at @x, @y" );
  462     vobject_class->build = vips_insert_build;
  463 
  464     operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
  465 
  466     VIPS_ARG_IMAGE( class, "main", 0, 
  467         _( "Main" ), 
  468         _( "Main input image" ),
  469         VIPS_ARGUMENT_REQUIRED_INPUT,
  470         G_STRUCT_OFFSET( VipsInsert, main ) );
  471 
  472     VIPS_ARG_IMAGE( class, "sub", 1, 
  473         _( "Sub-image" ), 
  474         _( "Sub-image to insert into main image" ),
  475         VIPS_ARGUMENT_REQUIRED_INPUT,
  476         G_STRUCT_OFFSET( VipsInsert, sub ) );
  477 
  478     VIPS_ARG_INT( class, "x", 3, 
  479         _( "X" ), 
  480         _( "Left edge of sub in main" ),
  481         VIPS_ARGUMENT_REQUIRED_INPUT,
  482         G_STRUCT_OFFSET( VipsInsert, x ),
  483         -VIPS_MAX_COORD, VIPS_MAX_COORD, 0 );
  484 
  485     VIPS_ARG_INT( class, "y", 4, 
  486         _( "Y" ), 
  487         _( "Top edge of sub in main" ),
  488         VIPS_ARGUMENT_REQUIRED_INPUT,
  489         G_STRUCT_OFFSET( VipsInsert, y ),
  490         -VIPS_MAX_COORD, VIPS_MAX_COORD, 0 );
  491 
  492     VIPS_ARG_BOOL( class, "expand", 5, 
  493         _( "Expand" ), 
  494         _( "Expand output to hold all of both inputs" ),
  495         VIPS_ARGUMENT_OPTIONAL_INPUT,
  496         G_STRUCT_OFFSET( VipsInsert, expand ),
  497         FALSE );
  498 
  499     VIPS_ARG_BOXED( class, "background", 6, 
  500         _( "Background" ), 
  501         _( "Color for new pixels" ),
  502         VIPS_ARGUMENT_OPTIONAL_INPUT,
  503         G_STRUCT_OFFSET( VipsInsert, background ),
  504         VIPS_TYPE_ARRAY_DOUBLE );
  505 }
  506 
  507 static void
  508 vips_insert_init( VipsInsert *insert )
  509 {
  510     /* Init our instance fields.
  511      */
  512     insert->background = vips_array_double_newv( 1, 0.0 );
  513 }
  514 
  515 /**
  516  * vips_insert: (method)
  517  * @main: big image
  518  * @sub: small image
  519  * @out: (out): output image
  520  * @x: left position of @sub
  521  * @y: top position of @sub
  522  * @...: %NULL-terminated list of optional named arguments
  523  *
  524  * Optional arguments:
  525  *
  526  * * @expand: expand output to hold whole of both images
  527  * * @background: colour for new pixels
  528  *
  529  * Insert @sub into @main at position @x, @y. 
  530  *
  531  * Normally @out shows the whole of @main. If @expand is #TRUE then @out is
  532  * made large enough to hold all of @main and @sub. 
  533  * Any areas of @out not coming from
  534  * either @main or @sub are set to @background (default 0). 
  535  *
  536  * If @sub overlaps @main,
  537  * @sub will appear on top of @main. 
  538  *
  539  * If the number of bands differs, one of the images 
  540  * must have one band. In this case, an n-band image is formed from the 
  541  * one-band image by joining n copies of the one-band image together, and then
  542  * the two n-band images are operated upon.
  543  *
  544  * The two input images are cast up to the smallest common type (see table 
  545  * Smallest common format in 
  546  * <link linkend="libvips-arithmetic">arithmetic</link>).
  547  *
  548  * See also: vips_join(), vips_embed(), vips_extract_area().
  549  *
  550  * Returns: 0 on success, -1 on error
  551  */
  552 int
  553 vips_insert( VipsImage *main, VipsImage *sub, VipsImage **out, 
  554     int x, int y, ... )
  555 {
  556     va_list ap;
  557     int result;
  558 
  559     va_start( ap, y );
  560     result = vips_call_split( "insert", ap, main, sub, out, x, y );
  561     va_end( ap );
  562 
  563     return( result );
  564 }