/* Print a one-line description of an image, with an index. */ static void * print_one_line( IMAGE *im, int *n, int *total ) { printf( "%2d) %p, %s, %s: %dx%d, %d bands, %s\n", *n, im, im_dtype2char( im->dtype ), im->filename, im->Xsize, im->Ysize, im->Bands, im_BandFmt2char( im->BandFmt ) ); *n += 1; if( im->dtype == IM_SETBUF && im->data ) { int size = IM_IMAGE_SIZEOF_LINE( im ) * im->Ysize; printf( "\t*** %d malloced bytes\n", size ); *total += size; } if( im->regions ) { int n2; int total2; printf( "\t%d regions\n", g_slist_length( im->regions ) ); n2 = 0; total2 = 0; (void) im_slist_map2( im->regions, (VSListMap2Fn) print_one_line_region, &n2, &total2 ); if( total2 ) printf( "\t*** using total of %d bytes\n", total2 ); *total += total2; } return( NULL ); }
/* Generate a region of pixels ... with threads! Very like im_prepare(), but * threaded and does sub-division. */ int im_prepare_thread( im_threadgroup_t *tg, REGION *or, Rect *r ) { IMAGE *im = or->im; g_assert( !im_image_sanity( im ) ); switch( im->dtype ) { case IM_PARTIAL: if( im_region_fill( or, r, (im_region_fill_fn) eval_to_region, tg ) ) return( -1 ); break; case IM_OPENIN: case IM_SETBUF: case IM_SETBUF_FOREIGN: case IM_MMAPIN: case IM_MMAPINRW: /* Attach to existing buffer. */ if( im_region_image( or, r ) ) return( -1 ); break; default: im_error( "im_prepare_thread", _( "unable to input from a %s " "image" ), im_dtype2char( im->dtype ) ); return( -1 ); } return( 0 ); }
/** * im_generate: * @im: generate this image * @start: start sequences with this function * @generate: generate pixels with this function * @stop: stop sequences with this function * @a: user data * @b: user data * * Generates an image. The action depends on the image type. * * For images opened with "p", im_generate() just attaches the * start/generate/stop callbacks and returns. * * For "t" images, memory is allocated for the whole image and it is entirely * generated using vips_sink(). * * For "w" images, memory for a few scanlines is allocated and * vips_sink_disc() used to generate the image in small chunks. As each * chunk is generated, it is written to disc. * * See also: vips_sink(), im_open(), im_prepare(), im_wrapone(). * * Returns: 0 on success, or -1 on error. */ int im_generate( IMAGE *im, im_start_fn start, im_generate_fn generate, im_stop_fn stop, void *a, void *b ) { int res; g_assert( !im_image_sanity( im ) ); if( !im->hint_set ) { im_error( "im_generate", "%s", _( "im_demand_hint() not set" ) ); return( -1 ); } if( im->Xsize <= 0 || im->Ysize <= 0 || im->Bands <= 0 ) { im_error( "im_generate", "%s", _( "bad dimensions" ) ); return( -1 ); } /* We don't use this, but make sure it's set in case any old binaries * are expectiing it. */ im->Bbits = im_bits_of_fmt( im->BandFmt ); /* Look at output type to decide our action. */ switch( im->dtype ) { case IM_PARTIAL: /* Output to partial image. Just attach functions and return. */ if( im->generate || im->start || im->stop ) { im_error( "im_generate", "%s", _( "func already attached" ) ); return( -1 ); } im->start = start; im->generate = generate; im->stop = stop; im->client1 = a; im->client2 = b; #ifdef DEBUG_IO printf( "im_generate: attaching partial callbacks\n" ); #endif /*DEBUG_IO*/ break; case IM_SETBUF: case IM_SETBUF_FOREIGN: case IM_MMAPINRW: case IM_OPENOUT: /* Eval now .. sanity check. */ if( im->generate || im->start || im->stop ) { im_error( "im_generate", "%s", _( "func already attached" ) ); return( -1 ); } /* Get output ready. */ if( im_setupout( im ) ) return( -1 ); /* Attach callbacks. */ im->start = start; im->generate = generate; im->stop = stop; im->client1 = a; im->client2 = b; if( im->dtype == IM_OPENOUT ) res = vips_sink_disc( im, (VipsRegionWrite) write_vips, NULL ); else res = vips_sink_memory( im ); /* Error? */ if( res ) return( -1 ); break; default: /* Not a known output style. */ im_error( "im_generate", _( "unable to output to a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } /* Successful write: trigger "written". */ if( im__trigger_callbacks( im->writtenfns ) ) 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 ); }
void im_printdesc( IMAGE *image ) { if( !image ) { printf( "NULL descriptor\n" ); return; } printf( "IMAGE* %p\n", image ); if( im_isMSBfirst( image ) ) printf( "SPARC (MSB first) " ); else printf( "Intel (LSB first) " ); printf( "byte order image, on a " ); if( im_amiMSBfirst() ) printf( "SPARC (MSB first) " ); else printf( "Intel (LSB first) " ); printf( "byte order machine\n" ); (void) im_header_map( image, (im_header_map_fn) print_field_fn, NULL ); printf( "Hist: %s", im_history_get( image ) ); /* Print other (non-header) fields. */ if( image->generate ) printf( "generate function attached\n" ); if( image->closefns ) printf( "close callbacks attached\n" ); if( image->evalfns ) printf( "eval callbacks attached\n" ); if( image->evalendfns ) printf( "evalend callbacks attached\n" ); if( image->evalstartfns ) printf( "evalstart callbacks attached\n" ); if( image->preclosefns ) printf( "preclose callbacks attached\n" ); if( image->invalidatefns ) printf( "invalidate callbacks attached\n" ); if( image->regions ) { printf( "%d regions present\n", g_slist_length( image->regions ) ); im_slist_map2( image->regions, (VSListMap2Fn) print_region, NULL, NULL ); } if( image->kill ) printf( "kill flag set\n" ); if( image->closing ) printf( "closing flag set\n" ); if( image->close_pending ) printf( "close_pending flag set\n" ); #ifdef DEBUG /* Can't get these with im_header_get(), so only show for debugging. */ printf( "dhint: %s\n", im_dhint2char( image->dhint ) ); printf( "dtype: %s\n", im_dtype2char( image->dtype ) ); #endif /*DEBUG*/ }
/* Attach a generate function to an image. */ int im_generate( IMAGE *im, im_start_fn start, im_generate_fn generate, im_stop_fn stop, void *a, void *b ) { int res; REGION *or; im_threadgroup_t *tg; g_assert( !im_image_sanity( im ) ); if( im->Xsize <= 0 || im->Ysize <= 0 || im->Bands <= 0 ) { im_error( "im_generate", _( "bad dimensions" ) ); return( -1 ); } /* Look at output type to decide our action. */ switch( im->dtype ) { case IM_PARTIAL: /* Output to partial image. Just attach functions and return. */ if( im->generate || im->start || im->stop ) { im_error( "im_generate", _( "func already attached" ) ); return( -1 ); } im->start = start; im->generate = generate; im->stop = stop; im->client1 = a; im->client2 = b; #ifdef DEBUG_IO printf( "im_generate: attaching partial callbacks\n" ); #endif /*DEBUG_IO*/ break; case IM_SETBUF: case IM_SETBUF_FOREIGN: case IM_MMAPINRW: case IM_OPENOUT: /* Eval now .. sanity check. */ if( im->generate || im->start || im->stop ) { im_error( "im_generate", _( "func already attached" ) ); return( -1 ); } /* Get output ready. */ if( im_setupout( im ) ) return( -1 ); /* Attach callbacks. */ im->start = start; im->generate = generate; im->stop = stop; im->client1 = a; im->client2 = b; /* Evaluate. Two output styles: to memory area (im_setbuf() * or im_mmapinrw()) or to file (im_openout()). */ if( !(or = im_region_create( im )) ) return( -1 ); if( !(tg = im_threadgroup_create( im )) ) { im_region_free( or ); return( -1 ); } if( im->dtype == IM_OPENOUT ) res = im_wbuffer( tg, write_vips, NULL, NULL ); else res = eval_to_memory( tg, or ); /* Clean up. */ im_threadgroup_free( tg ); im_region_free( or ); /* Error? */ if( res ) return( -1 ); break; default: /* Not a known output style. */ im_error( "im_generate", _( "unable to output to a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } return( 0 ); }