/src/libvips/libvips/arithmetic/round.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* round.c --- various rounding operations |
2 | | * |
3 | | * 20/6/02 JC |
4 | | * - adapted from im_abs() |
5 | | * 29/8/09 |
6 | | * - gtkdoc |
7 | | * - tiny cleanups |
8 | | * 19/9/09 |
9 | | * - im_ceil.c adapted to make round.c |
10 | | * 10/11/11 |
11 | | * - redone as a class |
12 | | */ |
13 | | |
14 | | /* |
15 | | |
16 | | Copyright (C) 1991-2005 The National Gallery |
17 | | |
18 | | This library is free software; you can redistribute it and/or |
19 | | modify it under the terms of the GNU Lesser General Public |
20 | | License as published by the Free Software Foundation; either |
21 | | version 2.1 of the License, or (at your option) any later version. |
22 | | |
23 | | This library is distributed in the hope that it will be useful, |
24 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
26 | | Lesser General Public License for more details. |
27 | | |
28 | | You should have received a copy of the GNU Lesser General Public |
29 | | License along with this library; if not, write to the Free Software |
30 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
31 | | 02110-1301 USA |
32 | | |
33 | | */ |
34 | | |
35 | | /* |
36 | | |
37 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
38 | | |
39 | | */ |
40 | | |
41 | | /* |
42 | | #define DEBUG |
43 | | */ |
44 | | |
45 | | #ifdef HAVE_CONFIG_H |
46 | | #include <config.h> |
47 | | #endif /*HAVE_CONFIG_H*/ |
48 | | #include <glib/gi18n-lib.h> |
49 | | |
50 | | #include <stdio.h> |
51 | | #include <stdlib.h> |
52 | | #include <math.h> |
53 | | |
54 | | #include <vips/vips.h> |
55 | | |
56 | | #include "unary.h" |
57 | | |
58 | | typedef struct _VipsRound { |
59 | | VipsUnary parent_instance; |
60 | | |
61 | | VipsOperationRound round; |
62 | | |
63 | | } VipsRound; |
64 | | |
65 | | typedef VipsUnaryClass VipsRoundClass; |
66 | | |
67 | | G_DEFINE_TYPE(VipsRound, vips_round, VIPS_TYPE_UNARY); |
68 | | |
69 | | static int |
70 | | vips_round_build(VipsObject *object) |
71 | 0 | { |
72 | 0 | VipsUnary *unary = (VipsUnary *) object; |
73 | | |
74 | | /* Is this one of the int types? Degenerate to vips_copy() if it |
75 | | * is. |
76 | | */ |
77 | 0 | if (unary->in && |
78 | 0 | vips_band_format_isint(unary->in->BandFmt)) |
79 | 0 | return vips_unary_copy(unary); |
80 | | |
81 | 0 | if (VIPS_OBJECT_CLASS(vips_round_parent_class)->build(object)) |
82 | 0 | return -1; |
83 | | |
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | | #define LOOP(TYPE, OP) \ |
88 | 0 | { \ |
89 | 0 | TYPE *restrict p = (TYPE *) in[0]; \ |
90 | 0 | TYPE *restrict q = (TYPE *) out; \ |
91 | 0 | \ |
92 | 0 | for (x = 0; x < sz; x++) \ |
93 | 0 | q[x] = OP(p[x]); \ |
94 | 0 | } |
95 | | |
96 | | #define SWITCH(OP) \ |
97 | 0 | { \ |
98 | 0 | switch (vips_image_get_format(im)) { \ |
99 | 0 | case VIPS_FORMAT_COMPLEX: \ |
100 | 0 | case VIPS_FORMAT_FLOAT: \ |
101 | 0 | LOOP(float, OP); \ |
102 | 0 | break; \ |
103 | 0 | \ |
104 | 0 | case VIPS_FORMAT_DPCOMPLEX: \ |
105 | 0 | case VIPS_FORMAT_DOUBLE: \ |
106 | 0 | LOOP(double, OP); \ |
107 | 0 | break; \ |
108 | 0 | \ |
109 | 0 | default: \ |
110 | 0 | g_assert_not_reached(); \ |
111 | 0 | } \ |
112 | 0 | } |
113 | | |
114 | | static void |
115 | | vips_round_buffer(VipsArithmetic *arithmetic, |
116 | | VipsPel *out, VipsPel **in, int width) |
117 | 0 | { |
118 | 0 | VipsRound *round = (VipsRound *) arithmetic; |
119 | 0 | VipsImage *im = arithmetic->ready[0]; |
120 | | |
121 | | /* Complex just doubles the size. |
122 | | */ |
123 | 0 | const int sz = width * im->Bands * |
124 | 0 | (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1); |
125 | |
|
126 | 0 | int x; |
127 | |
|
128 | 0 | switch (round->round) { |
129 | 0 | case VIPS_OPERATION_ROUND_RINT: |
130 | 0 | SWITCH(VIPS_RINT); |
131 | 0 | break; |
132 | 0 | case VIPS_OPERATION_ROUND_CEIL: |
133 | 0 | SWITCH(VIPS_CEIL); |
134 | 0 | break; |
135 | 0 | case VIPS_OPERATION_ROUND_FLOOR: |
136 | 0 | SWITCH(VIPS_FLOOR); |
137 | 0 | break; |
138 | | |
139 | 0 | default: |
140 | 0 | g_assert_not_reached(); |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | /* Save a bit of typing. |
145 | | */ |
146 | | #define UC VIPS_FORMAT_UCHAR |
147 | | #define C VIPS_FORMAT_CHAR |
148 | | #define US VIPS_FORMAT_USHORT |
149 | | #define S VIPS_FORMAT_SHORT |
150 | | #define UI VIPS_FORMAT_UINT |
151 | | #define I VIPS_FORMAT_INT |
152 | | #define F VIPS_FORMAT_FLOAT |
153 | | #define X VIPS_FORMAT_COMPLEX |
154 | | #define D VIPS_FORMAT_DOUBLE |
155 | | #define DX VIPS_FORMAT_DPCOMPLEX |
156 | | |
157 | | static const VipsBandFormat vips_round_format_table[10] = { |
158 | | /* Band format: UC C US S UI I F X D DX */ |
159 | | /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX |
160 | | }; |
161 | | |
162 | | static void |
163 | | vips_round_class_init(VipsRoundClass *class) |
164 | 1 | { |
165 | 1 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
166 | 1 | VipsObjectClass *object_class = (VipsObjectClass *) class; |
167 | 1 | VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); |
168 | | |
169 | 1 | gobject_class->set_property = vips_object_set_property; |
170 | 1 | gobject_class->get_property = vips_object_get_property; |
171 | | |
172 | 1 | object_class->nickname = "round"; |
173 | 1 | object_class->description = _("perform a round function on an image"); |
174 | 1 | object_class->build = vips_round_build; |
175 | | |
176 | 1 | aclass->process_line = vips_round_buffer; |
177 | | |
178 | 1 | vips_arithmetic_set_format_table(aclass, vips_round_format_table); |
179 | | |
180 | 1 | VIPS_ARG_ENUM(class, "round", 200, |
181 | 1 | _("Round operation"), |
182 | 1 | _("Rounding operation to perform"), |
183 | 1 | VIPS_ARGUMENT_REQUIRED_INPUT, |
184 | 1 | G_STRUCT_OFFSET(VipsRound, round), |
185 | 1 | VIPS_TYPE_OPERATION_ROUND, VIPS_OPERATION_ROUND_RINT); |
186 | 1 | } |
187 | | |
188 | | static void |
189 | | vips_round_init(VipsRound *round) |
190 | 0 | { |
191 | 0 | } |
192 | | |
193 | | static int |
194 | | vips_roundv(VipsImage *in, VipsImage **out, |
195 | | VipsOperationRound round, va_list ap) |
196 | 0 | { |
197 | 0 | return vips_call_split("round", ap, in, out, round); |
198 | 0 | } |
199 | | |
200 | | /** |
201 | | * vips_round: (method) |
202 | | * @in: input #VipsImage |
203 | | * @out: (out): output #VipsImage |
204 | | * @round: #VipsOperationRound rounding operation to perform |
205 | | * @...: %NULL-terminated list of optional named arguments |
206 | | * |
207 | | * Round to an integral value. |
208 | | * |
209 | | * Copy for integer types, round float and |
210 | | * complex types. |
211 | | * |
212 | | * The format of @out is always the same as @in, so you may wish to cast to an |
213 | | * integer format afterwards. |
214 | | * |
215 | | * See also: vips_cast() |
216 | | * |
217 | | * Returns: 0 on success, -1 on error |
218 | | */ |
219 | | int |
220 | | vips_round(VipsImage *in, VipsImage **out, VipsOperationRound round, ...) |
221 | 0 | { |
222 | 0 | va_list ap; |
223 | 0 | int result; |
224 | |
|
225 | 0 | va_start(ap, round); |
226 | 0 | result = vips_roundv(in, out, round, ap); |
227 | 0 | va_end(ap); |
228 | |
|
229 | 0 | return result; |
230 | 0 | } |
231 | | |
232 | | /** |
233 | | * vips_floor: (method) |
234 | | * @in: input #VipsImage |
235 | | * @out: (out): output #VipsImage |
236 | | * @...: %NULL-terminated list of optional named arguments |
237 | | * |
238 | | * Round to an integral value with #VIPS_OPERATION_ROUND_FLOOR. See |
239 | | * vips_round(). |
240 | | * |
241 | | * Returns: 0 on success, -1 on error |
242 | | */ |
243 | | int |
244 | | vips_floor(VipsImage *in, VipsImage **out, ...) |
245 | 0 | { |
246 | 0 | va_list ap; |
247 | 0 | int result; |
248 | |
|
249 | 0 | va_start(ap, out); |
250 | 0 | result = vips_roundv(in, out, VIPS_OPERATION_ROUND_FLOOR, ap); |
251 | 0 | va_end(ap); |
252 | |
|
253 | 0 | return result; |
254 | 0 | } |
255 | | |
256 | | /** |
257 | | * vips_ceil: (method) |
258 | | * @in: input #VipsImage |
259 | | * @out: (out): output #VipsImage |
260 | | * @...: %NULL-terminated list of optional named arguments |
261 | | * |
262 | | * Round to an integral value with #VIPS_OPERATION_ROUND_CEIL. See |
263 | | * vips_round(). |
264 | | * |
265 | | * Returns: 0 on success, -1 on error |
266 | | */ |
267 | | int |
268 | | vips_ceil(VipsImage *in, VipsImage **out, ...) |
269 | 0 | { |
270 | 0 | va_list ap; |
271 | 0 | int result; |
272 | |
|
273 | 0 | va_start(ap, out); |
274 | 0 | result = vips_roundv(in, out, VIPS_OPERATION_ROUND_CEIL, ap); |
275 | 0 | va_end(ap); |
276 | |
|
277 | 0 | return result; |
278 | 0 | } |
279 | | |
280 | | /** |
281 | | * vips_rint: (method) |
282 | | * @in: input #VipsImage |
283 | | * @out: (out): output #VipsImage |
284 | | * @...: %NULL-terminated list of optional named arguments |
285 | | * |
286 | | * Round to an integral value with #VIPS_OPERATION_ROUND_RINT. See |
287 | | * vips_round(). |
288 | | * |
289 | | * Returns: 0 on success, -1 on error |
290 | | */ |
291 | | int |
292 | | vips_rint(VipsImage *in, VipsImage **out, ...) |
293 | 0 | { |
294 | 0 | va_list ap; |
295 | 0 | int result; |
296 | |
|
297 | 0 | va_start(ap, out); |
298 | 0 | result = vips_roundv(in, out, VIPS_OPERATION_ROUND_RINT, ap); |
299 | 0 | va_end(ap); |
300 | |
|
301 | 0 | return result; |
302 | 0 | } |