Coverage Report

Created: 2026-04-01 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvips/libvips/draw/draw_rect.c
Line
Count
Source
1
/* Fill Rect r of image im with pels of colour ink.
2
 *
3
 * Copyright: J. Cupitt
4
 * Written: 15/06/1992
5
 * 22/7/93 JC
6
 *  - im_incheck() added
7
 * 16/8/94 JC
8
 *  - im_incheck() changed to im_makerw()
9
 * 5/12/06
10
 *  - im_invalidate() after paint
11
 * 6/3/10
12
 *  - don't im_invalidate() after paint, this now needs to be at a higher
13
 *    level
14
 * 22/9/10
15
 *  - gtk-doc
16
 *  - added 'fill'
17
 *  - renamed as im_draw_rect() for consistency
18
 * 27/9/10
19
 *  - memcpy() subsequent lines of the rect
20
 * 10/2/14
21
 *  - redo as a class
22
 */
23
24
/*
25
26
  This file is part of VIPS.
27
28
  VIPS is free software; you can redistribute it and/or modify
29
  it under the terms of the GNU Lesser General Public License as published by
30
  the Free Software Foundation; either version 2 of the License, or
31
  (at your option) any later version.
32
33
  This program is distributed in the hope that it will be useful,
34
  but WITHOUT ANY WARRANTY; without even the implied warranty of
35
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36
  GNU Lesser General Public License for more details.
37
38
  You should have received a copy of the GNU Lesser General Public License
39
  along with this program; if not, write to the Free Software
40
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
41
  02110-1301  USA
42
43
 */
44
45
/*
46
47
  These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
48
49
 */
50
51
#ifdef HAVE_CONFIG_H
52
#include <config.h>
53
#endif /*HAVE_CONFIG_H*/
54
#include <glib/gi18n-lib.h>
55
56
#include <stdio.h>
57
#include <stdlib.h>
58
#include <string.h>
59
60
#include <vips/vips.h>
61
#include <vips/internal.h>
62
63
#include "drawink.h"
64
65
typedef struct _VipsDrawRect {
66
  VipsDrawink parent_object;
67
68
  /* Parameters.
69
   */
70
  int left;
71
  int top;
72
  int width;
73
  int height;
74
  gboolean fill;
75
76
} VipsDrawRect;
77
78
typedef struct _VipsDrawRectClass {
79
  VipsDrawinkClass parent_class;
80
81
} VipsDrawRectClass;
82
83
38
G_DEFINE_TYPE(VipsDrawRect, vips_draw_rect, VIPS_TYPE_DRAWINK);
84
38
85
38
static int
86
38
vips_draw_rect_build(VipsObject *object)
87
38
{
88
11
  VipsDraw *draw = VIPS_DRAW(object);
89
11
  VipsDrawink *drawink = VIPS_DRAWINK(object);
90
11
  VipsArea *ink = VIPS_AREA(drawink->ink);
91
11
  VipsDrawRect *draw_rect = (VipsDrawRect *) object;
92
11
  int left = draw_rect->left;
93
11
  int top = draw_rect->top;
94
11
  int width = draw_rect->width;
95
11
  int height = draw_rect->height;
96
97
11
  VipsRect image;
98
11
  VipsRect rect;
99
11
  VipsRect clip;
100
101
11
  if (VIPS_OBJECT_CLASS(vips_draw_rect_parent_class)->build(object))
102
1
    return -1;
103
104
  /* Also use a solid fill for very narrow unfilled rects.
105
   */
106
10
  if (!draw_rect->fill &&
107
10
    width > 2 &&
108
5
    height > 2)
109
1
    return vips_draw_rect(draw->image,
110
1
           ink->data, ink->n,
111
1
           left, top, width, 1, NULL) ||
112
1
      vips_draw_rect(draw->image,
113
1
        ink->data, ink->n,
114
1
        left + width - 1, top, 1, height, NULL) ||
115
1
      vips_draw_rect(draw->image,
116
1
        ink->data, ink->n,
117
1
        left, top + height - 1, width, 1, NULL) ||
118
1
      vips_draw_rect(draw->image,
119
1
        ink->data, ink->n,
120
1
        left, top, 1, height, NULL);
121
122
9
  image.left = 0;
123
9
  image.top = 0;
124
9
  image.width = draw->image->Xsize;
125
9
  image.height = draw->image->Ysize;
126
9
  rect.left = left;
127
9
  rect.top = top;
128
9
  rect.width = width;
129
9
  rect.height = height;
130
9
  vips_rect_intersectrect(&rect, &image, &clip);
131
132
9
  if (!vips_rect_isempty(&clip)) {
133
6
    VipsPel *to =
134
6
      VIPS_IMAGE_ADDR(draw->image, clip.left, clip.top);
135
136
6
    VipsPel *q;
137
6
    int x, y;
138
139
    /* We plot the first line pointwise, then memcpy() it for the
140
     * subsequent lines.
141
     */
142
143
6
    q = to;
144
35
    for (x = 0; x < clip.width; x++) {
145
29
      vips__drawink_pel(drawink, q);
146
29
      q += draw->psize;
147
29
    }
148
149
6
    q = to + draw->lsize;
150
8
    for (y = 1; y < clip.height; y++) {
151
2
      memcpy(q, to, clip.width * draw->psize);
152
2
      q += draw->lsize;
153
2
    }
154
6
  }
155
156
9
  return 0;
157
10
}
158
159
static void
160
vips_draw_rect_class_init(VipsDrawRectClass *class)
161
19
{
162
19
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
163
19
  VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class);
164
165
19
  gobject_class->set_property = vips_object_set_property;
166
19
  gobject_class->get_property = vips_object_get_property;
167
168
19
  vobject_class->nickname = "draw_rect";
169
19
  vobject_class->description = _("paint a rectangle on an image");
170
19
  vobject_class->build = vips_draw_rect_build;
171
172
19
  VIPS_ARG_INT(class, "left", 6,
173
19
    _("Left"),
174
19
    _("Rect to fill"),
175
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
176
19
    G_STRUCT_OFFSET(VipsDrawRect, left),
177
19
    -1000000000, 1000000000, 0);
178
179
19
  VIPS_ARG_INT(class, "top", 7,
180
19
    _("Top"),
181
19
    _("Rect to fill"),
182
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
183
19
    G_STRUCT_OFFSET(VipsDrawRect, top),
184
19
    -1000000000, 1000000000, 0);
185
186
19
  VIPS_ARG_INT(class, "width", 8,
187
19
    _("Width"),
188
19
    _("Rect to fill"),
189
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
190
19
    G_STRUCT_OFFSET(VipsDrawRect, width),
191
19
    -1000000000, 1000000000, 0);
192
193
19
  VIPS_ARG_INT(class, "height", 9,
194
19
    _("Height"),
195
19
    _("Rect to fill"),
196
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
197
19
    G_STRUCT_OFFSET(VipsDrawRect, height),
198
19
    -1000000000, 1000000000, 0);
199
200
19
  VIPS_ARG_BOOL(class, "fill", 10,
201
19
    _("Fill"),
202
19
    _("Draw a solid object"),
203
19
    VIPS_ARGUMENT_OPTIONAL_INPUT,
204
19
    G_STRUCT_OFFSET(VipsDrawRect, fill),
205
19
    FALSE);
206
19
}
207
208
static void
209
vips_draw_rect_init(VipsDrawRect *draw_rect)
210
12
{
211
12
}
212
213
static int
214
vips_draw_rectv(VipsImage *image,
215
  double *ink, int n, int left, int top, int width, int height,
216
  va_list ap)
217
4
{
218
4
  VipsArea *area_ink;
219
4
  int result;
220
221
4
  area_ink = VIPS_AREA(vips_array_double_new(ink, n));
222
4
  result = vips_call_split("draw_rect", ap,
223
4
    image, area_ink, left, top, width, height);
224
4
  vips_area_unref(area_ink);
225
226
4
  return result;
227
4
}
228
229
/**
230
 * vips_draw_rect: (method)
231
 * @image: image to draw on
232
 * @ink: (array length=n): value to draw
233
 * @n: length of ink array
234
 * @left: area to paint
235
 * @top: area to paint
236
 * @width: area to paint
237
 * @height: area to paint
238
 * @...: `NULL`-terminated list of optional named arguments
239
 *
240
 * Paint pixels within @left, @top, @width, @height in @image with @ink.
241
 *
242
 * If @fill is zero, just paint a 1-pixel-wide outline.
243
 *
244
 * ::: tip "Optional arguments"
245
 *     * @fill: `gboolean`, fill the rect
246
 *
247
 * ::: seealso
248
 *     [method@Image.draw_circle].
249
 *
250
 * Returns: 0 on success, or -1 on error.
251
 */
252
int
253
vips_draw_rect(VipsImage *image,
254
  double *ink, int n, int left, int top, int width, int height, ...)
255
4
{
256
4
  va_list ap;
257
4
  int result;
258
259
4
  va_start(ap, height);
260
4
  result = vips_draw_rectv(image,
261
4
    ink, n, left, top, width, height, ap);
262
4
  va_end(ap);
263
264
4
  return result;
265
4
}
266
267
/**
268
 * vips_draw_rect1: (method)
269
 * @image: image to draw on
270
 * @ink: value to draw
271
 * @left: area to paint
272
 * @top: area to paint
273
 * @width: area to paint
274
 * @height: area to paint
275
 * @...: `NULL`-terminated list of optional named arguments
276
 *
277
 * As [method@Image.draw_rect], but just take a single double for @ink.
278
 *
279
 * ::: tip "Optional arguments"
280
 *     * @fill: `gboolean`, fill the rect
281
 *
282
 * ::: seealso
283
 *     [method@Image.draw_rect].
284
 *
285
 * Returns: 0 on success, or -1 on error.
286
 */
287
int
288
vips_draw_rect1(VipsImage *image,
289
  double ink, int left, int top, int width, int height, ...)
290
0
{
291
0
  double array_ink[1];
292
0
  va_list ap;
293
0
  int result;
294
295
0
  array_ink[0] = ink;
296
297
0
  va_start(ap, height);
298
0
  result = vips_draw_rectv(image,
299
0
    array_ink, 1, left, top, width, height, ap);
300
0
  va_end(ap);
301
302
0
  return result;
303
0
}
304
305
/**
306
 * vips_draw_point: (method)
307
 * @image: image to draw on
308
 * @ink: (array length=n): value to draw
309
 * @n: length of ink array
310
 * @x: point to paint
311
 * @y: point to paint
312
 * @...: `NULL`-terminated list of optional named arguments
313
 *
314
 * As [method@Image.draw_rect], but draw a single pixel at @x, @y.
315
 *
316
 * ::: seealso
317
 *     [method@Image.draw_rect].
318
 *
319
 * Returns: 0 on success, or -1 on error.
320
 */
321
int
322
vips_draw_point(VipsImage *image, double *ink, int n, int x, int y, ...)
323
0
{
324
0
  va_list ap;
325
0
  int result;
326
327
0
  va_start(ap, y);
328
0
  result = vips_draw_rectv(image, ink, n, x, y, 1, 1, ap);
329
0
  va_end(ap);
330
331
0
  return result;
332
0
}
333
334
/**
335
 * vips_draw_point1: (method)
336
 * @image: image to draw on
337
 * @ink: value to draw
338
 * @x: point to draw
339
 * @y: point to draw
340
 * @...: `NULL`-terminated list of optional named arguments
341
 *
342
 * As [method@Image.draw_point], but just take a single double for @ink.
343
 *
344
 * ::: seealso
345
 *     [method@Image.draw_point].
346
 *
347
 * Returns: 0 on success, or -1 on error.
348
 */
349
int
350
vips_draw_point1(VipsImage *image, double ink, int x, int y, ...)
351
0
{
352
0
  double array_ink[1];
353
0
  va_list ap;
354
0
  int result;
355
356
0
  array_ink[0] = ink;
357
358
0
  va_start(ap, y);
359
0
  result = vips_draw_rectv(image, array_ink, 1, x, y, 1, 1, ap);
360
0
  va_end(ap);
361
362
0
  return result;
363
0
}