Coverage Report

Created: 2025-01-28 06:32

/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
}