1 /* Make and destroy partial image regions.
2 *
3 * J.Cupitt, 8/4/93.
4 * 1/7/93 JC
5 * - adapted for partial v2
6 * - ANSIfied
7 * 15/8/94 JC
8 * - start & stop can now be NULL for no-op
9 * 12/5/94 JC
10 * - threads v2.0 added
11 * 22/2/95 JC
12 * - im_region_region() args changed
13 * 22/6/95 JC
14 * - im_region_local() did not always reset the data pointer
15 * 18/11/98 JC
16 * - init a, b, c also now, to help rtc avoid spurious checks
17 * 29/6/01 JC
18 * - im_region_free() now frees immediately
19 * 6/8/02 JC
20 * - new mmap() window regions
21 * 5/11/02 JC
22 * - fix for mmap a local region
23 * 28/2/05
24 * - shrink local region memory if required much-greater-than allocated
25 * 3/6/05
26 * - im_region_region() allows Bands and BandFmt to differ, provided
27 * sizeof( pel ) is the same ... makes im_copy_morph() work
28 * 30/10/06
29 * - switch to im_window_t for mmap window stuff
30 * 29/11/06
31 * - switch to im_buffer_t for local mem buffer stuff
32 * 19/1/07
33 * - im_region_image() only sets r, not whole image
34 * 1'2'07
35 * - gah, im_region_image() could still break (thanks Mikkel)
36 * 23/7/08
37 * - added im_region_print()
38 * 7/10/09
39 * - gtkdoc comments
40 * 5/3/10
41 * - move invalid stuff to region
42 * 3/3/11
43 * - move on top of VipsObject, rename as VipsRegion
44 * 23/2/17
45 * - multiply transparent images through alpha in vips_region_shrink()
46 * 13/6/18 harukizaemon
47 * - add VipsRegionShrink parameter to vips_region_shrink()
48 * 9/6/19
49 * - saner behaviour for vips_region_fetch() if the request is partly
50 * outside the image
51 * 22/2/21 f1ac
52 * - fix int overflow in vips_region_copy(), could cause crashes with
53 * very wide images
54 */
55
56 /*
57
58 This file is part of VIPS.
59
60 VIPS is free software; you can redistribute it and/or modify
61 it under the terms of the GNU Lesser General Public License as published by
62 the Free Software Foundation; either version 2 of the License, or
63 (at your option) any later version.
64
65 This program is distributed in the hope that it will be useful,
66 but WITHOUT ANY WARRANTY; without even the implied warranty of
67 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
68 GNU Lesser General Public License for more details.
69
70 You should have received a copy of the GNU Lesser General Public License
71 along with this program; if not, write to the Free Software
72 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
73 02110-1301 USA
74
75 */
76
77 /*
78
79 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
80
81 */
82
83 /*
84 #define DEBUG_MOVE
85 #define DEBUG_ENVIRONMENT 1
86 #define DEBUG_CREATE
87 #define DEBUG
88 #define VIPS_DEBUG
89 */
90
91 #ifdef HAVE_CONFIG_H
92 #include <config.h>
93 #endif /*HAVE_CONFIG_H*/
94 #include <vips/intl.h>
95
96 #include <stdio.h>
97 #include <stdlib.h>
98 #ifdef HAVE_UNISTD_H
99 #include <unistd.h>
100 #endif /*HAVE_UNISTD_H*/
101 #include <string.h>
102
103 #include <vips/vips.h>
104 #include <vips/internal.h>
105 #include <vips/thread.h>
106 #include <vips/debug.h>
107
108 /**
109 * SECTION: region
110 * @short_description: small, rectangular parts of images
111 * @stability: Stable
112 * @see_also: <link linkend="VipsImage">image</link>,
113 * <link linkend="libvips-generate">generate</link>
114 * @include: vips/vips.h
115 *
116 * A #VipsRegion is a small part of an image. You use regions to
117 * read pixels out of images without having to have the whole image in memory
118 * at once.
119 *
120 * A region can be a memory buffer, part of a memory-mapped file, part of some
121 * other image, or part of some other region.
122 *
123 * Regions must be created, used and freed all within the same thread, since
124 * they can reference private per-thread caches. VIPS sanity-checks region
125 * ownership in various places, so you are likely to see g_assert() errors if
126 * you don't follow this rule.
127 *
128 * There
129 * is API to transfer ownership of regions between threads, but hopefully this
130 * is only needed within VIPS, so we don't expose it. Hopefully.
131 */
132
133 /**
134 * VipsRegion:
135 * @im: the #VipsImage that this region is defined on
136 * @valid: the #VipsRect of pixels that this region represents
137 *
138 * A small part of a #VipsImage. @valid holds the left/top/width/height of the
139 * area of pixels that are available from the region.
140 *
141 * See also: VIPS_REGION_ADDR(), vips_region_new(), vips_region_prepare().
142 */
143
144 /**
145 * VIPS_REGION_LSKIP:
146 * @R: a #VipsRegion
147 *
148 * Returns: The number of bytes to add to move down a scanline.
149 */
150
151 /**
152 * VIPS_REGION_N_ELEMENTS:
153 * @R: a #VipsRegion
154 *
155 * Returns: The number of band elements across a region.
156 */
157
158 /**
159 * VIPS_REGION_SIZEOF_LINE:
160 * @R: a #VipsRegion
161 *
162 * Returns: The number of bytes across a region.
163 */
164
165 /**
166 * VIPS_REGION_ADDR:
167 * @R: a #VipsRegion
168 * @X: x coordinate
169 * @Y: y coordinate
170 *
171 * This macro returns a pointer to a pixel in a region. The (@X, @Y)
172 * coordinates need to be within the #VipsRect (@R->valid).
173 *
174 * If DEBUG is defined, you get a version that checks bounds for you.
175 *
176 * See also: vips_region_prepare().
177 *
178 * Returns: The address of pixel (@X,@Y) in @R.
179 */
180
181 /**
182 * VIPS_REGION_ADDR_TOPLEFT:
183 * @R: a #VipsRegion
184 *
185 * This macro returns a pointer to the top-left pixel in the #VipsRegion, that
186 * is, the pixel at (@R->valid.left, @R->valid.top).
187 *
188 * See also: vips_region_prepare().
189 *
190 * Returns: The address of the top-left pixel in the region.
191 */
192
193 /* Properties.
194 */
195 enum {
196 PROP_IMAGE = 1,
197 PROP_LAST
198 };
199
200 G_DEFINE_TYPE( VipsRegion, vips_region, VIPS_TYPE_OBJECT );
201
202 #ifdef VIPS_DEBUG
203 static GSList *vips__regions_all = NULL;
204 #endif /*VIPS_DEBUG*/
205
206 static void
vips_region_finalize(GObject * gobject)207 vips_region_finalize( GObject *gobject )
208 {
209 #ifdef VIPS_DEBUG
210 VIPS_DEBUG_MSG( "vips_region_finalize: " );
211 vips_object_print_name( VIPS_OBJECT( gobject ) );
212 VIPS_DEBUG_MSG( "\n" );
213 #endif /*VIPS_DEBUG*/
214
215 #ifdef VIPS_DEBUG
216 g_mutex_lock( vips__global_lock );
217 vips__regions_all = g_slist_remove( vips__regions_all, gobject );
218 g_mutex_unlock( vips__global_lock );
219 #endif /*VIPS_DEBUG*/
220
221 G_OBJECT_CLASS( vips_region_parent_class )->finalize( gobject );
222 }
223
224 /* Call a start function if no sequence is running on this VipsRegion.
225 */
226 int
vips__region_start(VipsRegion * region)227 vips__region_start( VipsRegion *region )
228 {
229 VipsImage *image = region->im;
230
231 if( !region->seq && image->start_fn ) {
232 VIPS_GATE_START( "vips__region_start: wait" );
233
234 g_mutex_lock( image->sslock );
235
236 VIPS_GATE_STOP( "vips__region_start: wait" );
237
238 region->seq = image->start_fn( image,
239 image->client1, image->client2 );
240
241 g_mutex_unlock( image->sslock );
242
243 if( !region->seq ) {
244 #ifdef DEBUG
245 printf( "vips__region_start: "
246 "start function failed for image %s",
247 image->filename );
248 #endif /*DEBUG*/
249
250 return( -1 );
251 }
252 }
253
254 return( 0 );
255 }
256
257 /* Call a stop function if a sequence is running in this VipsRegion.
258 */
259 void
vips__region_stop(VipsRegion * region)260 vips__region_stop( VipsRegion *region )
261 {
262 VipsImage *image = region->im;
263
264 if( region->seq && image->stop_fn ) {
265 int result;
266
267 VIPS_GATE_START( "vips__region_stop: wait" );
268
269 g_mutex_lock( image->sslock );
270
271 VIPS_GATE_STOP( "vips__region_stop: wait" );
272
273 result = image->stop_fn( region->seq,
274 image->client1, image->client2 );
275
276 g_mutex_unlock( image->sslock );
277
278 /* stop function can return an error, but we have nothing we
279 * can really do with it, sadly.
280 */
281 if( result )
282 g_warning( "stop callback failed for image %s",
283 image->filename );
284
285 region->seq = NULL;
286 }
287 }
288
289 static void
vips_region_dispose(GObject * gobject)290 vips_region_dispose( GObject *gobject )
291 {
292 VipsRegion *region = VIPS_REGION( gobject );
293 VipsImage *image = region->im;
294
295 #ifdef VIPS_DEBUG
296 VIPS_DEBUG_MSG( "vips_region_dispose: " );
297 vips_object_print_name( VIPS_OBJECT( gobject ) );
298 VIPS_DEBUG_MSG( "\n" );
299 #endif /*VIPS_DEBUG*/
300
301 vips_object_preclose( VIPS_OBJECT( gobject ) );
302
303 /* Stop this sequence.
304 */
305 vips__region_stop( region );
306
307 /* Free any attached memory.
308 */
309 VIPS_FREEF( vips_window_unref, region->window );
310 VIPS_FREEF( vips_buffer_unref, region->buffer );
311
312 /* Detach from image.
313 */
314 VIPS_GATE_START( "vips_region_dispose: wait" );
315
316 g_mutex_lock( image->sslock );
317
318 VIPS_GATE_STOP( "vips_region_dispose: wait" );
319
320 image->regions = g_slist_remove( image->regions, region );
321
322 g_mutex_unlock( image->sslock );
323
324 region->im = NULL;
325
326 g_object_unref( image );
327
328 G_OBJECT_CLASS( vips_region_parent_class )->dispose( gobject );
329 }
330
331 static void
vips_region_dump(VipsObject * object,VipsBuf * buf)332 vips_region_dump( VipsObject *object, VipsBuf *buf )
333 {
334 VipsRegion *region = VIPS_REGION( object );
335
336 vips_buf_appendf( buf, "VipsRegion: %p, ", region );
337 vips_buf_appendf( buf, "im = %p, ", region->im );
338 vips_buf_appendf( buf, "valid.left = %d, ", region->valid.left );
339 vips_buf_appendf( buf, "valid.top = %d, ", region->valid.top );
340 vips_buf_appendf( buf, "valid.width = %d, ", region->valid.width );
341 vips_buf_appendf( buf, "valid.height = %d, ", region->valid.height );
342 vips_buf_appendf( buf, "type = %d, ", region->type );
343 vips_buf_appendf( buf, "data = %p, ", region->data );
344 vips_buf_appendf( buf, "bpl = %d, ", region->bpl );
345 vips_buf_appendf( buf, "seq = %p, ", region->seq );
346 vips_buf_appendf( buf, "thread = %p, ", region->thread );
347 vips_buf_appendf( buf, "window = %p, ", region->window );
348 vips_buf_appendf( buf, "buffer = %p, ", region->buffer );
349 vips_buf_appendf( buf, "invalid = %d", region->invalid );
350
351 VIPS_OBJECT_CLASS( vips_region_parent_class )->dump( object, buf );
352 }
353
354 static void
vips_region_summary(VipsObject * object,VipsBuf * buf)355 vips_region_summary( VipsObject *object, VipsBuf *buf )
356 {
357 VipsRegion *region = VIPS_REGION( object );
358
359 vips_buf_appendf( buf, "VipsRegion: %p, ", region );
360 vips_buf_appendf( buf, "im = %p, ", region->im );
361 vips_buf_appendf( buf, "left = %d, ", region->valid.left );
362 vips_buf_appendf( buf, "top = %d, ", region->valid.top );
363 vips_buf_appendf( buf, "width = %d, ", region->valid.width );
364 vips_buf_appendf( buf, "height = %d", region->valid.height );
365
366 if( region->buffer && region->buffer->buf )
367 vips_buf_appendf( buf, ", %.3gMB",
368 region->buffer->bsize / (1024 * 1024.0) );
369
370 VIPS_OBJECT_CLASS( vips_region_parent_class )->summary( object, buf );
371 }
372
373 /* If a region is being created in one thread (eg. the main thread) and then
374 * used in another (eg. a worker thread), the new thread needs to tell VIPS
375 * to stop sanity g_assert() fails. The previous owner needs to
376 * vips__region_no_ownership() before we can call this.
377 */
378 void
vips__region_take_ownership(VipsRegion * region)379 vips__region_take_ownership( VipsRegion *region )
380 {
381 /* Lock so that there's a memory barrier with the thread doing the
382 * vips__region_no_ownership() before us.
383 */
384 VIPS_GATE_START( "vips__region_take_ownership: wait" );
385
386 g_mutex_lock( region->im->sslock );
387
388 VIPS_GATE_STOP( "vips__region_take_ownership: wait" );
389
390 if( region->thread != g_thread_self() ) {
391 g_assert( region->thread == NULL );
392
393 /* We don't want to move shared buffers: the other region
394 * using this buffer will still be on the other thread.
395 * Not sure if this will ever happen: if it does, we'll
396 * need to dup the buffer.
397 */
398 g_assert( !region->buffer ||
399 region->buffer->ref_count == 1 );
400
401 region->thread = g_thread_self();
402 }
403
404 g_mutex_unlock( region->im->sslock );
405 }
406
407 void
vips__region_check_ownership(VipsRegion * region)408 vips__region_check_ownership( VipsRegion *region )
409 {
410 if( region->thread ) {
411 g_assert( region->thread == g_thread_self() );
412 if( region->buffer && region->buffer->cache )
413 g_assert( region->thread ==
414 region->buffer->cache->thread );
415 }
416 }
417
418 /* Call this from the relinquishing thread. Removes the buffer (if any) from
419 * this thread's buffer cache.
420 */
421 void
vips__region_no_ownership(VipsRegion * region)422 vips__region_no_ownership( VipsRegion *region )
423 {
424 VIPS_GATE_START( "vips__region_no_ownership: wait" );
425
426 g_mutex_lock( region->im->sslock );
427
428 VIPS_GATE_STOP( "vips__region_no_ownership: wait" );
429
430 vips__region_check_ownership( region );
431
432 region->thread = NULL;
433 if( region->buffer )
434 vips_buffer_undone( region->buffer );
435
436 g_mutex_unlock( region->im->sslock );
437 }
438
439 static int
vips_region_build(VipsObject * object)440 vips_region_build( VipsObject *object )
441 {
442 VipsRegion *region = VIPS_REGION( object );
443 VipsImage *image = region->im;
444
445 VIPS_DEBUG_MSG( "vips_region_build: %p\n", region );
446
447 if( VIPS_OBJECT_CLASS( vips_region_parent_class )->build( object ) )
448 return( -1 );
449
450 vips__region_take_ownership( region );
451
452 /* We're usually inside the ss lock anyway. But be safe ...
453 */
454 VIPS_GATE_START( "vips_region_build: wait" );
455
456 g_mutex_lock( image->sslock );
457
458 VIPS_GATE_STOP( "vips_region_build: wait" );
459
460 image->regions = g_slist_prepend( image->regions, region );
461
462 g_mutex_unlock( image->sslock );
463
464 return( 0 );
465 }
466
467 static void
vips_region_class_init(VipsRegionClass * class)468 vips_region_class_init( VipsRegionClass *class )
469 {
470 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
471 VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
472
473 gobject_class->finalize = vips_region_finalize;
474 gobject_class->dispose = vips_region_dispose;
475
476 vobject_class->summary = vips_region_summary;
477 vobject_class->dump = vips_region_dump;
478 vobject_class->build = vips_region_build;
479 }
480
481 static void
vips_region_init(VipsRegion * region)482 vips_region_init( VipsRegion *region )
483 {
484 region->type = VIPS_REGION_NONE;
485
486 #ifdef VIPS_DEBUG
487 g_mutex_lock( vips__global_lock );
488 vips__regions_all = g_slist_prepend( vips__regions_all, region );
489 printf( "vips_region_init: %d regions in vips\n",
490 g_slist_length( vips__regions_all ) );
491 g_mutex_unlock( vips__global_lock );
492 #endif /*VIPS_DEBUG*/
493 }
494
495 /**
496 * vips_region_new: (constructor)
497 * @image: image to create this region on
498 *
499 * Create a region. #VipsRegion s start out empty, you need to call
500 * vips_region_prepare() to fill them with pixels.
501 *
502 * See also: vips_region_prepare().
503 */
504 VipsRegion *
vips_region_new(VipsImage * image)505 vips_region_new( VipsImage *image )
506 {
507 VipsRegion *region;
508
509 /* Ref quickly, we want to make sure we keep the image around.
510 * We can't use the property system, we need to be very threaded.
511 */
512 g_object_ref( image );
513 g_assert( G_OBJECT( image )->ref_count > 1 );
514 g_assert( vips_object_sanity( VIPS_OBJECT( image ) ) );
515
516 region = VIPS_REGION( g_object_new( VIPS_TYPE_REGION, NULL ) );
517 region->im = image;
518
519 if( vips_object_build( VIPS_OBJECT( region ) ) ) {
520 VIPS_UNREF( region );
521 return( NULL );
522 }
523
524 g_assert( vips_object_sanity( VIPS_OBJECT( region ) ) );
525
526 return( region );
527 }
528
529 /* Region should be a pixel buffer. On return, check
530 * reg->buffer->done to see if there are pixels there already. Otherwise, you
531 * need to calculate.
532 */
533
534 /**
535 * vips_region_buffer: (method)
536 * @reg: region to operate upon
537 * @r: #VipsRect of pixels you need to be able to address
538 *
539 * The region is transformed so that at least @r pixels are available as a
540 * memory buffer that can be written to.
541 *
542 * Returns: 0 on success, or -1 for error.
543 */
544 int
vips_region_buffer(VipsRegion * reg,const VipsRect * r)545 vips_region_buffer( VipsRegion *reg, const VipsRect *r )
546 {
547 VipsImage *im = reg->im;
548
549 VipsRect image;
550 VipsRect clipped;
551
552 vips__region_check_ownership( reg );
553
554 /* Clip against image.
555 */
556 image.top = 0;
557 image.left = 0;
558 image.width = im->Xsize;
559 image.height = im->Ysize;
560 vips_rect_intersectrect( r, &image, &clipped );
561
562 /* Test for empty.
563 */
564 if( vips_rect_isempty( &clipped ) ) {
565 vips_error( "VipsRegion",
566 "%s", _( "valid clipped to nothing" ) );
567 return( -1 );
568 }
569
570 VIPS_FREEF( vips_window_unref, reg->window );
571
572 /* Have we been asked to drop caches? We want to throw everything
573 * away.
574 *
575 * If not, try to reuse the current buffer.
576 */
577 if( reg->invalid ) {
578 VIPS_FREEF( vips_buffer_unref, reg->buffer );
579 reg->invalid = FALSE;
580
581 if( !(reg->buffer = vips_buffer_new( im, &clipped )) )
582 return( -1 );
583 }
584 else {
585 /* We combine buffer unref and new buffer ref in one call
586 * to reduce malloc/free cycling.
587 */
588 if( !(reg->buffer =
589 vips_buffer_unref_ref( reg->buffer, im, &clipped )) )
590 return( -1 );
591 }
592
593 /* Init new stuff.
594 */
595 reg->valid = reg->buffer->area;
596 reg->bpl = VIPS_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width;
597 reg->type = VIPS_REGION_BUFFER;
598 reg->data = reg->buffer->buf;
599
600 return( 0 );
601 }
602
603 /**
604 * vips_region_image: (method)
605 * @reg: region to operate upon
606 * @r: #VipsRect of pixels you need to be able to address
607 *
608 * The region is transformed so that at least @r pixels are available to be
609 * read from the image. The image needs to be a memory buffer or represent a
610 * file on disc that has been mapped or can be mapped.
611 *
612 * Returns: 0 on success, or -1 for error.
613 */
614 int
vips_region_image(VipsRegion * reg,const VipsRect * r)615 vips_region_image( VipsRegion *reg, const VipsRect *r )
616 {
617 VipsImage *image = reg->im;
618
619 VipsRect all;
620 VipsRect clipped;
621
622 /* Sanity check.
623 */
624 vips__region_check_ownership( reg );
625
626 /* Clip against image.
627 */
628 all.top = 0;
629 all.left = 0;
630 all.width = image->Xsize;
631 all.height = image->Ysize;
632 vips_rect_intersectrect( r, &all, &clipped );
633
634 if( vips_rect_isempty( &clipped ) ) {
635 vips_error( "VipsRegion",
636 "%s", _( "valid clipped to nothing" ) );
637 return( -1 );
638 }
639
640 reg->invalid = FALSE;
641 VIPS_FREEF( vips_buffer_unref, reg->buffer );
642
643 if( image->data ) {
644 /* We have the whole image available ... easy!
645 */
646 VIPS_FREEF( vips_window_unref, reg->window );
647
648 /* We can't just set valid = whole image, since this may be an
649 * incompletely calculated memory buffer. Just set valid to r.
650 */
651 reg->valid = clipped;
652 reg->bpl = VIPS_IMAGE_SIZEOF_LINE( image );
653 reg->data = VIPS_IMAGE_ADDR( image, clipped.left, clipped.top );
654 reg->type = VIPS_REGION_OTHER_IMAGE;
655 }
656 else if( image->dtype == VIPS_IMAGE_OPENIN ) {
657 /* No complete image data ... but we can use a rolling window.
658 */
659 reg->type = VIPS_REGION_WINDOW;
660 if( !(reg->window = vips_window_take( reg->window, image,
661 clipped.top, clipped.height )) )
662 return( -1 );
663
664 /* Note the area the window actually represents.
665 */
666 reg->valid.left = 0;
667 reg->valid.top = reg->window->top;
668 reg->valid.width = image->Xsize;
669 reg->valid.height = reg->window->height;
670 reg->bpl = VIPS_IMAGE_SIZEOF_LINE( image );
671 reg->data = reg->window->data;
672 }
673 else {
674 VIPS_FREEF( vips_window_unref, reg->window );
675
676 vips_error( "VipsRegion", "%s", _( "bad image type" ) );
677 return( -1 );
678 }
679
680 return( 0 );
681 }
682
683 /**
684 * vips_region_region: (method)
685 * @reg: region to operate upon
686 * @dest: region to connect to
687 * @r: #VipsRect of pixels you need to be able to address
688 * @x: postion of @r in @dest
689 * @y: postion of @r in @dest
690 *
691 * Make VIPS_REGION_ADDR() on @reg go to @dest instead.
692 *
693 * @r is the part of @reg which you want to be able to address (this
694 * effectively becomes the valid field), (@x, @y) is the top LH corner of the
695 * corresponding area in @dest.
696 *
697 * Performs all clipping necessary to ensure that @reg->valid is indeed
698 * valid.
699 *
700 * If the region we attach to is moved or destroyed, we can be left with
701 * dangling pointers! If the region we attach to is on another image, the
702 * two images must have the same sizeof( pel ).
703 *
704 * Returns: 0 on success, or -1 for error.
705 */
706 int
vips_region_region(VipsRegion * reg,VipsRegion * dest,const VipsRect * r,int x,int y)707 vips_region_region( VipsRegion *reg,
708 VipsRegion *dest, const VipsRect *r, int x, int y )
709 {
710 VipsRect image;
711 VipsRect wanted;
712 VipsRect clipped;
713 VipsRect clipped2;
714 VipsRect final;
715
716 /* Sanity check.
717 */
718 if( !dest->data ) {
719 vips_error( "VipsRegion",
720 "%s", _( "no pixel data on attached image" ) );
721 return( -1 );
722 }
723 if( VIPS_IMAGE_SIZEOF_PEL( dest->im ) !=
724 VIPS_IMAGE_SIZEOF_PEL( reg->im ) ) {
725 vips_error( "VipsRegion",
726 "%s", _( "images do not match in pixel size" ) );
727 return( -1 );
728 }
729 vips__region_check_ownership( reg );
730
731 /* We can't test
732
733 g_assert( dest->thread == g_thread_self() );
734
735 * since we can have several threads writing to the same region in
736 * threadgroup.
737 */
738
739 /* Clip r against size of the image.
740 */
741 image.top = 0;
742 image.left = 0;
743 image.width = reg->im->Xsize;
744 image.height = reg->im->Ysize;
745 vips_rect_intersectrect( r, &image, &clipped );
746
747 /* Translate to dest's coordinate space and clip against the available
748 * pixels.
749 */
750 wanted.left = x + (clipped.left - r->left);
751 wanted.top = y + (clipped.top - r->top);
752 wanted.width = clipped.width;
753 wanted.height = clipped.height;
754
755 /* Test that dest->valid is large enough.
756 */
757 if( !vips_rect_includesrect( &dest->valid, &wanted ) ) {
758 vips_error( "VipsRegion",
759 "%s", _( "dest too small" ) );
760 return( -1 );
761 }
762
763 /* Clip against the available pixels.
764 */
765 vips_rect_intersectrect( &wanted, &dest->valid, &clipped2 );
766
767 /* Translate back to reg's coordinate space and set as valid.
768 */
769 final.left = r->left + (clipped2.left - wanted.left);
770 final.top = r->top + (clipped2.top - wanted.top);
771 final.width = clipped2.width;
772 final.height = clipped2.height;
773
774 /* Test for empty.
775 */
776 if( vips_rect_isempty( &final ) ) {
777 vips_error( "VipsRegion",
778 "%s", _( "valid clipped to nothing" ) );
779 return( -1 );
780 }
781
782 /* Init new stuff.
783 */
784 VIPS_FREEF( vips_buffer_unref, reg->buffer );
785 VIPS_FREEF( vips_window_unref, reg->window );
786 reg->invalid = FALSE;
787 reg->valid = final;
788 reg->bpl = dest->bpl;
789 reg->data = VIPS_REGION_ADDR( dest, clipped2.left, clipped2.top );
790 reg->type = VIPS_REGION_OTHER_REGION;
791
792 return( 0 );
793 }
794
795 /**
796 * vips_region_equalsregion:
797 * @reg1: region to test
798 * @reg2: region to test
799 *
800 * Do two regions point to the same piece of image? ie.
801 *
802 * |[
803 * VIPS_REGION_ADDR( reg1, x, y ) == VIPS_REGION_ADDR( reg2, x, y ) &&
804 * *VIPS_REGION_ADDR( reg1, x, y ) ==
805 * *VIPS_REGION_ADDR( reg2, x, y ) for all x, y, reg1, reg2.
806 * ]|
807 *
808 * Returns: non-zero on equality.
809 */
810 int
vips_region_equalsregion(VipsRegion * reg1,VipsRegion * reg2)811 vips_region_equalsregion( VipsRegion *reg1, VipsRegion *reg2 )
812 {
813 return( reg1->im == reg2->im &&
814 vips_rect_equalsrect( ®1->valid, ®2->valid ) &&
815 reg1->data == reg2->data );
816 }
817
818 /**
819 * vips_region_position: (method)
820 * @reg: region to operate upon
821 * @x: position to move to
822 * @y: position to move to
823 *
824 * Set the position of a region. This only affects reg->valid, ie. the way
825 * pixels are addressed, not reg->data, the pixels which are addressed. Clip
826 * against the size of the image. Do not allow negative positions, or
827 * positions outside the image.
828 *
829 * Returns: 0 on success, or -1 for error.
830 */
831 int
vips_region_position(VipsRegion * reg,int x,int y)832 vips_region_position( VipsRegion *reg, int x, int y )
833 {
834 VipsRect req, image, clipped;
835
836 /* Clip!
837 */
838 image.top = 0;
839 image.left = 0;
840 image.width = reg->im->Xsize;
841 image.height = reg->im->Ysize;
842 req.top = y;
843 req.left = x;
844 req.width = reg->valid.width;
845 req.height = reg->valid.height;
846 vips_rect_intersectrect( &image, &req, &clipped );
847 if( x < 0 || y < 0 || vips_rect_isempty( &clipped ) ) {
848 vips_error( "VipsRegion", "%s", _( "bad position" ) );
849 return( -1 );
850 }
851
852 reg->valid = clipped;
853 reg->invalid = FALSE;
854
855 return( 0 );
856 }
857
858 int
vips_region_fill(VipsRegion * reg,const VipsRect * r,VipsRegionFillFn fn,void * a)859 vips_region_fill( VipsRegion *reg,
860 const VipsRect *r, VipsRegionFillFn fn, void *a )
861 {
862 g_assert( reg->im->dtype == VIPS_IMAGE_PARTIAL );
863 g_assert( reg->im->generate_fn );
864
865 /* You'd think we could check reg and see if it already has some of
866 * the pixels we need. If it does, we could copy them and only
867 * generate the new ones.
868 *
869 * However, we usually have neighbouring regions on different threads,
870 * so from the point of view of this thread, we will get no overlaps
871 * on successive prepare requests.
872 */
873
874 /* Should have local memory.
875 */
876 if( vips_region_buffer( reg, r ) )
877 return( -1 );
878
879 /* Evaluate into or, if we've not got calculated pixels.
880 */
881 if( !reg->buffer->done ) {
882 if( fn( reg, a ) )
883 return( -1 );
884
885 /* Publish our results.
886 */
887 if( reg->buffer )
888 vips_buffer_done( reg->buffer );
889 }
890
891 return( 0 );
892 }
893
894 #define FILL_LINE( TYPE, Q, N, V ) { \
895 int x; \
896 TYPE *QT = (TYPE *) Q; \
897 \
898 for( x = 0; x < (N); x++ ) \
899 QT[x] = (V); \
900 }
901
902 /**
903 * vips_region_paint: (method)
904 * @reg: region to operate upon
905 * @r: area to paint
906 * @value: value to paint
907 *
908 * Paints @value into @reg covering rectangle @r.
909 * @r is clipped against
910 * @reg->valid.
911 *
912 * For int images, @value is
913 * passed to memset(), so it usually needs to be 0 or 255. For float images,
914 * value is cast to a float and copied in to each band element.
915 *
916 * @r is clipped against
917 * @reg->valid.
918 *
919 * See also: vips_region_black().
920 */
921 void
vips_region_paint(VipsRegion * reg,const VipsRect * r,int value)922 vips_region_paint( VipsRegion *reg, const VipsRect *r, int value )
923 {
924 VipsRect clipped;
925
926 vips_rect_intersectrect( r, ®->valid, &clipped );
927 if( !vips_rect_isempty( &clipped ) ) {
928 VipsPel *q = VIPS_REGION_ADDR( reg, clipped.left, clipped.top );
929 size_t ls = VIPS_REGION_LSKIP( reg );
930 size_t wd = clipped.width * VIPS_IMAGE_SIZEOF_PEL( reg->im );
931 int y;
932
933 if( vips_band_format_isint( reg->im->BandFmt ) ) {
934 for( y = 0; y < clipped.height; y++ ) {
935 memset( (char *) q, value, wd );
936 q += ls;
937 }
938 }
939 else {
940 gboolean iscomplex =
941 vips_band_format_iscomplex( reg->im->BandFmt );
942 int nele = clipped.width * reg->im->Bands *
943 (iscomplex ? 2 : 1);
944 VipsPel *q1;
945
946 switch( reg->im->BandFmt ) {
947 case VIPS_FORMAT_FLOAT:
948 case VIPS_FORMAT_COMPLEX:
949 FILL_LINE( float, q, nele, value );
950 break;
951
952 case VIPS_FORMAT_DOUBLE:
953 case VIPS_FORMAT_DPCOMPLEX:
954 FILL_LINE( double, q, nele, value );
955 break;
956
957 default:
958 g_assert_not_reached();
959 }
960
961 q1 = q + ls;
962
963 for( y = 1; y < clipped.height; y++ ) {
964 memcpy( (char *) q1, (char *) q, wd );
965 q1 += ls;
966 }
967 }
968 }
969 }
970
971 /**
972 * vips_region_paint_pel: (method)
973 * @reg: region to operate upon
974 * @r: area to paint
975 * @ink: value to paint
976 *
977 * Paints @ink into @reg covering rectangle @r. @r is clipped against
978 * @reg->valid.
979 *
980 * @ink should be a byte array of the same size as an image pixel containing
981 * the binary value to write into the pixels.
982 *
983 * See also: vips_region_paint().
984 */
985 void
vips_region_paint_pel(VipsRegion * reg,const VipsRect * r,const VipsPel * ink)986 vips_region_paint_pel( VipsRegion *reg, const VipsRect *r, const VipsPel *ink )
987 {
988 VipsRect ovl;
989
990 vips_rect_intersectrect( r, ®->valid, &ovl );
991 if( !vips_rect_isempty( &ovl ) ) {
992 int ps = VIPS_IMAGE_SIZEOF_PEL( reg->im );
993 int ws = ovl.width * ps;
994 int ls = VIPS_REGION_LSKIP( reg );
995
996 VipsPel *to, *q;
997 int x, y, z;
998
999 /* We plot the first line pointwise, then memcpy() it for the
1000 * subsequent lines.
1001 */
1002 to = VIPS_REGION_ADDR( reg, ovl.left, ovl.top );
1003
1004 q = to;
1005 for( x = 0; x < ovl.width; x++ ) {
1006 /* Faster than memcpy() for about n<20.
1007 */
1008 for( z = 0; z < ps; z++ )
1009 q[z] = ink[z];
1010
1011 q += ps;
1012 }
1013
1014 q = to + ls;
1015 for( y = 1; y < ovl.height; y++ ) {
1016 memcpy( q, to, ws );
1017 q += ls;
1018 }
1019 }
1020 }
1021
1022 /**
1023 * vips_region_black: (method)
1024 * @reg: region to operate upon
1025 *
1026 * Paints 0 into the valid part of @reg.
1027 *
1028 * See also: vips_region_paint().
1029 */
1030 void
vips_region_black(VipsRegion * reg)1031 vips_region_black( VipsRegion *reg )
1032 {
1033 vips_region_paint( reg, ®->valid, 0 );
1034 }
1035
1036 /**
1037 * vips_region_copy:
1038 * @reg: source region
1039 * @dest: (inout): destination region
1040 * @r: #VipsRect of pixels you need to copy
1041 * @x: postion of @r in @dest
1042 * @y: postion of @r in @dest
1043 *
1044 * Copy from one region to another. Copy area @r from inside @reg to @dest,
1045 * positioning the area of pixels at @x, @y. The two regions must have pixels
1046 * which are the same size.
1047 *
1048 * See also: vips_region_paint().
1049 */
1050 void
vips_region_copy(VipsRegion * reg,VipsRegion * dest,const VipsRect * r,int x,int y)1051 vips_region_copy( VipsRegion *reg,
1052 VipsRegion *dest, const VipsRect *r, int x, int y )
1053 {
1054 size_t len = VIPS_IMAGE_SIZEOF_PEL( reg->im ) * r->width;
1055 VipsPel *p = VIPS_REGION_ADDR( reg, r->left, r->top );
1056 VipsPel *q = VIPS_REGION_ADDR( dest, x, y );
1057 size_t plsk = VIPS_REGION_LSKIP( reg );
1058 size_t qlsk = VIPS_REGION_LSKIP( dest );
1059
1060 int z;
1061
1062 #ifdef DEBUG
1063 /* Find the area we will write to in dest.
1064 */
1065 VipsRect output;
1066
1067 printf( "vips_region_copy: sanity check\n" );
1068
1069 output.left = x;
1070 output.top = y;
1071 output.width = r->width;
1072 output.height = r->height;
1073
1074 /* Must be inside dest->valid.
1075 */
1076 g_assert( vips_rect_includesrect( &dest->valid, &output ) );
1077
1078 /* Check the area we are reading from in reg.
1079 */
1080 g_assert( vips_rect_includesrect( ®->valid, r ) );
1081
1082 /* VipsPel size must be the same.
1083 */
1084 g_assert( VIPS_IMAGE_SIZEOF_PEL( reg->im ) ==
1085 VIPS_IMAGE_SIZEOF_PEL( dest->im ) );
1086 #endif /*DEBUG*/
1087
1088 /* Copy the scanlines.
1089 *
1090 * Special case: if the two sets of scanlines are end-to-end (this
1091 * happens if we are copying complete regions) we can do a single
1092 * memcpy() for the whole thing. This is a little faster since we
1093 * won't have to do unaligned copies.
1094 */
1095 if( len == plsk &&
1096 len == qlsk )
1097 memcpy( q, p, len * r->height );
1098 else
1099 for( z = 0; z < r->height; z++ ) {
1100 memcpy( q, p, len );
1101
1102 p += plsk;
1103 q += qlsk;
1104 }
1105 }
1106
1107 /* Generate area @target in @to using pixels in @from.
1108 *
1109 * VIPS_CODING_LABQ only.
1110 */
1111 static void
vips_region_shrink_labpack(VipsRegion * from,VipsRegion * to,const VipsRect * target)1112 vips_region_shrink_labpack( VipsRegion *from,
1113 VipsRegion *to, const VipsRect *target )
1114 {
1115 int ls = VIPS_REGION_LSKIP( from );
1116
1117 int x, y;
1118
1119 for( y = 0; y < target->height; y++ ) {
1120 VipsPel *p = VIPS_REGION_ADDR( from,
1121 target->left * 2, (target->top + y) * 2 );
1122 VipsPel *q = VIPS_REGION_ADDR( to,
1123 target->left, target->top + y );
1124
1125 /* Ignore the extra bits for speed.
1126 */
1127 for( x = 0; x < target->width; x++ ) {
1128 signed char *sp = (signed char *) p;
1129 unsigned char *up = (unsigned char *) p;
1130
1131 int l = up[0] + up[4] +
1132 up[ls] + up[ls + 4];
1133 int a = sp[1] + sp[5] +
1134 sp[ls + 1] + sp[ls + 5];
1135 int b = sp[2] + sp[6] +
1136 sp[ls + 2] + sp[ls + 6];
1137
1138 q[0] = (l + 2) >> 2;
1139 q[1] = a >> 2;
1140 q[2] = b >> 2;
1141 q[3] = 0;
1142
1143 q += 4;
1144 p += 8;
1145 }
1146 }
1147 }
1148
1149 #define SHRINK_TYPE_MEAN_INT( TYPE ) \
1150 for( x = 0; x < target->width; x++ ) { \
1151 TYPE *tp = (TYPE *) p; \
1152 TYPE *tp1 = (TYPE *) (p + ls); \
1153 TYPE *tq = (TYPE *) q; \
1154 \
1155 for( z = 0; z < nb; z++ ) { \
1156 int tot = tp[z] + tp[z + nb] + \
1157 tp1[z] + tp1[z + nb]; \
1158 \
1159 tq[z] = (tot + 2) >> 2; \
1160 } \
1161 \
1162 /* Move on two pels in input. \
1163 */ \
1164 p += ps << 1; \
1165 q += ps; \
1166 }
1167
1168 #define SHRINK_TYPE_MEAN_FLOAT( TYPE ) \
1169 for( x = 0; x < target->width; x++ ) { \
1170 TYPE *tp = (TYPE *) p; \
1171 TYPE *tp1 = (TYPE *) (p + ls); \
1172 TYPE *tq = (TYPE *) q; \
1173 \
1174 for( z = 0; z < nb; z++ ) { \
1175 double tot = tp[z] + tp[z + nb] + \
1176 tp1[z] + tp1[z + nb]; \
1177 \
1178 tq[z] = tot / 4; \
1179 } \
1180 \
1181 /* Move on two pels in input. \
1182 */ \
1183 p += ps << 1; \
1184 q += ps; \
1185 }
1186
1187 /* Generate area @target in @to using pixels in @from. Non-complex.
1188 */
1189 static void
vips_region_shrink_uncoded_mean(VipsRegion * from,VipsRegion * to,const VipsRect * target)1190 vips_region_shrink_uncoded_mean( VipsRegion *from,
1191 VipsRegion *to, const VipsRect *target )
1192 {
1193 int ls = VIPS_REGION_LSKIP( from );
1194 int ps = VIPS_IMAGE_SIZEOF_PEL( from->im );
1195 int nb = from->im->Bands;
1196
1197 int x, y, z;
1198
1199 for( y = 0; y < target->height; y++ ) {
1200 VipsPel *p = VIPS_REGION_ADDR( from,
1201 target->left * 2, (target->top + y) * 2 );
1202 VipsPel *q = VIPS_REGION_ADDR( to,
1203 target->left, target->top + y );
1204
1205 /* Process this line of pels.
1206 */
1207 switch( from->im->BandFmt ) {
1208 case VIPS_FORMAT_UCHAR:
1209 SHRINK_TYPE_MEAN_INT( unsigned char ); break;
1210 case VIPS_FORMAT_CHAR:
1211 SHRINK_TYPE_MEAN_INT( signed char ); break;
1212 case VIPS_FORMAT_USHORT:
1213 SHRINK_TYPE_MEAN_INT( unsigned short ); break;
1214 case VIPS_FORMAT_SHORT:
1215 SHRINK_TYPE_MEAN_INT( signed short ); break;
1216 case VIPS_FORMAT_UINT:
1217 SHRINK_TYPE_MEAN_INT( unsigned int ); break;
1218 case VIPS_FORMAT_INT:
1219 SHRINK_TYPE_MEAN_INT( signed int ); break;
1220 case VIPS_FORMAT_FLOAT:
1221 SHRINK_TYPE_MEAN_FLOAT( float ); break;
1222 case VIPS_FORMAT_DOUBLE:
1223 SHRINK_TYPE_MEAN_FLOAT( double ); break;
1224
1225 default:
1226 g_assert_not_reached();
1227 }
1228 }
1229 }
1230
1231 /* This method is implemented so as to perform well and to always select an
1232 * output pixel from one of the input pixels. As such we make only the
1233 * following guarantees:
1234 *
1235 * ONLY works for non-complex uncoded images pixel types
1236 * ALWAYS draws from the input values
1237 * NEVER interpolates
1238 * NOT stable with respect to the ordered set of input values
1239 * IS stable with respect to the initial arrangement of input values
1240 */
1241 #define SHRINK_TYPE_MEDIAN( TYPE ) { \
1242 int ls = VIPS_REGION_LSKIP( from ); \
1243 \
1244 for( x = 0; x < target->width; x++ ) { \
1245 TYPE *tp = (TYPE *) p; \
1246 TYPE *tp1 = (TYPE *) (p + ls); \
1247 TYPE *tq = (TYPE *) q; \
1248 \
1249 for( z = 0; z < nb; z++ ) { \
1250 tq[z] = VIPS_MIN( \
1251 VIPS_MAX( tp[z], tp[z + nb] ), \
1252 VIPS_MAX( tp1[z], tp1[z + nb] ) \
1253 ); \
1254 } \
1255 \
1256 /* Move on two pels in input. \
1257 */ \
1258 p += ps << 1; \
1259 q += ps; \
1260 } \
1261 }
1262
1263 /* This method is implemented so as to perform well and to always select an
1264 * output pixel from one of the input pixels. As such we make only the
1265 * following guarantees:
1266 *
1267 * ONLY works for non-complex uncoded images pixel types
1268 * ALWAYS draws from the input values
1269 * NEVER interpolates
1270 * NOT stable with respect to the ordered set of input values
1271 * IS stable with respect to the initial arrangement of input values
1272 */
1273 #define SHRINK_TYPE_MODE( TYPE ) { \
1274 int ls = VIPS_REGION_LSKIP( from ); \
1275 \
1276 for( x = 0; x < target->width; x++ ) { \
1277 TYPE *tp = (TYPE *) p; \
1278 TYPE *tp1 = (TYPE *) (p + ls); \
1279 TYPE *tq = (TYPE *) q; \
1280 \
1281 for( z = 0; z < nb; z++ ) { \
1282 TYPE v[] = {tp[z], tp[z + nb], tp1[z], tp1[z + nb]}; \
1283 int b0 = (v[0] == v[1]) | \
1284 (v[0] == v[2]) | \
1285 (v[0] == v[3]); \
1286 int b1 = (v[1] == v[0]) | \
1287 (v[1] == v[2]) | \
1288 (v[1] == v[3]); \
1289 int index = ((~b0) & 0x1) + (~(b0 ^ b1) & 0x1); \
1290 \
1291 tq[z] = v[index]; \
1292 } \
1293 \
1294 p += ps << 1; \
1295 q += ps; \
1296 } \
1297 }
1298
1299 #define SHRINK_TYPE_MAX( TYPE ) { \
1300 int ls = VIPS_REGION_LSKIP( from ); \
1301 \
1302 for( x = 0; x < target->width; x++ ) { \
1303 TYPE *tp = (TYPE *) p; \
1304 TYPE *tp1 = (TYPE *) (p + ls); \
1305 TYPE *tq = (TYPE *) q; \
1306 \
1307 for( z = 0; z < nb; z++ ) { \
1308 tq[z] = VIPS_MAX( \
1309 VIPS_MAX( tp[z], tp[z + nb] ), \
1310 VIPS_MAX( tp1[z], tp1[z + nb] ) \
1311 ); \
1312 } \
1313 \
1314 p += ps << 1; \
1315 q += ps; \
1316 } \
1317 }
1318
1319 #define SHRINK_TYPE_MIN( TYPE ) { \
1320 int ls = VIPS_REGION_LSKIP( from ); \
1321 \
1322 for( x = 0; x < target->width; x++ ) { \
1323 TYPE *tp = (TYPE *) p; \
1324 TYPE *tp1 = (TYPE *) (p + ls); \
1325 TYPE *tq = (TYPE *) q; \
1326 \
1327 for( z = 0; z < nb; z++ ) { \
1328 tq[z] = VIPS_MIN( \
1329 VIPS_MIN( tp[z], tp[z + nb] ), \
1330 VIPS_MIN( tp1[z], tp1[z + nb] ) \
1331 ); \
1332 } \
1333 \
1334 p += ps << 1; \
1335 q += ps; \
1336 } \
1337 }
1338
1339 #define SHRINK_TYPE_NEAREST( TYPE ) { \
1340 for( x = 0; x < target->width; x++ ) { \
1341 TYPE *tp = (TYPE *) p; \
1342 TYPE *tq = (TYPE *) q; \
1343 \
1344 for( z = 0; z < nb; z++ ) \
1345 tq[z] = tp[z]; \
1346 \
1347 p += ps << 1; \
1348 q += ps; \
1349 } \
1350 }
1351
1352 #define VIPS_REGION_SHRINK( OP ) \
1353 static void \
1354 vips_region_shrink_uncoded_ ## OP( VipsRegion *from, \
1355 VipsRegion *to, const VipsRect *target ) \
1356 { \
1357 int ps = VIPS_IMAGE_SIZEOF_PEL( from->im ); \
1358 int nb = from->im->Bands; \
1359 \
1360 int x, y, z; \
1361 \
1362 for( y = 0; y < target->height; y++ ) { \
1363 VipsPel *p = VIPS_REGION_ADDR( from, \
1364 target->left * 2, (target->top + y) * 2 ); \
1365 VipsPel *q = VIPS_REGION_ADDR( to, \
1366 target->left, target->top + y ); \
1367 \
1368 /* Process this line of pels. \
1369 */ \
1370 switch( from->im->BandFmt ) { \
1371 case VIPS_FORMAT_UCHAR: \
1372 SHRINK_TYPE_ ## OP( unsigned char ); break; \
1373 case VIPS_FORMAT_CHAR: \
1374 SHRINK_TYPE_ ## OP( signed char ); break; \
1375 case VIPS_FORMAT_USHORT: \
1376 SHRINK_TYPE_ ## OP( unsigned short ); break; \
1377 case VIPS_FORMAT_SHORT: \
1378 SHRINK_TYPE_ ## OP( signed short ); break; \
1379 case VIPS_FORMAT_UINT: \
1380 SHRINK_TYPE_ ## OP( unsigned int ); break; \
1381 case VIPS_FORMAT_INT: \
1382 SHRINK_TYPE_ ## OP( signed int ); break; \
1383 case VIPS_FORMAT_FLOAT: \
1384 SHRINK_TYPE_ ## OP( float ); break; \
1385 case VIPS_FORMAT_DOUBLE: \
1386 SHRINK_TYPE_ ## OP( double ); break; \
1387 \
1388 default: \
1389 g_assert_not_reached(); \
1390 } \
1391 } \
1392 }
1393
1394 VIPS_REGION_SHRINK( MAX );
1395 VIPS_REGION_SHRINK( MIN );
1396 VIPS_REGION_SHRINK( MODE );
1397 VIPS_REGION_SHRINK( MEDIAN );
1398 VIPS_REGION_SHRINK( NEAREST );
1399
1400 /* Generate area @target in @to using pixels in @from. Non-complex.
1401 */
1402 static void
vips_region_shrink_uncoded(VipsRegion * from,VipsRegion * to,const VipsRect * target,VipsRegionShrink method)1403 vips_region_shrink_uncoded( VipsRegion *from,
1404 VipsRegion *to, const VipsRect *target, VipsRegionShrink method )
1405 {
1406 switch( method ) {
1407 case VIPS_REGION_SHRINK_MEAN:
1408 vips_region_shrink_uncoded_mean( from, to, target );
1409 break;
1410
1411 case VIPS_REGION_SHRINK_MEDIAN:
1412 vips_region_shrink_uncoded_MEDIAN( from, to, target );
1413 break;
1414
1415 case VIPS_REGION_SHRINK_MODE:
1416 vips_region_shrink_uncoded_MODE( from, to, target );
1417 break;
1418
1419 case VIPS_REGION_SHRINK_MAX:
1420 vips_region_shrink_uncoded_MAX( from, to, target );
1421 break;
1422
1423 case VIPS_REGION_SHRINK_MIN:
1424 vips_region_shrink_uncoded_MIN( from, to, target );
1425 break;
1426
1427 case VIPS_REGION_SHRINK_NEAREST:
1428 vips_region_shrink_uncoded_NEAREST( from, to, target );
1429 break;
1430
1431 default:
1432 g_assert_not_reached();
1433 }
1434 }
1435
1436 /* No point having an int path, this will always be horribly slow.
1437 */
1438 #define SHRINK_ALPHA_TYPE( TYPE ) { \
1439 TYPE *tp = (TYPE *) p; \
1440 TYPE *tp1 = (TYPE *) (p + ls); \
1441 TYPE *tq = (TYPE *) q; \
1442 \
1443 for( x = 0; x < target->width; x++ ) { \
1444 /* Make the input alphas. \
1445 */ \
1446 double a1 = tp[nb - 1]; \
1447 double a2 = tp[nb + nb - 1]; \
1448 double a3 = tp1[nb - 1]; \
1449 double a4 = tp1[nb + nb - 1]; \
1450 \
1451 /* Output alpha. \
1452 */ \
1453 double a = (a1 + a2 + a3 + a4) / 4.0; \
1454 \
1455 if( a == 0 ) { \
1456 for( z = 0; z < nb; z++ ) \
1457 tq[z] = 0; \
1458 } \
1459 else { \
1460 for( z = 0; z < nb - 1; z++ ) \
1461 tq[z] = (a1 * tp[z] + a2 * tp[z + nb] + \
1462 a3 * tp1[z] + a4 * tp1[z + nb]) / \
1463 (4.0 * a); \
1464 tq[z] = a; \
1465 } \
1466 \
1467 /* Move on two pels in input. \
1468 */ \
1469 tp += nb << 1; \
1470 tp1 += nb << 1; \
1471 tq += nb; \
1472 } \
1473 }
1474
1475 /* Generate area @target in @to using pixels in @from. Non-complex. Use the
1476 * last band as alpha.
1477 */
1478 static void
vips_region_shrink_alpha(VipsRegion * from,VipsRegion * to,const VipsRect * target)1479 vips_region_shrink_alpha( VipsRegion *from,
1480 VipsRegion *to, const VipsRect *target )
1481 {
1482 int ls = VIPS_REGION_LSKIP( from );
1483 int nb = from->im->Bands;
1484
1485 int x, y, z;
1486
1487 for( y = 0; y < target->height; y++ ) {
1488 VipsPel *p = VIPS_REGION_ADDR( from,
1489 target->left * 2, (target->top + y) * 2 );
1490 VipsPel *q = VIPS_REGION_ADDR( to,
1491 target->left, target->top + y );
1492
1493 /* Process this line of pels.
1494 */
1495 switch( from->im->BandFmt ) {
1496 case VIPS_FORMAT_UCHAR:
1497 SHRINK_ALPHA_TYPE( unsigned char ); break;
1498 case VIPS_FORMAT_CHAR:
1499 SHRINK_ALPHA_TYPE( signed char ); break;
1500 case VIPS_FORMAT_USHORT:
1501 SHRINK_ALPHA_TYPE( unsigned short ); break;
1502 case VIPS_FORMAT_SHORT:
1503 SHRINK_ALPHA_TYPE( signed short ); break;
1504 case VIPS_FORMAT_UINT:
1505 SHRINK_ALPHA_TYPE( unsigned int ); break;
1506 case VIPS_FORMAT_INT:
1507 SHRINK_ALPHA_TYPE( signed int ); break;
1508 case VIPS_FORMAT_FLOAT:
1509 SHRINK_ALPHA_TYPE( float ); break;
1510 case VIPS_FORMAT_DOUBLE:
1511 SHRINK_ALPHA_TYPE( double ); break;
1512
1513 default:
1514 g_assert_not_reached();
1515 }
1516 }
1517 }
1518
1519 /**
1520 * vips_region_shrink_method:
1521 * @from: source region
1522 * @to: (inout): destination region
1523 * @target: #VipsRect of pixels you need to copy
1524 * @method: method to use when generating target pixels
1525 *
1526 * Write the pixels @target in @to from the x2 larger area in @from.
1527 * Non-complex uncoded images and LABQ only. Images with alpha (see
1528 * vips_image_hasalpha()) shrink with pixels scaled by alpha to avoid fringing.
1529 *
1530 * @method selects the method used to do the 2x2 shrink.
1531 *
1532 * See also: vips_region_copy().
1533 */
1534 int
vips_region_shrink_method(VipsRegion * from,VipsRegion * to,const VipsRect * target,VipsRegionShrink method)1535 vips_region_shrink_method( VipsRegion *from, VipsRegion *to,
1536 const VipsRect *target, VipsRegionShrink method )
1537 {
1538 VipsImage *image = from->im;
1539
1540 if( vips_check_coding_noneorlabq( "vips_region_shrink_method", image ) )
1541 return( -1 );
1542
1543 if( from->im->Coding == VIPS_CODING_NONE ) {
1544 if( vips_check_noncomplex( "vips_region_shrink_method",
1545 image ) )
1546 return( -1 );
1547
1548 if( vips_image_hasalpha( image ) )
1549 vips_region_shrink_alpha( from, to, target );
1550 else
1551 vips_region_shrink_uncoded( from, to, target, method );
1552 }
1553 else
1554 vips_region_shrink_labpack( from, to, target );
1555
1556 return( 0 );
1557 }
1558
1559 /**
1560 * vips_region_shrink: (skip)
1561 * @from: source region
1562 * @to: (inout): destination region
1563 * @target: #VipsRect of pixels you need to copy
1564 *
1565 * Write the pixels @target in @to from the x2 larger area in @from.
1566 * Non-complex uncoded images and LABQ only. Images with alpha (see
1567 * vips_image_hasalpha()) shrink with pixels scaled by alpha to avoid fringing.
1568 *
1569 * This is a compatibility stub that just calls vips_region_shrink_method().
1570 *
1571 * See also: vips_region_shrink_method().
1572 */
1573 int
vips_region_shrink(VipsRegion * from,VipsRegion * to,const VipsRect * target)1574 vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target )
1575 {
1576 return( vips_region_shrink_method( from, to, target,
1577 VIPS_REGION_SHRINK_MEAN ) );
1578 }
1579
1580 /* Generate into a region.
1581 */
1582 static int
vips_region_generate(VipsRegion * reg,void * a)1583 vips_region_generate( VipsRegion *reg, void *a )
1584 {
1585 VipsImage *im = reg->im;
1586
1587 gboolean stop;
1588
1589 /* Start new sequence, if necessary.
1590 */
1591 if( vips__region_start( reg ) )
1592 return( -1 );
1593
1594 /* Ask for evaluation.
1595 */
1596 stop = FALSE;
1597 if( im->generate_fn( reg, reg->seq, im->client1, im->client2, &stop ) )
1598 return( -1 );
1599 if( stop ) {
1600 vips_error( "vips_region_generate",
1601 "%s", _( "stop requested" ) );
1602 return( -1 );
1603 }
1604
1605 return( 0 );
1606 }
1607
1608 /**
1609 * vips_region_prepare: (method)
1610 * @reg: region to prepare
1611 * @r: #VipsRect of pixels you need to be able to address
1612 *
1613 * vips_region_prepare() fills @reg with pixels. After calling,
1614 * you can address at least the area @r with VIPS_REGION_ADDR() and get
1615 * valid pixels.
1616 *
1617 * vips_region_prepare() runs in-line, that is, computation is done by
1618 * the calling thread, no new threads are involved, and computation
1619 * blocks until the pixels are ready.
1620 *
1621 * Use vips_sink_screen() to calculate an area of pixels in the
1622 * background.
1623 *
1624 * See also: vips_sink_screen(),
1625 * vips_region_prepare_to().
1626 *
1627 * Returns: 0 on success, or -1 on error.
1628 */
1629 int
vips_region_prepare(VipsRegion * reg,const VipsRect * r)1630 vips_region_prepare( VipsRegion *reg, const VipsRect *r )
1631 {
1632 VipsImage *im = reg->im;
1633
1634 VipsRect save = *r;
1635
1636 vips__region_check_ownership( reg );
1637
1638 if( vips_image_iskilled( im ) )
1639 return( -1 );
1640
1641 /* We use save for sanity checking valid: we test at the end that the
1642 * pixels we have generated are indeed all the ones that were asked
1643 * for.
1644 *
1645 * However, r may be clipped by the image size, so we need to clip
1646 * save as well to make sure we don't fail the assert due to that.
1647 */
1648 {
1649 VipsRect image;
1650
1651 image.left = 0;
1652 image.top = 0;
1653 image.width = reg->im->Xsize;
1654 image.height = reg->im->Ysize;
1655 vips_rect_intersectrect( &save, &image, &save );
1656 }
1657
1658 #ifdef DEBUG
1659 printf( "vips_region_prepare: "
1660 "left = %d, top = %d, width = %d, height = %d\n",
1661 r->left, r->top, r->width, r->height );
1662 #endif /*DEBUG*/
1663
1664 switch( im->dtype ) {
1665 case VIPS_IMAGE_PARTIAL:
1666 if( vips_region_fill( reg, r, vips_region_generate, NULL ) )
1667 return( -1 );
1668
1669 break;
1670
1671 case VIPS_IMAGE_SETBUF:
1672 case VIPS_IMAGE_SETBUF_FOREIGN:
1673 case VIPS_IMAGE_MMAPIN:
1674 case VIPS_IMAGE_MMAPINRW:
1675 case VIPS_IMAGE_OPENIN:
1676 /* Attach to existing buffer.
1677 */
1678 if( vips_region_image( reg, r ) )
1679 return( -1 );
1680
1681 break;
1682
1683 default:
1684 vips_error( "vips_region_prepare",
1685 _( "unable to input from a %s image" ),
1686 vips_enum_string( VIPS_TYPE_DEMAND_STYLE, im->dtype ) );
1687 return( -1 );
1688 }
1689
1690 /* valid should now include all the pixels that were asked for.
1691 */
1692 g_assert( vips_rect_includesrect( ®->valid, &save ) );
1693
1694 return( 0 );
1695 }
1696
1697 /* We need to make pixels using reg's generate function, and write the result
1698 * to dest.
1699 */
1700 static int
vips_region_prepare_to_generate(VipsRegion * reg,VipsRegion * dest,const VipsRect * r,int x,int y)1701 vips_region_prepare_to_generate( VipsRegion *reg,
1702 VipsRegion *dest, const VipsRect *r, int x, int y )
1703 {
1704 VipsImage *im = reg->im;
1705 VipsPel *p;
1706
1707 if( !im->generate_fn ) {
1708 vips_error( "vips_region_prepare_to",
1709 "%s", _( "incomplete header" ) );
1710 return( -1 );
1711 }
1712
1713 if( vips_region_region( reg, dest, r, x, y ) )
1714 return( -1 );
1715
1716 /* Remember where reg is pointing now.
1717 */
1718 p = VIPS_REGION_ADDR( reg, reg->valid.left, reg->valid.top );
1719
1720 /* Run sequence into reg.
1721 */
1722 if( vips_region_generate( reg, NULL ) )
1723 return( -1 );
1724
1725 /* The generate function may not have actually made any pixels ... it
1726 * might just have redirected reg to point somewhere else. If it has,
1727 * we need an extra copy operation.
1728 */
1729 if( VIPS_REGION_ADDR( reg, reg->valid.left, reg->valid.top ) != p )
1730 vips_region_copy( reg, dest, r, x, y );
1731
1732 return( 0 );
1733 }
1734
1735 /**
1736 * vips_region_prepare_to: (method)
1737 * @reg: region to prepare
1738 * @dest: (inout): region to write to
1739 * @r: #VipsRect of pixels you need to be able to address
1740 * @x: postion of @r in @dest
1741 * @y: postion of @r in @dest
1742 *
1743 * Like vips_region_prepare(): fill @reg with the pixels in area @r.
1744 *
1745 * Unlike vips_region_prepare(), rather than writing the result to @reg, the
1746 * pixels are written into @dest at offset @x, @y.
1747 *
1748 * Also unlike vips_region_prepare(), @dest is not set up for writing for
1749 * you with vips_region_buffer(). You can
1750 * point @dest at anything, and pixels really will be written there.
1751 * This makes vips_region_prepare_to() useful for making the ends of
1752 * pipelines.
1753 *
1754 * See also: vips_region_prepare(), vips_sink_disc().
1755 *
1756 * Returns: 0 on success, or -1 on error
1757 */
1758 int
vips_region_prepare_to(VipsRegion * reg,VipsRegion * dest,const VipsRect * r,int x,int y)1759 vips_region_prepare_to( VipsRegion *reg,
1760 VipsRegion *dest, const VipsRect *r, int x, int y )
1761 {
1762 VipsImage *im = reg->im;
1763 VipsRect image;
1764 VipsRect wanted;
1765 VipsRect clipped;
1766 VipsRect clipped2;
1767 VipsRect final;
1768
1769 if( vips_image_iskilled( im ) )
1770 return( -1 );
1771
1772 /* Sanity check.
1773 */
1774 if( !dest->data ||
1775 dest->im->BandFmt != reg->im->BandFmt ||
1776 dest->im->Bands != reg->im->Bands ) {
1777 vips_error( "vips_region_prepare_to",
1778 "%s", _( "inappropriate region type" ) );
1779 return( -1 );
1780 }
1781
1782 /* clip r first against the size of reg->im, then again against the
1783 * memory we have available to write to on dest. Just like
1784 * vips_region_region()
1785 */
1786 image.top = 0;
1787 image.left = 0;
1788 image.width = reg->im->Xsize;
1789 image.height = reg->im->Ysize;
1790 vips_rect_intersectrect( r, &image, &clipped );
1791
1792 g_assert( clipped.left == r->left );
1793 g_assert( clipped.top == r->top );
1794
1795 wanted.left = x + (clipped.left - r->left);
1796 wanted.top = y + (clipped.top - r->top);
1797 wanted.width = clipped.width;
1798 wanted.height = clipped.height;
1799
1800 /* Test that dest->valid is large enough.
1801 */
1802 if( !vips_rect_includesrect( &dest->valid, &wanted ) ) {
1803 vips_error( "vips_region_prepare_to",
1804 "%s", _( "dest too small" ) );
1805 return( -1 );
1806 }
1807
1808 vips_rect_intersectrect( &wanted, &dest->valid, &clipped2 );
1809
1810 /* Translate back to reg's coordinate space and set as valid.
1811 */
1812 final.left = r->left + (clipped2.left - wanted.left);
1813 final.top = r->top + (clipped2.top - wanted.top);
1814 final.width = clipped2.width;
1815 final.height = clipped2.height;
1816
1817 x = clipped2.left;
1818 y = clipped2.top;
1819
1820 if( vips_rect_isempty( &final ) ) {
1821 vips_error( "vips_region_prepare_to",
1822 "%s", _( "valid clipped to nothing" ) );
1823 return( -1 );
1824 }
1825
1826 #ifdef DEBUG
1827 printf( "vips_region_prepare_to: "
1828 "left = %d, top = %d, width = %d, height = %d\n",
1829 final.left, final.top, final.width, final.height );
1830 #endif /*DEBUG*/
1831
1832 /* Input or output image type?
1833 */
1834 switch( im->dtype ) {
1835 case VIPS_IMAGE_OPENOUT:
1836 case VIPS_IMAGE_PARTIAL:
1837 /* We are generating with a sequence.
1838 */
1839 if( vips_region_prepare_to_generate( reg, dest, &final, x, y ) )
1840 return( -1 );
1841
1842 break;
1843
1844 case VIPS_IMAGE_MMAPIN:
1845 case VIPS_IMAGE_MMAPINRW:
1846 case VIPS_IMAGE_OPENIN:
1847 /* Attach to existing buffer and copy to dest.
1848 */
1849 if( vips_region_image( reg, &final ) )
1850 return( -1 );
1851 vips_region_copy( reg, dest, &final, x, y );
1852
1853 break;
1854
1855 case VIPS_IMAGE_SETBUF:
1856 case VIPS_IMAGE_SETBUF_FOREIGN:
1857 /* Could be either input or output. If there is a generate
1858 * function, we are outputting.
1859 */
1860 if( im->generate_fn ) {
1861 if( vips_region_prepare_to_generate( reg,
1862 dest, &final, x, y ) )
1863 return( -1 );
1864 }
1865 else {
1866 if( vips_region_image( reg, &final ) )
1867 return( -1 );
1868 vips_region_copy( reg, dest, &final, x, y );
1869 }
1870
1871 break;
1872
1873 default:
1874 vips_error( "vips_region_prepare_to",
1875 _( "unable to input from a %s image" ),
1876 vips_enum_nick( VIPS_TYPE_DEMAND_STYLE, im->dtype ) );
1877 return( -1 );
1878 }
1879
1880 /* We've written fresh pixels to dest, it's no longer invalid (if it
1881 * was).
1882 *
1883 * We need this extra thing here because, unlike
1884 * vips_region_prepare(), we don't vips_region_buffer() dest before
1885 * writing it.
1886 */
1887 dest->invalid = FALSE;
1888
1889 return( 0 );
1890 }
1891
1892 /* Don't use this, use vips_reorder_prepare_many() instead.
1893 */
1894 int
vips_region_prepare_many(VipsRegion ** reg,const VipsRect * r)1895 vips_region_prepare_many( VipsRegion **reg, const VipsRect *r )
1896 {
1897 for( ; *reg; ++reg )
1898 if( vips_region_prepare( *reg, r ) )
1899 return( -1 );
1900
1901 return( 0 );
1902 }
1903
1904 /**
1905 * vips_region_fetch: (method)
1906 * @reg: region to fetch pixels from
1907 * @left: area of pixels to fetch
1908 * @top: area of pixels to fetch
1909 * @width: area of pixels to fetch
1910 * @height: area of pixels to fetch
1911 *
1912 * Generate an area of pixels and return a copy. The result must be freed
1913 * with g_free(). The requested area must be completely inside the image.
1914 *
1915 * This is equivalent to vips_region_prepare(), followed by a memcpy. It is
1916 * convenient for language bindings.
1917 *
1918 * Returns: A copy of the pixel data.
1919 */
1920 VipsPel *
vips_region_fetch(VipsRegion * region,int left,int top,int width,int height,size_t * len)1921 vips_region_fetch( VipsRegion *region,
1922 int left, int top, int width, int height, size_t *len )
1923 {
1924 VipsRect request;
1925 VipsRect image;
1926 int y;
1927 VipsPel *result;
1928 VipsPel *p, *q;
1929 size_t skip;
1930 size_t line;
1931
1932 g_assert( width > 0 );
1933 g_assert( height > 0 );
1934
1935 image.left = 0;
1936 image.top = 0;
1937 image.width = region->im->Xsize;
1938 image.height = region->im->Ysize;
1939 request.left = left;
1940 request.top = top;
1941 request.width = width;
1942 request.height = height;
1943 if( !vips_rect_includesrect( &image, &request ) )
1944 return( NULL );
1945 if( vips_region_prepare( region, &request ) )
1946 return( NULL );
1947
1948 skip = VIPS_REGION_LSKIP( region );
1949 line = VIPS_IMAGE_SIZEOF_PEL( region->im ) * request.width;
1950 if( !(result = (VipsPel *) vips_malloc( NULL, line * request.height )) )
1951 return( NULL );
1952
1953 p = VIPS_REGION_ADDR( region, request.left, request.top );
1954 q = result;
1955 for( y = 0; y < request.height; y++ ) {
1956 memcpy( q, p, line );
1957
1958 p += skip;
1959 q += line;
1960 }
1961
1962 if( len )
1963 *len = request.height * line;
1964
1965 return( result );
1966 }
1967
1968 /**
1969 * vips_region_width: (method)
1970 * @region: fetch width from this
1971 *
1972 * Returns: Width of the pixels held in region.
1973 */
1974 int
vips_region_width(VipsRegion * region)1975 vips_region_width( VipsRegion *region )
1976 {
1977 return( region->valid.width );
1978 }
1979
1980 /**
1981 * vips_region_height: (method)
1982 * @region: fetch height from this
1983 *
1984 * Returns: Height of the pixels held in region.
1985 */
1986 int
vips_region_height(VipsRegion * region)1987 vips_region_height( VipsRegion *region )
1988 {
1989 return( region->valid.height );
1990 }
1991
1992 /**
1993 * vips_region_invalidate: (method)
1994 * @reg: region to invalidate
1995 *
1996 * Mark a region as containing invalid pixels. Calling this function means
1997 * that the next time vips_region_prepare() is called, the region will be
1998 * recalculated.
1999 *
2000 * This is faster than calling vips_image_invalidate_all(), but obviously only
2001 * affects a single region.
2002 *
2003 * See also: vips_image_invalidate_all(), vips_region_prepare().
2004 */
2005 void
vips_region_invalidate(VipsRegion * reg)2006 vips_region_invalidate( VipsRegion *reg )
2007 {
2008 reg->invalid = TRUE;
2009 }
2010
2011 #ifdef VIPS_DEBUG
2012 static void *
vips_region_dump_all_cb(VipsRegion * region,size_t * alive,void * b)2013 vips_region_dump_all_cb( VipsRegion *region, size_t *alive, void *b )
2014 {
2015 char str[2048];
2016 VipsBuf buf = VIPS_BUF_STATIC( str );
2017
2018 vips_object_summary( VIPS_OBJECT( region ), &buf );
2019 printf( "%s\n", vips_buf_all( &buf ) );
2020
2021 if( region->buffer && region->buffer->buf )
2022 *alive += region->buffer->bsize;
2023
2024 return( NULL );
2025 }
2026
2027 void
vips_region_dump_all(void)2028 vips_region_dump_all( void )
2029 {
2030 size_t alive;
2031
2032 g_mutex_lock( vips__global_lock );
2033 alive = 0;
2034 printf( "%d regions in vips\n", g_slist_length( vips__regions_all ) );
2035 vips_slist_map2( vips__regions_all,
2036 (VipsSListMap2Fn) vips_region_dump_all_cb, &alive, NULL );
2037 printf( "%gMB alive\n", alive / (1024 * 1024.0) );
2038 g_mutex_unlock( vips__global_lock );
2039 }
2040 #endif /*VIPS_DEBUG*/
2041
2042 #ifdef DEBUG_LEAK
2043 void
vips__region_count_pixels(VipsRegion * region,const char * nickname)2044 vips__region_count_pixels( VipsRegion *region, const char *nickname )
2045 {
2046 VipsImage *image = region->im;
2047 VipsImagePixels *pixels = g_object_get_qdata( G_OBJECT( image ),
2048 vips__image_pixels_quark );
2049
2050 g_mutex_lock( vips__global_lock );
2051 if( !pixels->tpels )
2052 pixels->tpels = VIPS_IMAGE_N_PELS( image );
2053 if( !pixels->nickname )
2054 pixels->nickname = nickname;
2055 pixels->npels += region->valid.width * region->valid.height;
2056 g_mutex_unlock( vips__global_lock );
2057 }
2058 #endif /*DEBUG_LEAK*/
2059