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