Coverage Report

Created: 2025-01-28 06:32

/src/libvips/libvips/conversion/bandfold.c
Line
Count
Source (jump to first uncovered line)
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 _VipsBandfold {
57
  VipsConversion parent_instance;
58
59
  /* The input image.
60
   */
61
  VipsImage *in;
62
63
  int factor;
64
65
} VipsBandfold;
66
67
typedef VipsConversionClass VipsBandfoldClass;
68
69
G_DEFINE_TYPE(VipsBandfold, vips_bandfold, VIPS_TYPE_CONVERSION);
70
71
static int
72
vips_bandfold_gen(VipsRegion *out_region,
73
  void *seq, void *a, void *b, gboolean *stop)
74
0
{
75
0
  VipsBandfold *bandfold = (VipsBandfold *) b;
76
0
  VipsRegion *ir = (VipsRegion *) seq;
77
0
  VipsImage *out = out_region->im;
78
0
  VipsRect *r = &out_region->valid;
79
0
  int psize = VIPS_IMAGE_SIZEOF_PEL(out);
80
81
0
  VipsRect need;
82
0
  int y;
83
84
0
  need.left = r->left * bandfold->factor;
85
0
  need.top = r->top;
86
0
  need.width = r->width * bandfold->factor;
87
0
  need.height = r->height;
88
0
  if (vips_region_prepare(ir, &need))
89
0
    return -1;
90
91
0
  for (y = 0; y < r->height; y++) {
92
0
    VipsPel *p = VIPS_REGION_ADDR(ir,
93
0
      r->left * bandfold->factor, r->top + y);
94
0
    VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y);
95
96
    /* We can't use vips_region_region() since we change pixel
97
     * coordinates.
98
     */
99
0
    memcpy(q, p, psize * r->width);
100
0
  }
101
102
0
  return 0;
103
0
}
104
105
static int
106
vips_bandfold_build(VipsObject *object)
107
0
{
108
0
  VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object);
109
0
  VipsConversion *conversion = VIPS_CONVERSION(object);
110
0
  VipsBandfold *bandfold = (VipsBandfold *) object;
111
112
0
  if (VIPS_OBJECT_CLASS(vips_bandfold_parent_class)->build(object))
113
0
    return -1;
114
115
0
  if (vips_image_pio_input(bandfold->in))
116
0
    return -1;
117
118
0
  if (bandfold->factor == 0)
119
0
    bandfold->factor = bandfold->in->Xsize; // FIXME: Invalidates operation cache
120
121
0
  if (bandfold->in->Xsize % bandfold->factor != 0) {
122
0
    vips_error(class->nickname,
123
0
      "%s", _("@factor must be a factor of image width"));
124
0
    return -1;
125
0
  }
126
127
0
  if (vips_image_pipelinev(conversion->out,
128
0
      VIPS_DEMAND_STYLE_THINSTRIP, bandfold->in, NULL))
129
0
    return -1;
130
131
0
  conversion->out->Xsize /= bandfold->factor;
132
0
  conversion->out->Bands *= bandfold->factor;
133
134
0
  if (vips_image_generate(conversion->out,
135
0
      vips_start_one, vips_bandfold_gen, vips_stop_one,
136
0
      bandfold->in, bandfold))
137
0
    return -1;
138
139
0
  return 0;
140
0
}
141
142
static void
143
vips_bandfold_class_init(VipsBandfoldClass *class)
144
0
{
145
0
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
146
0
  VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class);
147
0
  VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class);
148
149
0
  VIPS_DEBUG_MSG("vips_bandfold_class_init\n");
150
151
0
  gobject_class->set_property = vips_object_set_property;
152
0
  gobject_class->get_property = vips_object_get_property;
153
154
0
  vobject_class->nickname = "bandfold";
155
0
  vobject_class->description = _("fold up x axis into bands");
156
0
  vobject_class->build = vips_bandfold_build;
157
158
0
  operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
159
160
0
  VIPS_ARG_IMAGE(class, "in", 1,
161
0
    _("Input"),
162
0
    _("Input image"),
163
0
    VIPS_ARGUMENT_REQUIRED_INPUT,
164
0
    G_STRUCT_OFFSET(VipsBandfold, in));
165
166
0
  VIPS_ARG_INT(class, "factor", 11,
167
0
    _("Factor"),
168
0
    _("Fold by this factor"),
169
0
    VIPS_ARGUMENT_OPTIONAL_INPUT,
170
0
    G_STRUCT_OFFSET(VipsBandfold, factor),
171
0
    0, 10000000, 0);
172
0
}
173
174
static void
175
vips_bandfold_init(VipsBandfold *bandfold)
176
0
{
177
  /* 0 means fold by width, see above.
178
   */
179
0
  bandfold->factor = 0;
180
0
}
181
182
/**
183
 * vips_bandfold: (method)
184
 * @in: input image
185
 * @out: (out): output image
186
 * @...: %NULL-terminated list of optional named arguments
187
 *
188
 * Optional arguments:
189
 *
190
 * * @factor: fold by this factor
191
 *
192
 * Fold up an image horizontally: width is collapsed into bands.
193
 * Use @factor to set how much to fold by: @factor 3, for example, will make
194
 * the output image three times narrower than the input, and with three times
195
 * as many bands. By default the whole of the input width is folded up.
196
 *
197
 * See also: vips_csvload(), vips_bandunfold().
198
 *
199
 * Returns: 0 on success, -1 on error.
200
 */
201
int
202
vips_bandfold(VipsImage *in, VipsImage **out, ...)
203
0
{
204
0
  va_list ap;
205
0
  int result;
206
207
0
  va_start(ap, out);
208
0
  result = vips_call_split("bandfold", ap, in, out);
209
0
  va_end(ap);
210
211
0
  return result;
212
0
}