/** * im_region_region: * @reg: region to operate upon * @dest: region to connect to * @r: #Rect of pixels you need to be able to address * @x: postion of @r in @dest * @y: postion of @r in @dest * * Make IM_REGION_ADDR() on @reg go to @dest instead. * * @r is the part of @reg which you want to be able to address (this * effectively becomes the valid field), (@x, @y) is the top LH corner of the * corresponding area in @dest. * * Performs all clipping necessary to ensure that @reg->valid is indeed * valid. * * If the region we attach to is modified, we can be left with dangling * pointers! If the region we attach to is on another image, the two images * must have * the same sizeof( pel ). * * Returns: 0 on success, or -1 for error. */ int im_region_region( REGION *reg, REGION *dest, Rect *r, int x, int y ) { Rect image; Rect wanted; Rect clipped; Rect clipped2; Rect final; /* Sanity check. */ if( !dest->data || IM_IMAGE_SIZEOF_PEL( dest->im ) != IM_IMAGE_SIZEOF_PEL( reg->im ) ) { im_error( "im_region_region", "%s", _( "inappropriate region type" ) ); return( -1 ); } im__region_check_ownership( reg ); /* We can't test g_assert( dest->thread == g_thread_self() ); * since we can have several threads writing to the same region in * threadgroup. */ /* Clip r against size of the image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Translate to dest's coordinate space and clip against the available * pixels. */ wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if( !im_rect_includesrect( &dest->valid, &wanted ) ) { im_error( "im_region_region", "%s", _( "dest too small" ) ); return( -1 ); } /* Clip against the available pixels. */ im_rect_intersectrect( &wanted, &dest->valid, &clipped2 ); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left);
/** * im_region_buffer: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available as a * memory buffer. * * Returns: 0 on success, or -1 for error. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } /* Have we been asked to drop caches? We want to throw everything * away. * * If not, try to reuse the current buffer. */ if( reg->invalid ) { im_region_reset( reg ); if( !(reg->buffer = im_buffer_new( im, &clipped )) ) return( -1 ); } else { /* Don't call im_region_reset() ... we combine buffer unref * and new buffer ref in one call to reduce malloc/free * cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); } /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; return( 0 ); }
/* Call this from the relinquishing thread. Removes the buffer (if any) from * this thread's buffer cache. */ void im__region_no_ownership( REGION *reg ) { g_mutex_lock( reg->im->sslock ); im__region_check_ownership( reg ); reg->thread = NULL; if( reg->buffer ) im_buffer_undone( reg->buffer ); g_mutex_unlock( reg->im->sslock ); }
/* Region should be a pixel buffer. On return, check * reg->buffer->done to see if there are pixels there already. Otherwise, you * need to calculate. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", _( "valid clipped to nothing" ) ); return( -1 ); } /* Already have stuff? */ if( reg->type == IM_REGION_BUFFER && im_rect_includesrect( ®->valid, &clipped ) && reg->buffer && !reg->buffer->invalid ) return( 0 ); /* Don't call im_region_reset() ... we combine buffer unref and new * buffer ref in one call to reduce malloc/free cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; return( 0 ); }
/** * im_region_image: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available directly * from the image. The image needs to be a memory buffer or represent a file * on disc that has been mapped or can be mapped. * * Returns: 0 on success, or -1 for error. */ int im_region_image( REGION *reg, Rect *r ) { Rect image; Rect clipped; /* Sanity check. */ im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_image", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } if( reg->im->data ) { /* We have the whole image available ... easy! */ im_region_reset( reg ); /* We can't just set valid = clipped, since this may be an * incompletely calculated memory buffer. Just set valid to r. */ reg->valid = clipped; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->im->data + (gint64) clipped.top * IM_IMAGE_SIZEOF_LINE( reg->im ) + clipped.left * IM_IMAGE_SIZEOF_PEL( reg->im ); reg->type = IM_REGION_OTHER_IMAGE; } else if( reg->im->dtype == IM_OPENIN ) { /* No complete image data ... but we can use a rolling window. */ if( reg->type != IM_REGION_WINDOW || !reg->window || reg->window->top > clipped.top || reg->window->top + reg->window->height < clipped.top + clipped.height ) { im_region_reset( reg ); if( !(reg->window = im_window_ref( reg->im, clipped.top, clipped.height )) ) return( -1 ); reg->type = IM_REGION_WINDOW; } /* Note the area the window actually represents. */ reg->valid.left = 0; reg->valid.top = reg->window->top; reg->valid.width = reg->im->Xsize; reg->valid.height = reg->window->height; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->window->data; } else { im_error( "im_region_image", "%s", _( "bad image type" ) ); return( -1 ); } return( 0 ); }
/* Make REGION reg ready for input of area r. For most image types, we can * just im_attach, for PARTIAL though we may need to generate. */ int im_prepare( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect save = *r; im__region_check_ownership( reg ); if( im__test_kill( im ) ) return( -1 ); /* We use save for sanity checking valid: we test at the end that the * pixels we have generated are indeed all the ones that were asked * for. * * However, r may be clipped by the image size, so we need to clip * save as well to make sure we don't fail the assert due to that. */ { Rect image; image.left = 0; image.top = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( &save, &image, &save ); } #ifdef DEBUG printf( "im_prepare: left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height ); #endif /*DEBUG*/ switch( im->dtype ) { case IM_PARTIAL: if( im_region_fill( reg, r, (im_region_fill_fn) fill_region, NULL ) ) return( -1 ); break; case IM_SETBUF: case IM_SETBUF_FOREIGN: case IM_MMAPIN: case IM_MMAPINRW: case IM_OPENIN: /* Attach to existing buffer. */ if( im_region_image( reg, r ) ) return( -1 ); break; default: im_error( "im_prepare", _( "unable to input from a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } /* valid should now include all the pixels that were asked for. */ assert( im_rect_includesrect( ®->valid, &save ) ); return( 0 ); }