1 /* replicate an image x times horizontally and vertically
2  *
3  * JC, 30 sep 03
4  *
5  * 15/4/04
6  *	- some optimisations for some cases
7  * 1/2/10
8  * 	- gtkdoc
9  * 26/10/11
10  * 	- redone as a class
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 /*
41 #define VIPS_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 <string.h>
51 #include <stdlib.h>
52 
53 #include <vips/vips.h>
54 #include <vips/internal.h>
55 #include <vips/debug.h>
56 
57 #include "pconversion.h"
58 
59 typedef struct _VipsReplicate {
60 	VipsConversion parent_instance;
61 
62 	/* The input image.
63 	 */
64 	VipsImage *in;
65 
66 	int across;
67 	int down;
68 
69 } VipsReplicate;
70 
71 typedef VipsConversionClass VipsReplicateClass;
72 
73 G_DEFINE_TYPE( VipsReplicate, vips_replicate, VIPS_TYPE_CONVERSION );
74 
75 static int
vips_replicate_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)76 vips_replicate_gen( VipsRegion *or, void *seq, void *a, void *b,
77 	gboolean *stop )
78 {
79 	VipsRegion *ir = (VipsRegion *) seq;
80 	VipsImage *in = (VipsImage *) a;
81 	VipsRect *r = &or->valid;
82 	int twidth = in->Xsize;
83 	int theight = in->Ysize;
84 
85 	int x, y;
86 	VipsRect tile;
87 
88 	/* Find top left of tiles we need.
89 	 */
90 	int xs = (r->left / twidth) * twidth;
91 	int ys = (r->top / theight) * theight;
92 
93 	/* The tile enclosing the top-left corner of the requested area.
94 	 */
95 	tile.left = xs;
96 	tile.top = ys;
97 	tile.width = twidth;
98 	tile.height = theight;
99 
100 	/* If the request fits inside a single tile, we can just pointer-copy.
101 	 */
102 	if( vips_rect_includesrect( &tile, r ) ) {
103 		VipsRect irect;
104 
105 		/* Translate request to input space.
106 		 */
107 		irect = *r;
108 		irect.left -= xs;
109 		irect.top -= ys;
110 		if( vips_region_prepare( ir, &irect ) )
111 			return( -1 );
112 
113 		if( vips_region_region( or, ir, r, irect.left, irect.top ) )
114 			return( -1 );
115 
116 		return( 0 );
117 	}
118 
119 	for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += theight )
120 		for( x = xs; x < VIPS_RECT_RIGHT( r ); x += twidth ) {
121 			VipsRect paint;
122 
123 			/* Whole tile at x, y
124 			 */
125 			tile.left = x;
126 			tile.top = y;
127 			tile.width = twidth;
128 			tile.height = theight;
129 
130 			/* Which parts touch the area of the output we are
131 			 * building.
132 			 */
133 			vips_rect_intersectrect( &tile, r, &paint );
134 
135 			/* Translate back to ir coordinates.
136 			 */
137 			paint.left -= x;
138 			paint.top -= y;
139 
140 			g_assert( !vips_rect_isempty( &paint ) );
141 
142 			/* Render into or.
143 			 */
144 			if( vips_region_prepare_to( ir, or, &paint,
145 				paint.left + x,
146 				paint.top + y ) )
147 				return( -1 );
148 		}
149 
150 	return( 0 );
151 }
152 
153 static int
vips_replicate_build(VipsObject * object)154 vips_replicate_build( VipsObject *object )
155 {
156 	VipsConversion *conversion = VIPS_CONVERSION( object );
157 	VipsReplicate *replicate = (VipsReplicate *) object;
158 
159 	if( VIPS_OBJECT_CLASS( vips_replicate_parent_class )->build( object ) )
160 		return( -1 );
161 
162 	if( vips_image_pio_input( replicate->in ) )
163 		return( -1 );
164 
165 	if( vips_image_pipelinev( conversion->out,
166 		VIPS_DEMAND_STYLE_SMALLTILE, replicate->in, NULL ) )
167 		return( -1 );
168 
169 	conversion->out->Xsize *= replicate->across;
170 	conversion->out->Ysize *= replicate->down;
171 
172 	if( vips_image_generate( conversion->out,
173 		vips_start_one, vips_replicate_gen, vips_stop_one,
174 		replicate->in, replicate ) )
175 		return( -1 );
176 
177 	return( 0 );
178 }
179 
180 static void
vips_replicate_class_init(VipsReplicateClass * class)181 vips_replicate_class_init( VipsReplicateClass *class )
182 {
183 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
184 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
185 
186 	VIPS_DEBUG_MSG( "vips_replicate_class_init\n" );
187 
188 	gobject_class->set_property = vips_object_set_property;
189 	gobject_class->get_property = vips_object_get_property;
190 
191 	vobject_class->nickname = "replicate";
192 	vobject_class->description = _( "replicate an image" );
193 	vobject_class->build = vips_replicate_build;
194 
195 	VIPS_ARG_IMAGE( class, "in", 0,
196 		_( "Input" ),
197 		_( "Input image" ),
198 		VIPS_ARGUMENT_REQUIRED_INPUT,
199 		G_STRUCT_OFFSET( VipsReplicate, in ) );
200 
201 	VIPS_ARG_INT( class, "across", 4,
202 		_( "Across" ),
203 		_( "Repeat this many times horizontally" ),
204 		VIPS_ARGUMENT_REQUIRED_INPUT,
205 		G_STRUCT_OFFSET( VipsReplicate, across ),
206 		1, 1000000, 1 );
207 
208 	VIPS_ARG_INT( class, "down", 5,
209 		_( "Down" ),
210 		_( "Repeat this many times vertically" ),
211 		VIPS_ARGUMENT_REQUIRED_INPUT,
212 		G_STRUCT_OFFSET( VipsReplicate, down ),
213 		1, 1000000, 1 );
214 
215 }
216 
217 static void
vips_replicate_init(VipsReplicate * replicate)218 vips_replicate_init( VipsReplicate *replicate )
219 {
220 }
221 
222 /**
223  * vips_replicate: (method)
224  * @in: input image
225  * @out: (out): output image
226  * @across: repeat input this many times across
227  * @down: repeat input this many times down
228  * @...: %NULL-terminated list of optional named arguments
229  *
230  * Repeats an image many times.
231  *
232  * See also: vips_extract_area().
233  *
234  * Returns: 0 on success, -1 on error
235  */
236 int
vips_replicate(VipsImage * in,VipsImage ** out,int across,int down,...)237 vips_replicate( VipsImage *in, VipsImage **out, int across, int down, ... )
238 {
239 	va_list ap;
240 	int result;
241 
242 	va_start( ap, down );
243 	result = vips_call_split( "replicate", ap, in, out, across, down );
244 	va_end( ap );
245 
246 	return( result );
247 }
248