/src/libvips/libvips/conversion/extract.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* extract an area and/or a set of bands |
2 | | * |
3 | | * Copyright: 1990, J. Cupitt |
4 | | * |
5 | | * Author: J. Cupitt |
6 | | * Written on: 12/02/1990 |
7 | | * Modified on: 4/6/92, J.Cupitt |
8 | | * - speed up! why wasn't this done before? Why am I stupid? |
9 | | * - layout, messages fixed |
10 | | * now extracts IM_CODING_LABQ to IM_CODING_LABQ file: K.Martinez 1/7/93 |
11 | | * 2/7/93 JC |
12 | | * - adapted for partial v2 |
13 | | * - ANSIfied |
14 | | * 7/7/93 JC |
15 | | * - behaviour for IM_CODING_LABQ fixed |
16 | | * - better messages |
17 | | * 7/10/94 JC |
18 | | * - new IM_NEW() |
19 | | * 22/2/95 JC |
20 | | * - new use of im_region_region() |
21 | | * 6/7/98 JC |
22 | | * - im_extract_area() and im_extract_band() added |
23 | | * 11/7/01 JC |
24 | | * - im_extract_band() now numbers from zero |
25 | | * 7/11/01 JC |
26 | | * - oh what pain, im_extract now numbers bands from zero as well |
27 | | * 6/9/02 JC |
28 | | * - zero xoff/yoff for extracted area |
29 | | * 14/4/04 JC |
30 | | * - nope, -ve the origin |
31 | | * 17/7/04 |
32 | | * - added im_extract_bands(), remove many bands from image |
33 | | * 24/3/09 |
34 | | * - added IM_CODING_RAD support |
35 | | * 29/1/10 |
36 | | * - cleanups |
37 | | * - gtkdoc |
38 | | * 26/10/11 |
39 | | * - redone as a class |
40 | | */ |
41 | | |
42 | | /* |
43 | | |
44 | | This file is part of VIPS. |
45 | | |
46 | | VIPS is free software; you can redistribute it and/or modify |
47 | | it under the terms of the GNU Lesser General Public License as published by |
48 | | the Free Software Foundation; either version 2 of the License, or |
49 | | (at your option) any later version. |
50 | | |
51 | | This program is distributed in the hope that it will be useful, |
52 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
53 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
54 | | GNU Lesser General Public License for more details. |
55 | | |
56 | | You should have received a copy of the GNU Lesser General Public License |
57 | | along with this program; if not, write to the Free Software |
58 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
59 | | 02110-1301 USA |
60 | | |
61 | | */ |
62 | | |
63 | | /* |
64 | | |
65 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
66 | | |
67 | | */ |
68 | | |
69 | | /* |
70 | | #define VIPS_DEBUG |
71 | | */ |
72 | | |
73 | | #ifdef HAVE_CONFIG_H |
74 | | #include <config.h> |
75 | | #endif /*HAVE_CONFIG_H*/ |
76 | | #include <glib/gi18n-lib.h> |
77 | | |
78 | | #include <stdio.h> |
79 | | #include <string.h> |
80 | | #include <stdlib.h> |
81 | | |
82 | | #include <vips/vips.h> |
83 | | #include <vips/internal.h> |
84 | | #include <vips/debug.h> |
85 | | |
86 | | #include "pconversion.h" |
87 | | |
88 | | #include "bandary.h" |
89 | | |
90 | | typedef struct _VipsExtractArea { |
91 | | VipsConversion parent_instance; |
92 | | |
93 | | /* The input image. |
94 | | */ |
95 | | VipsImage *in; |
96 | | |
97 | | int left; |
98 | | int top; |
99 | | int width; |
100 | | int height; |
101 | | |
102 | | } VipsExtractArea; |
103 | | |
104 | | typedef VipsConversionClass VipsExtractAreaClass; |
105 | | |
106 | | G_DEFINE_TYPE(VipsExtractArea, vips_extract_area, VIPS_TYPE_CONVERSION); |
107 | | |
108 | | /* Extract an area. Can just use pointers. |
109 | | */ |
110 | | static int |
111 | | vips_extract_area_gen(VipsRegion *out_region, |
112 | | void *seq, void *a, void *b, gboolean *stop) |
113 | 151k | { |
114 | 151k | VipsRegion *ir = (VipsRegion *) seq; |
115 | 151k | VipsExtractArea *extract = (VipsExtractArea *) b; |
116 | 151k | VipsRect iarea; |
117 | | |
118 | | /* Ask for input we need. Translate from demand in or's space to |
119 | | * demand in ir's space. |
120 | | */ |
121 | 151k | iarea = out_region->valid; |
122 | 151k | iarea.left += extract->left; |
123 | 151k | iarea.top += extract->top; |
124 | 151k | if (vips_region_prepare(ir, &iarea)) |
125 | 14.1k | return -1; |
126 | | |
127 | | /* Attach or to ir. |
128 | | */ |
129 | 137k | if (vips_region_region(out_region, ir, |
130 | 137k | &out_region->valid, iarea.left, iarea.top)) |
131 | 0 | return -1; |
132 | | |
133 | 137k | return 0; |
134 | 137k | } |
135 | | |
136 | | static int |
137 | | vips_extract_area_build(VipsObject *object) |
138 | 51.3k | { |
139 | 51.3k | VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); |
140 | 51.3k | VipsConversion *conversion = VIPS_CONVERSION(object); |
141 | 51.3k | VipsExtractArea *extract = (VipsExtractArea *) object; |
142 | | |
143 | 51.3k | if (VIPS_OBJECT_CLASS(vips_extract_area_parent_class)->build(object)) |
144 | 0 | return -1; |
145 | | |
146 | 51.3k | if (extract->left + extract->width > extract->in->Xsize || |
147 | 51.3k | extract->top + extract->height > extract->in->Ysize || |
148 | 51.3k | extract->left < 0 || extract->top < 0 || |
149 | 51.3k | extract->width <= 0 || extract->height <= 0) { |
150 | 0 | vips_error(class->nickname, "%s", _("bad extract area")); |
151 | 0 | return -1; |
152 | 0 | } |
153 | | |
154 | 51.3k | if (vips_image_pio_input(extract->in) || |
155 | 51.3k | vips_check_coding_known(class->nickname, extract->in)) |
156 | 0 | return -1; |
157 | | |
158 | 51.3k | if (vips_image_pipelinev(conversion->out, |
159 | 51.3k | VIPS_DEMAND_STYLE_THINSTRIP, extract->in, NULL)) |
160 | 0 | return -1; |
161 | | |
162 | 51.3k | conversion->out->Xsize = extract->width; |
163 | 51.3k | conversion->out->Ysize = extract->height; |
164 | 51.3k | conversion->out->Xoffset = -extract->left; |
165 | 51.3k | conversion->out->Yoffset = -extract->top; |
166 | | |
167 | 51.3k | if (vips_image_generate(conversion->out, |
168 | 51.3k | vips_start_one, vips_extract_area_gen, vips_stop_one, |
169 | 51.3k | extract->in, extract)) |
170 | 0 | return -1; |
171 | | |
172 | 51.3k | return 0; |
173 | 51.3k | } |
174 | | |
175 | | static void |
176 | | vips_extract_area_class_init(VipsExtractAreaClass *class) |
177 | 32 | { |
178 | 32 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
179 | 32 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
180 | 32 | VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); |
181 | | |
182 | 32 | VIPS_DEBUG_MSG("vips_extract_area_class_init\n"); |
183 | | |
184 | 32 | gobject_class->set_property = vips_object_set_property; |
185 | 32 | gobject_class->get_property = vips_object_get_property; |
186 | | |
187 | 32 | vobject_class->nickname = "extract_area"; |
188 | 32 | vobject_class->description = _("extract an area from an image"); |
189 | 32 | vobject_class->build = vips_extract_area_build; |
190 | | |
191 | 32 | operation_class->flags = VIPS_OPERATION_SEQUENTIAL; |
192 | | |
193 | 32 | VIPS_ARG_IMAGE(class, "input", 1, |
194 | 32 | _("Input"), |
195 | 32 | _("Input image"), |
196 | 32 | VIPS_ARGUMENT_REQUIRED_INPUT, |
197 | 32 | G_STRUCT_OFFSET(VipsExtractArea, in)); |
198 | | |
199 | 32 | VIPS_ARG_INT(class, "left", 3, |
200 | 32 | _("Left"), |
201 | 32 | _("Left edge of extract area"), |
202 | 32 | VIPS_ARGUMENT_REQUIRED_INPUT, |
203 | 32 | G_STRUCT_OFFSET(VipsExtractArea, left), |
204 | 32 | -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); |
205 | | |
206 | 32 | VIPS_ARG_INT(class, "top", 4, |
207 | 32 | _("Top"), |
208 | 32 | _("Top edge of extract area"), |
209 | 32 | VIPS_ARGUMENT_REQUIRED_INPUT, |
210 | 32 | G_STRUCT_OFFSET(VipsExtractArea, top), |
211 | 32 | -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); |
212 | | |
213 | 32 | VIPS_ARG_INT(class, "width", 5, |
214 | 32 | _("Width"), |
215 | 32 | _("Width of extract area"), |
216 | 32 | VIPS_ARGUMENT_REQUIRED_INPUT, |
217 | 32 | G_STRUCT_OFFSET(VipsExtractArea, width), |
218 | 32 | 1, VIPS_MAX_COORD, 1); |
219 | | |
220 | 32 | VIPS_ARG_INT(class, "height", 6, |
221 | 32 | _("Height"), |
222 | 32 | _("Height of extract area"), |
223 | 32 | VIPS_ARGUMENT_REQUIRED_INPUT, |
224 | 32 | G_STRUCT_OFFSET(VipsExtractArea, height), |
225 | 32 | 1, VIPS_MAX_COORD, 1); |
226 | 32 | } |
227 | | |
228 | | #ifdef __EMSCRIPTEN__ |
229 | | static void |
230 | | vips_crop_init_adapter(VipsExtractArea *extract, void *dummy) |
231 | | { |
232 | | vips_extract_area_init(extract); |
233 | | } |
234 | | #endif |
235 | | |
236 | | static void |
237 | | vips_extract_area_init(VipsExtractArea *extract) |
238 | 51.3k | { |
239 | 51.3k | } |
240 | | |
241 | | /** |
242 | | * vips_extract_area: (method) |
243 | | * @in: input image |
244 | | * @out: (out): output image |
245 | | * @left: left edge of area to extract |
246 | | * @top: top edge of area to extract |
247 | | * @width: width of area to extract |
248 | | * @height: height of area to extract |
249 | | * @...: %NULL-terminated list of optional named arguments |
250 | | * |
251 | | * Extract an area from an image. The area must fit within @in. |
252 | | * |
253 | | * See also: vips_extract_bands(), vips_smartcrop(). |
254 | | * |
255 | | * Returns: 0 on success, -1 on error. |
256 | | */ |
257 | | int |
258 | | vips_extract_area(VipsImage *in, VipsImage **out, |
259 | | int left, int top, int width, int height, ...) |
260 | 51.3k | { |
261 | 51.3k | va_list ap; |
262 | 51.3k | int result; |
263 | | |
264 | 51.3k | va_start(ap, height); |
265 | 51.3k | result = vips_call_split("extract_area", ap, in, out, |
266 | 51.3k | left, top, width, height); |
267 | 51.3k | va_end(ap); |
268 | | |
269 | 51.3k | return result; |
270 | 51.3k | } |
271 | | |
272 | | /* A synonym for extract_area. |
273 | | */ |
274 | | |
275 | | GType |
276 | | vips_crop_get_type(void) |
277 | 33 | { |
278 | 33 | static gsize gtype_id = 0; |
279 | | |
280 | 33 | if (g_once_init_enter(>ype_id)) { |
281 | 33 | GType new_type = g_type_register_static_simple(VIPS_TYPE_CONVERSION, |
282 | 33 | g_intern_static_string("crop"), |
283 | 33 | sizeof(VipsExtractAreaClass), |
284 | 33 | (GClassInitFunc) (void (*)(void)) vips_extract_area_class_intern_init, |
285 | 33 | sizeof(VipsExtractArea), |
286 | | #ifdef __EMSCRIPTEN__ |
287 | | (GInstanceInitFunc) vips_crop_init_adapter, |
288 | | #else |
289 | 33 | (GInstanceInitFunc) (void (*)(void)) vips_extract_area_init, |
290 | 33 | #endif |
291 | 33 | (GTypeFlags) 0); |
292 | | |
293 | 33 | g_once_init_leave(>ype_id, new_type); |
294 | 33 | } |
295 | | |
296 | 33 | return (GType) gtype_id; |
297 | 33 | } |
298 | | |
299 | | /** |
300 | | * vips_crop: (method) |
301 | | * @in: input image |
302 | | * @out: (out): output image |
303 | | * @left: left edge of area to extract |
304 | | * @top: top edge of area to extract |
305 | | * @width: width of area to extract |
306 | | * @height: height of area to extract |
307 | | * @...: %NULL-terminated list of optional named arguments |
308 | | * |
309 | | * A synonym for vips_extract_area(). |
310 | | * |
311 | | * See also: vips_extract_bands(), vips_smartcrop(). |
312 | | * |
313 | | * Returns: 0 on success, -1 on error. |
314 | | */ |
315 | | int |
316 | | vips_crop(VipsImage *in, VipsImage **out, |
317 | | int left, int top, int width, int height, ...) |
318 | 0 | { |
319 | 0 | va_list ap; |
320 | 0 | int result; |
321 | |
|
322 | 0 | va_start(ap, height); |
323 | 0 | result = vips_call_split("crop", ap, in, out, |
324 | 0 | left, top, width, height); |
325 | 0 | va_end(ap); |
326 | |
|
327 | 0 | return result; |
328 | 0 | } |
329 | | |
330 | | typedef struct _VipsExtractBand { |
331 | | VipsBandary parent_instance; |
332 | | |
333 | | /* The input image. |
334 | | */ |
335 | | VipsImage *in; |
336 | | |
337 | | int band; |
338 | | int n; |
339 | | } VipsExtractBand; |
340 | | |
341 | | typedef VipsBandaryClass VipsExtractBandClass; |
342 | | |
343 | | G_DEFINE_TYPE(VipsExtractBand, vips_extract_band, VIPS_TYPE_BANDARY); |
344 | | |
345 | | static void |
346 | | vips_extract_band_buffer(VipsBandarySequence *seq, |
347 | | VipsPel *out, VipsPel **in, int width) |
348 | 4.62M | { |
349 | 4.62M | VipsBandary *bandary = seq->bandary; |
350 | 4.62M | VipsConversion *conversion = (VipsConversion *) bandary; |
351 | 4.62M | VipsExtractBand *extract = (VipsExtractBand *) bandary; |
352 | 4.62M | VipsImage *im = bandary->ready[0]; |
353 | 4.62M | int es = VIPS_IMAGE_SIZEOF_ELEMENT(im); |
354 | 4.62M | int ips = VIPS_IMAGE_SIZEOF_PEL(im); |
355 | 4.62M | const int ops = VIPS_IMAGE_SIZEOF_PEL(conversion->out); |
356 | | |
357 | 4.62M | VipsPel *restrict p; |
358 | 4.62M | VipsPel *restrict q; |
359 | 4.62M | int x, z; |
360 | | |
361 | 4.62M | p = in[0] + extract->band * es; |
362 | 4.62M | q = out; |
363 | 4.62M | if (ops == 1) { |
364 | 39.4M | for (x = 0; x < width; x++) { |
365 | 38.9M | q[x] = p[0]; |
366 | 38.9M | p += ips; |
367 | 38.9M | } |
368 | 562k | } |
369 | 4.05M | else { |
370 | 186M | for (x = 0; x < width; x++) { |
371 | 1.06G | for (z = 0; z < ops; z++) |
372 | 880M | q[z] = p[z]; |
373 | | |
374 | 181M | p += ips; |
375 | 181M | q += ops; |
376 | 181M | } |
377 | 4.05M | } |
378 | 4.62M | } |
379 | | |
380 | | static int |
381 | | vips_extract_band_build(VipsObject *object) |
382 | 270k | { |
383 | 270k | VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); |
384 | 270k | VipsBandary *bandary = (VipsBandary *) object; |
385 | 270k | VipsExtractBand *extract = (VipsExtractBand *) object; |
386 | | |
387 | 270k | if (extract->in) { |
388 | 270k | int bands; |
389 | | |
390 | 270k | vips_image_decode_predict(extract->in, &bands, NULL); |
391 | | |
392 | 270k | bandary->n = 1; |
393 | 270k | bandary->in = &extract->in; |
394 | 270k | bandary->out_bands = extract->n; |
395 | | |
396 | 270k | if (extract->band + extract->n > bands) { |
397 | 0 | vips_error(class->nickname, |
398 | 0 | "%s", _("bad extract band")); |
399 | 0 | return -1; |
400 | 0 | } |
401 | | |
402 | 270k | if (extract->band == 0 && |
403 | 270k | extract->n == bands) |
404 | 15.7k | return vips_bandary_copy(bandary); |
405 | 270k | } |
406 | | |
407 | 254k | if (VIPS_OBJECT_CLASS(vips_extract_band_parent_class)->build(object)) |
408 | 0 | return -1; |
409 | | |
410 | 254k | return 0; |
411 | 254k | } |
412 | | |
413 | | static void |
414 | | vips_extract_band_class_init(VipsExtractBandClass *class) |
415 | 16 | { |
416 | 16 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
417 | 16 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
418 | 16 | VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); |
419 | | |
420 | 16 | VIPS_DEBUG_MSG("vips_extract_band_class_init\n"); |
421 | | |
422 | 16 | gobject_class->set_property = vips_object_set_property; |
423 | 16 | gobject_class->get_property = vips_object_get_property; |
424 | | |
425 | 16 | vobject_class->nickname = "extract_band"; |
426 | 16 | vobject_class->description = _("extract band from an image"); |
427 | 16 | vobject_class->build = vips_extract_band_build; |
428 | | |
429 | 16 | bandary_class->process_line = vips_extract_band_buffer; |
430 | | |
431 | 16 | VIPS_ARG_IMAGE(class, "in", 1, |
432 | 16 | _("Input"), |
433 | 16 | _("Input image"), |
434 | 16 | VIPS_ARGUMENT_REQUIRED_INPUT, |
435 | 16 | G_STRUCT_OFFSET(VipsExtractBand, in)); |
436 | | |
437 | 16 | VIPS_ARG_INT(class, "band", 3, |
438 | 16 | _("Band"), |
439 | 16 | _("Band to extract"), |
440 | 16 | VIPS_ARGUMENT_REQUIRED_INPUT, |
441 | 16 | G_STRUCT_OFFSET(VipsExtractBand, band), |
442 | 16 | 0, VIPS_MAX_COORD, 0); |
443 | | |
444 | 16 | VIPS_ARG_INT(class, "n", 4, |
445 | 16 | _("n"), |
446 | 16 | _("Number of bands to extract"), |
447 | 16 | VIPS_ARGUMENT_OPTIONAL_INPUT, |
448 | 16 | G_STRUCT_OFFSET(VipsExtractBand, n), |
449 | 16 | 1, VIPS_MAX_COORD, 1); |
450 | 16 | } |
451 | | |
452 | | static void |
453 | | vips_extract_band_init(VipsExtractBand *extract) |
454 | 289k | { |
455 | 289k | extract->n = 1; |
456 | 289k | } |
457 | | |
458 | | /** |
459 | | * vips_extract_band: (method) |
460 | | * @in: input image |
461 | | * @out: (out): output image |
462 | | * @band: index of first band to extract |
463 | | * @...: %NULL-terminated list of optional named arguments |
464 | | * |
465 | | * Optional arguments: |
466 | | * |
467 | | * * @n: number of bands to extract |
468 | | * |
469 | | * Extract a band or bands from an image. Extracting out of range is an error. |
470 | | * |
471 | | * @n defaults to 1. |
472 | | * |
473 | | * See also: vips_extract_area(). |
474 | | * |
475 | | * Returns: 0 on success, -1 on error. |
476 | | */ |
477 | | int |
478 | | vips_extract_band(VipsImage *in, VipsImage **out, int band, ...) |
479 | 289k | { |
480 | 289k | va_list ap; |
481 | 289k | int result; |
482 | | |
483 | 289k | va_start(ap, band); |
484 | 289k | result = vips_call_split("extract_band", ap, in, out, band); |
485 | 289k | va_end(ap); |
486 | | |
487 | 289k | return result; |
488 | 289k | } |