Coverage Report

Created: 2026-08-11 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}