/src/libvips/libvips/conversion/bandunfold.c
Line | Count | Source |
1 | | /* Fold up x into bands. |
2 | | * |
3 | | * 5/6/15 |
4 | | * - from copy.c |
5 | | * 10/6/15 |
6 | | * - add @factor option |
7 | | */ |
8 | | |
9 | | /* |
10 | | |
11 | | This file is part of VIPS. |
12 | | |
13 | | VIPS is free software; you can redistribute it and/or modify |
14 | | it under the terms of the GNU Lesser General Public License as published by |
15 | | the Free Software Foundation; either version 2 of the License, or |
16 | | (at your option) any later version. |
17 | | |
18 | | This program is distributed in the hope that it will be useful, |
19 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | | GNU Lesser General Public License for more details. |
22 | | |
23 | | You should have received a copy of the GNU Lesser General Public License |
24 | | along with this program; if not, write to the Free Software |
25 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
26 | | 02110-1301 USA |
27 | | |
28 | | */ |
29 | | |
30 | | /* |
31 | | |
32 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
33 | | |
34 | | */ |
35 | | |
36 | | /* |
37 | | #define VIPS_DEBUG |
38 | | */ |
39 | | |
40 | | #ifdef HAVE_CONFIG_H |
41 | | #include <config.h> |
42 | | #endif /*HAVE_CONFIG_H*/ |
43 | | #include <glib/gi18n-lib.h> |
44 | | |
45 | | #include <stdio.h> |
46 | | #include <stdlib.h> |
47 | | #include <string.h> |
48 | | #include <math.h> |
49 | | |
50 | | #include <vips/vips.h> |
51 | | #include <vips/internal.h> |
52 | | #include <vips/debug.h> |
53 | | |
54 | | #include "pconversion.h" |
55 | | |
56 | | typedef struct _VipsBandunfold { |
57 | | VipsConversion parent_instance; |
58 | | |
59 | | /* The input image. |
60 | | */ |
61 | | VipsImage *in; |
62 | | |
63 | | int factor; |
64 | | |
65 | | } VipsBandunfold; |
66 | | |
67 | | typedef VipsConversionClass VipsBandunfoldClass; |
68 | | |
69 | 39 | G_DEFINE_TYPE(VipsBandunfold, vips_bandunfold, VIPS_TYPE_CONVERSION); |
70 | 39 | |
71 | 39 | static int |
72 | 39 | vips_bandunfold_gen(VipsRegion *out_region, |
73 | 39 | void *seq, void *a, void *b, gboolean *stop) |
74 | 39 | { |
75 | 15 | VipsBandunfold *bandunfold = (VipsBandunfold *) b; |
76 | 15 | VipsRegion *ir = (VipsRegion *) seq; |
77 | 15 | VipsImage *in = ir->im; |
78 | 15 | VipsImage *out = out_region->im; |
79 | 15 | VipsRect *r = &out_region->valid; |
80 | 15 | int esize = VIPS_IMAGE_SIZEOF_ELEMENT(in); |
81 | 15 | int psize = VIPS_IMAGE_SIZEOF_PEL(out); |
82 | | |
83 | 15 | VipsRect need; |
84 | 15 | int y; |
85 | | |
86 | 15 | need.left = r->left / bandunfold->factor; |
87 | 15 | need.top = r->top; |
88 | 15 | need.width = 1 + VIPS_RECT_RIGHT(r) / bandunfold->factor - need.left; |
89 | 15 | need.height = r->height; |
90 | 15 | if (vips_region_prepare(ir, &need)) |
91 | 1 | return -1; |
92 | | |
93 | 167 | for (y = 0; y < r->height; y++) { |
94 | 153 | VipsPel *p = VIPS_REGION_ADDR(ir, |
95 | 153 | r->left / bandunfold->factor, r->top + y) + |
96 | 153 | (r->left % bandunfold->factor) * esize; |
97 | 153 | VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); |
98 | | |
99 | | /* We can't use vips_region_region() since we change pixel |
100 | | * coordinates. |
101 | | */ |
102 | 153 | memcpy(q, p, (size_t) r->width * psize); |
103 | 153 | } |
104 | | |
105 | 14 | return 0; |
106 | 15 | } |
107 | | |
108 | | static int |
109 | | vips_bandunfold_build(VipsObject *object) |
110 | 8 | { |
111 | 8 | VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); |
112 | 8 | VipsConversion *conversion = VIPS_CONVERSION(object); |
113 | 8 | VipsBandunfold *bandunfold = (VipsBandunfold *) object; |
114 | 8 | VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); |
115 | | |
116 | 8 | VipsImage *in; |
117 | | |
118 | 8 | if (VIPS_OBJECT_CLASS(vips_bandunfold_parent_class)->build(object)) |
119 | 0 | return -1; |
120 | | |
121 | 8 | in = bandunfold->in; |
122 | | |
123 | 8 | if (vips_image_decode(in, &t[0])) |
124 | 0 | return -1; |
125 | 8 | in = t[0]; |
126 | | |
127 | 8 | if (bandunfold->factor == 0) |
128 | 8 | bandunfold->factor = in->Bands; // FIXME: Invalidates operation cache |
129 | | |
130 | 8 | if (in->Bands % bandunfold->factor != 0) { |
131 | 0 | vips_error(class->nickname, |
132 | 0 | "%s", _("@factor must be a factor of image bands")); |
133 | 0 | return -1; |
134 | 0 | } |
135 | | |
136 | 8 | if (vips_image_pipelinev(conversion->out, |
137 | 8 | VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) |
138 | 0 | return -1; |
139 | | |
140 | 8 | conversion->out->Xsize *= bandunfold->factor; |
141 | 8 | conversion->out->Bands /= bandunfold->factor; |
142 | | |
143 | 8 | if (vips_image_generate(conversion->out, |
144 | 8 | vips_start_one, vips_bandunfold_gen, vips_stop_one, |
145 | 8 | in, bandunfold)) |
146 | 0 | return -1; |
147 | | |
148 | 8 | return 0; |
149 | 8 | } |
150 | | |
151 | | static void |
152 | | vips_bandunfold_class_init(VipsBandunfoldClass *class) |
153 | 19 | { |
154 | 19 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
155 | 19 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
156 | 19 | VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); |
157 | | |
158 | 19 | VIPS_DEBUG_MSG("vips_bandunfold_class_init\n"); |
159 | | |
160 | 19 | gobject_class->set_property = vips_object_set_property; |
161 | 19 | gobject_class->get_property = vips_object_get_property; |
162 | | |
163 | 19 | vobject_class->nickname = "bandunfold"; |
164 | 19 | vobject_class->description = _("unfold image bands into x axis"); |
165 | 19 | vobject_class->build = vips_bandunfold_build; |
166 | | |
167 | 19 | operation_class->flags = VIPS_OPERATION_SEQUENTIAL; |
168 | | |
169 | 19 | VIPS_ARG_IMAGE(class, "in", 1, |
170 | 19 | _("Input"), |
171 | 19 | _("Input image"), |
172 | 19 | VIPS_ARGUMENT_REQUIRED_INPUT, |
173 | 19 | G_STRUCT_OFFSET(VipsBandunfold, in)); |
174 | | |
175 | 19 | VIPS_ARG_INT(class, "factor", 11, |
176 | 19 | _("Factor"), |
177 | 19 | _("Unfold by this factor"), |
178 | 19 | VIPS_ARGUMENT_OPTIONAL_INPUT, |
179 | 19 | G_STRUCT_OFFSET(VipsBandunfold, factor), |
180 | 19 | 0, 10000000, 0); |
181 | 19 | } |
182 | | |
183 | | static void |
184 | | vips_bandunfold_init(VipsBandunfold *bandunfold) |
185 | 9 | { |
186 | | /* 0 means unfold by width, see above. |
187 | | */ |
188 | 9 | bandunfold->factor = 0; |
189 | 9 | } |
190 | | |
191 | | /** |
192 | | * vips_bandunfold: (method) |
193 | | * @in: input image |
194 | | * @out: (out): output image |
195 | | * @...: `NULL`-terminated list of optional named arguments |
196 | | * |
197 | | * Unfold image bands into x axis. |
198 | | * Use @factor to set how much to unfold by: @factor 3, for example, will make |
199 | | * the output image three times wider than the input, and with one third |
200 | | * as many bands. By default, all bands are unfolded. |
201 | | * |
202 | | * ::: tip "Optional arguments" |
203 | | * * @factor: `gint`, unfold by this factor |
204 | | * |
205 | | * ::: seealso |
206 | | * [ctor@Image.csvload], [method@Image.bandfold]. |
207 | | * |
208 | | * Returns: 0 on success, -1 on error. |
209 | | */ |
210 | | int |
211 | | vips_bandunfold(VipsImage *in, VipsImage **out, ...) |
212 | 0 | { |
213 | 0 | va_list ap; |
214 | 0 | int result; |
215 | |
|
216 | 0 | va_start(ap, out); |
217 | 0 | result = vips_call_split("bandunfold", ap, in, out); |
218 | 0 | va_end(ap); |
219 | |
|
220 | 0 | return result; |
221 | 0 | } |