1 /* Use one mosiaced file to mosaic another set of images.
2  *
3  * 1/11/01 JC
4  *	- from global_balance
5  * 25/02/02 JC
6  *	- detect size change
7  * 10/4/06
8  * 	- spot file-not-found
9  * 18/6/20 kleisauke
10  * 	- convert to vips8
11  */
12 
13 /*
14 
15     This file is part of VIPS.
16 
17     VIPS is free software; you can redistribute it and/or modify
18     it under the terms of the GNU Lesser General Public License as published by
19     the Free Software Foundation; either version 2 of the License, or
20     (at your option) any later version.
21 
22     This program is distributed in the hope that it will be useful,
23     but WITHOUT ANY WARRANTY; without even the implied warranty of
24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25     GNU Lesser General Public License for more details.
26 
27     You should have received a copy of the GNU Lesser General Public License
28     along with this program; if not, write to the Free Software
29     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30     02110-1301  USA
31 
32  */
33 
34 /*
35 
36     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
37 
38  */
39 
40 /* Define for debug output.
41 #define DEBUG
42  */
43 
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif /*HAVE_CONFIG_H*/
47 #include <vips/intl.h>
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <math.h>
54 
55 #include <vips/vips.h>
56 #include <vips/transform.h>
57 
58 #include "pmosaicing.h"
59 #include "global_balance.h"
60 
61 typedef struct {
62 	VipsOperation parent_instance;
63 
64 	VipsImage *in;
65 	VipsImage *out;
66 	char *old_str;
67 	char *new_str;
68 
69 	int new_len;
70 	int old_len;
71 
72 } VipsRemosaic;
73 
74 typedef VipsOperationClass VipsRemosaicClass;
75 
76 G_DEFINE_TYPE( VipsRemosaic, vips_remosaic, VIPS_TYPE_OPERATION );
77 
78 static VipsImage *
remosaic_fn(JoinNode * node,VipsRemosaic * remosaic)79 remosaic_fn( JoinNode *node, VipsRemosaic *remosaic )
80 {
81 	SymbolTable *st = node->st;
82 	VipsImage *im = node->im;
83 
84 	VipsImage *out;
85 	char filename[FILENAME_MAX];
86 	char *p;
87 
88 	if( !im ) {
89 		vips_error( "vips_remosaic", _( "file \"%s\" not found" ),
90 			node->name );
91 		return( NULL );
92 	}
93 
94 	/* Remove substring remosaic->old_str from in->filename, replace with
95 	 * remosaic->new_str.
96 	 */
97 	vips_strncpy( filename, im->filename, FILENAME_MAX );
98 	if( (p = vips_strrstr( filename, remosaic->old_str )) ) {
99 		int offset = p - &filename[0];
100 
101 		vips_strncpy( p, remosaic->new_str, FILENAME_MAX - offset );
102 		vips_strncpy( p + remosaic->new_len,
103 			im->filename + offset + remosaic->old_len,
104 			FILENAME_MAX - offset - remosaic->new_len );
105 	}
106 
107 #ifdef DEBUG
108 	printf( "vips_remosaic: filename \"%s\" -> \"%s\"\n",
109 		im->filename, filename );
110 #endif /*DEBUG*/
111 
112 	if( !(out = vips__global_open_image( st, filename )) )
113 		return( NULL );
114 
115 	if( out->Xsize != im->Xsize || out->Ysize != im->Ysize ) {
116 		vips_error( "vips_remosaic",
117 			_( "substitute image \"%s\" is not "
118 				"the same size as \"%s\"" ),
119 			filename, im->filename );
120 		return( NULL );
121 	}
122 
123 	return( out );
124 }
125 
126 static int
vips_remosaic_build(VipsObject * object)127 vips_remosaic_build( VipsObject *object )
128 {
129 	VipsRemosaic *remosaic = (VipsRemosaic *) object;
130 
131 	SymbolTable *st;
132 
133 	g_object_set( remosaic, "out", vips_image_new(), NULL );
134 
135 	if( VIPS_OBJECT_CLASS( vips_remosaic_parent_class )->
136 		build( object ) )
137 		return( -1 );
138 
139 	if( !(st = vips__build_symtab( remosaic->out, SYM_TAB_SIZE )) ||
140 		vips__parse_desc( st, remosaic->in ) )
141 		return( -1 );
142 
143 	remosaic->old_len = strlen( remosaic->old_str );
144 	remosaic->new_len = strlen( remosaic->new_str );
145 	if( vips__build_mosaic( st, remosaic->out,
146 		(transform_fn) remosaic_fn, remosaic ) )
147 		return( -1 );
148 
149 	return( 0 );
150 }
151 
152 static void
vips_remosaic_class_init(VipsRemosaicClass * class)153 vips_remosaic_class_init( VipsRemosaicClass *class )
154 {
155 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
156 	VipsObjectClass *object_class = (VipsObjectClass *) class;
157 
158 	gobject_class->set_property = vips_object_set_property;
159 	gobject_class->get_property = vips_object_get_property;
160 
161 	object_class->nickname = "remosaic";
162 	object_class->description = _( "rebuild an mosaiced image" );
163 	object_class->build = vips_remosaic_build;
164 
165 	VIPS_ARG_IMAGE( class, "in", 1,
166 		_( "Input" ),
167 		_( "Input image" ),
168 		VIPS_ARGUMENT_REQUIRED_INPUT,
169 		G_STRUCT_OFFSET( VipsRemosaic, in ) );
170 
171 	VIPS_ARG_IMAGE( class, "out", 2,
172 		_( "Output" ),
173 		_( "Output image" ),
174 		VIPS_ARGUMENT_REQUIRED_OUTPUT,
175 		G_STRUCT_OFFSET( VipsRemosaic, out ) );
176 
177 	VIPS_ARG_STRING( class, "old_str", 5,
178 		_( "old_str" ),
179 		_( "Search for this string" ),
180 		VIPS_ARGUMENT_REQUIRED_INPUT,
181 		G_STRUCT_OFFSET( VipsRemosaic, old_str ),
182 		"" );
183 
184 	VIPS_ARG_STRING( class, "new_str", 6,
185 		_( "new_str" ),
186 		_( "And swap for this string" ),
187 		VIPS_ARGUMENT_REQUIRED_INPUT,
188 		G_STRUCT_OFFSET( VipsRemosaic, new_str ),
189 		"" );
190 
191 }
192 
193 static void
vips_remosaic_init(VipsRemosaic * remosaic)194 vips_remosaic_init( VipsRemosaic *remosaic )
195 {
196 }
197 
198 /**
199  * vips_remosaic: (method)
200  * @in: mosaic to rebuild
201  * @out: (out): output image
202  * @old_str: gamma of source images
203  * @new_str: gamma of source images
204  * @...: %NULL-terminated list of optional named arguments
205  *
206  * vips_remosaic() works rather as vips_globalbalance(). It takes apart the
207  * mosaiced image @in and rebuilds it, substituting images.
208  *
209  * Unlike vips_globalbalance(), images are substituted based on their file‐
210  * names.  The  rightmost  occurrence  of the string @old_str is swapped
211  * for @new_str, that file is opened, and that image substituted  for
212  * the old image.
213  *
214  * It's convenient for multispectral images. You can mosaic one band, then
215  * use that mosaic as a template for mosaicing the others automatically.
216  *
217  * See also: vips_globalbalance().
218  *
219  * Returns: 0 on success, -1 on error
220  */
221 int
vips_remosaic(VipsImage * in,VipsImage ** out,const char * old_str,const char * new_str,...)222 vips_remosaic( VipsImage *in, VipsImage **out,
223 	const char *old_str, const char *new_str, ... )
224 {
225 	va_list ap;
226 	int result;
227 
228 	va_start( ap, new_str );
229 	result = vips_call_split( "remosaic", ap, in, out, old_str, new_str );
230 	va_end( ap );
231 
232 	return( result );
233 }
234