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( &reg1->valid, &reg2->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, &reg->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, &reg->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, &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( &reg->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( &reg->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