/** * im_copy_file: * @in: input image * @out: output image * * Copy an image to a disc file, then copy again to output. If the image is * already a disc file, just copy straight through. * * The disc file is allocated in the same way as im_system_image(). * The file is automatically deleted when @out is closed. * * See also: im_copy(), im_system_image(). * * Returns: 0 on success, -1 on error */ int im_copy_file( IMAGE *in, IMAGE *out ) { if( !im_isfile( in ) ) { IMAGE *disc; if( !(disc = im__open_temp( "%s.v" )) ) return( -1 ); if( im_add_close_callback( out, (im_callback_fn) im_close, disc, NULL ) ) { im_close( disc ); return( -1 ); } if( im_copy( in, disc ) || im_copy( disc, out ) ) return( -1 ); } else { if( im_copy( in, out ) ) return( -1 ); } return( 0 ); }
int im_flood_blob_copy( IMAGE *in, IMAGE *out, int x, int y, PEL *ink ) { IMAGE *t; if( !(t = im_open_local( out, "im_flood_blob_copy", "t" )) || im_copy( in, t ) || im_flood_blob( t, x, y, ink, NULL ) || im_copy( t, out ) ) return( -1 ); return( 0 ); }
int im_flood_other_copy( IMAGE *test, IMAGE *mark, IMAGE *out, int x, int y, int serial ) { IMAGE *t; if( !(t = im_open_local( out, "im_flood_other_copy", "t" )) || im_copy( mark, t ) || im_flood_other( test, t, x, y, serial, NULL ) || im_copy( t, out ) ) return( -1 ); return( 0 ); }
/** * im_shrink: * @in: input image * @out: output image * @xshrink: horizontal shrink * @yshrink: vertical shrink * * Shrink @in by a pair of factors with a simple box filter. * * You will get aliasing for non-integer shrinks. In this case, shrink with * this function to the nearest integer size above the target shrink, then * downsample to the exact size with im_affinei() and your choice of * interpolator. * * im_rightshift_size() is faster for factors which are integer powers of two. * * See also: im_rightshift_size(), im_affinei(). * * Returns: 0 on success, -1 on error */ int im_shrink( IMAGE *in, IMAGE *out, double xshrink, double yshrink ) { if( im_check_noncomplex( "im_shrink", in ) || im_check_coding_known( "im_shrink", in ) || im_piocheck( in, out ) ) return( -1 ); if( xshrink < 1.0 || yshrink < 1.0 ) { im_error( "im_shrink", "%s", _( "shrink factors should be >= 1" ) ); return( -1 ); } if( xshrink == 1 && yshrink == 1 ) { return( im_copy( in, out ) ); } else if( in->Coding == IM_CODING_LABQ ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "im_shrink:1", "p" ) || im_LabQ2LabS( in, t[0] ) || shrink( t[0], t[1], xshrink, yshrink ) || im_LabS2LabQ( t[1], out ) ) return( -1 ); } else if( shrink( in, out, xshrink, yshrink ) ) return( -1 ); return( 0 ); }
static int system_image_vec( im_object *argv ) { IMAGE *in = argv[0]; IMAGE *out = argv[1]; char *in_format = argv[2]; char *out_format = argv[3]; char *cmd = argv[4]; char **log = (char **) &argv[5]; IMAGE *out_image; if( !(out_image = im_system_image( in, in_format, out_format, cmd, log )) ) { im_error( "im_system_image", "%s", *log ); return( -1 ); } if( im_copy( out_image, out ) || im_add_close_callback( out, (im_callback_fn) im_close, out_image, NULL ) ) { im_close( out_image ); return( -1 ); } return( 0 ); }
int im_rotquad( IMAGE *in, IMAGE *out ) { IMAGE *t[6]; int xd = in->Xsize / 2; int yd = in->Ysize / 2; if( in->Xsize < 2 || in->Ysize < 2 ) return( im_copy( in, out ) ); if( im_open_local_array( out, t, 6, "im_rotquad-1", "p" ) || /* Extract 4 areas. */ im_extract_area( in, t[0], 0, 0, xd, yd ) || im_extract_area( in, t[1], xd, 0, in->Xsize - xd, yd ) || im_extract_area( in, t[2], 0, yd, xd, in->Ysize - yd ) || im_extract_area( in, t[3], xd, yd, in->Xsize - xd, in->Ysize - yd ) || /* Reassemble, rotated. */ im_insert( t[3], t[2], t[4], in->Xsize - xd, 0 ) || im_insert( t[1], t[0], t[5], in->Xsize - xd, 0 ) || im_insert( t[4], t[5], out, 0, in->Ysize - yd ) ) return( -1 ); out->Xoffset = xd; out->Yoffset = yd; return( 0 ); }
/** * im_system: * @im: image to run command on * @cmd: command to run * @out: stdout of command is returned here * * im_system() runs a command on an image, returning the command's output as a * string. The command is executed with popen(), the first '%%s' in the * command being substituted for a filename. * * If the IMAGE is a file on disc, then the filename will be the name of the * real file. If the image is in memory, or the result of a computation, * then a new file is created in the temporary area called something like * "vips_XXXXXX.v", and that filename given to the command. The file is * deleted when the command finishes. * * The environment variable TMPDIR can be used to set the temporary * directory. If it is not set, it defaults to "/tmp". * * In all cases, @log must be freed with im_free(). * * See also: im_system_image(). * * Returns: 0 on success, -1 on error */ int im_system( IMAGE *im, const char *cmd, char **out ) { FILE *fp; if( !im_isfile( im ) ) { IMAGE *disc; if( !(disc = im__open_temp( "%s.v" )) ) return( -1 ); if( im_copy( im, disc ) || im_system( disc, cmd, out ) ) { im_close( disc ); return( -1 ); } im_close( disc ); } else if( (fp = im_popenf( cmd, "r", im->filename )) ) { char line[IM_MAX_STRSIZE]; char txt[IM_MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); while( fgets( line, IM_MAX_STRSIZE, fp ) ) if( !vips_buf_appends( &buf, line ) ) break; pclose( fp ); if( out ) *out = im_strdup( NULL, vips_buf_all( &buf ) ); } return( 0 ); }
/** * im_copy_native: * @in: input image * @out: output image * @is_msb_first: %TRUE if @in is in most-significant first form * * Copy an image to native order, that is, the order for the executing * program. * * See also: im_copy_swap(), im_amiMSBfirst(). * * Returns: 0 on success, -1 on error. */ int im_copy_native( IMAGE *in, IMAGE *out, gboolean is_msb_first ) { if( is_msb_first != im_amiMSBfirst() ) return( im_copy_swap( in, out ) ); else return( im_copy( in, out ) ); }
/** * im_copy_set_meta: * @in: input image * @out: output image * @field: metadata field to set * @value: value to set for the field * * Copy an image, changing a metadata field. You can use this to, for example, * update the ICC profile attached to an image. * * See also: im_copy(). * * Returns: 0 on success, -1 on error. */ int im_copy_set_meta( IMAGE *in, IMAGE *out, const char *field, GValue *value ) { if( im_copy( in, out ) || im_meta_set( out, field, value ) ) return( 1 ); return( 0 ); }
/** * im_tone_map: * @in: input image * @out: output image * @lut: look-up table * * Map the first channel of @in through @lut. If @in is IM_CODING_LABQ, unpack * to LABS, map L and then repack. * * @in should be a LABS or LABQ image for this to work * sensibly. * * See also: im_maplut(). * * Returns: 0 on success, -1 on error */ int im_tone_map( IMAGE *in, IMAGE *out, IMAGE *lut ) { IMAGE *t[8]; if( im_check_hist( "im_tone_map", lut ) || im_open_local_array( out, t, 8, "im_tone_map", "p" ) ) return( -1 ); /* If in is IM_CODING_LABQ, unpack. */ if( in->Coding == IM_CODING_LABQ ) { if( im_LabQ2LabS( in, t[0] ) ) return( -1 ); } else t[0] = in; /* Split into bands. */ if( im_extract_band( t[0], t[1], 0 ) ) return( -1 ); if( t[0]->Bands > 1 ) { if( im_extract_bands( t[0], t[2], 1, t[0]->Bands - 1 ) ) return( -1 ); } /* Map L. */ if( im_maplut( t[1], t[3], lut ) ) return( -1 ); /* Recombine bands. */ if( t[0]->Bands > 1 ) { if( im_bandjoin( t[3], t[2], t[4] ) ) return( -1 ); } else t[4] = t[3]; /* If input was LabQ, repack. */ if( in->Coding == IM_CODING_LABQ ) { if( im_LabS2LabQ( t[4], t[5] ) ) return( -1 ); } else t[5] = t[4]; return( im_copy( t[4], out ) ); }
static VALUE writer_write_internal(VALUE obj, VALUE path) { VipsImage *out; GetImg(obj, data, im); if (!(out = im_open(StringValuePtr(path), "w")) || im_copy(im, out)) vips_lib_error(); im_close(out); return obj; }
/** * im_label_regions: * @test: image to test * @mask: write labelled regions here * @segments: return number of regions here * * im_label_regions() repeatedly scans @test for regions of 4-connected pixels * with the same pixel value. Every time a region is discovered, those * pixels are marked in @mask with a unique serial number. Once all pixels * have been labelled, the operation returns, setting @segments to the number * of discrete regions which were detected. * * @mask is always a 1-band %IM_BANDFMT_UINT image of the same dimensions as * @test. * * This operation is useful for, for example, blob counting. You can use the * morphological operators to detect and isolate a series of objects, then use * im_label_regions() to number them all. * * Use im_histindexed() to (for example) find blob coordinates. * * See also: im_histindexed() * * Returns: 0 on success, -1 on error. */ int im_label_regions( IMAGE *test, IMAGE *mask, int *segments ) { IMAGE *t[2]; int serial; int *m; int x, y; /* Create the zero mask image. */ if( im_open_local_array( mask, t, 2, "im_label_regions", "p" ) || im_black( t[0], test->Xsize, test->Ysize, 1 ) || im_clip2fmt( t[0], t[1], IM_BANDFMT_INT ) ) return( -1 ); /* Search the mask image, flooding as we find zero pixels. */ if( im_rwcheck( t[1] ) ) return( -1 ); serial = 0; m = (int *) t[1]->data; for( y = 0; y < test->Ysize; y++ ) { for( x = 0; x < test->Xsize; x++ ) { if( !m[x] ) { /* if( im_flood_other_old( t[1], test, x, y, serial ) ) */ if( im_flood_other( test, t[1], x, y, serial, NULL ) ) // if( im_flood_other_old( t[1], test, // x, y, serial ) ) return( -1 ); serial += 1; } } m += test->Xsize; } /* Copy result to mask. */ if( im_copy( t[1], mask ) ) return( -1 ); if( segments ) *segments = serial; return( 0 ); }
/* Normalise an image using the rules noted above. */ static int normalise( IMAGE *in, IMAGE *out ) { if( im_check_uncoded( "im_histplot", in ) || im_check_noncomplex( "im_histplot", in ) ) return( -1 ); if( vips_bandfmt_isuint( in->BandFmt ) ) { if( im_copy( in, out ) ) return( -1 ); } else if( vips_bandfmt_isint( in->BandFmt ) ) { IMAGE *t1; double min; /* Move min up to 0. */ if( !(t1 = im_open_local( out, "im_histplot", "p" )) || im_min( in, &min ) || im_lintra( 1.0, in, -min, t1 ) ) return( -1 ); } else { /* Float image: scale min--max to 0--any. Output square * graph. */ IMAGE *t1; DOUBLEMASK *stats; double min, max; int any; if( in->Xsize == 1 ) any = in->Ysize; else any = in->Xsize; if( !(stats = im_stats( in )) ) return( -1 ); min = VIPS_MASK( stats, 0, 0 ); max = VIPS_MASK( stats, 1, 0 ); im_free_dmask( stats ); if( !(t1 = im_open_local( out, "im_histplot", "p" )) || im_lintra( any / (max - min), in, -min * any / (max - min), out ) ) return( -1 ); } return( 0 ); }
static VALUE writer_initialize(int argc, VALUE *argv, VALUE obj) { VALUE image, opts; rb_scan_args(argc, argv, "11", &image, &opts); GetImg(image, data, im); GetImg(obj, data_new, im_new); img_add_dep(data_new, image); if (im_copy(im, im_new)) vips_lib_error(); return obj; }
int im_freqflt( IMAGE *in, IMAGE *mask, IMAGE *out ) { IMAGE *dummy; /* Placeholder for memory free. */ if( !(dummy = im_open( "memory-1", "p" )) ) return( -1 ); if( im_iscomplex( in ) ) { /* Easy case! Assume it has already been transformed. */ IMAGE *t1 = im_open_local( dummy, "im_freqflt-1", "p" ); if( !t1 || im_multiply( in, mask, t1 ) || im_invfftr( t1, out ) ) { im_close( dummy ); return( -1 ); } } else { /* Harder - fft first, then mult, then force back to start * type. * * Optimisation: output of im_invfft() is float buffer, we * will usually chagetype to char, so rather than keeping a * large float buffer and partial to char from that, do * changetype to a memory buffer, and copy to out from that. */ IMAGE *t[3]; IMAGE *t3; if( im_open_local_array( dummy, t, 3, "im_freqflt-1", "p" ) || !(t3 = im_open_local( out, "im_freqflt-3", "t" )) || im_fwfft( in, t[0] ) || im_multiply( t[0], mask, t[1] ) || im_invfftr( t[1], t[2] ) || im_clip2fmt( t[2], t3, in->BandFmt ) || im_copy( t3, out ) ) { im_close( dummy ); return( -1 ); } } im_close( dummy ); return( 0 ); }
/** * im_abs: * @in: input #IMAGE * @out: output #IMAGE * * This operation finds the absolute value of an image. It does a copy for * unsigned integer types, negate for negative values in * signed integer types, <function>fabs(3)</function> for * float types, and calculate modulus for complex * types. * * See also: im_exp10tra(), im_sign(). * * Returns: 0 on success, -1 on error */ int im_abs( IMAGE *in, IMAGE *out ) { if( im_piocheck( in, out ) || im_check_uncoded( "im_abs", in ) ) return( -1 ); /* Is this one of the unsigned types? Degenerate to im_copy() if it * is. */ if( vips_bandfmt_isuint( in->BandFmt ) ) return( im_copy( in, out ) ); /* Prepare output header. Output type == input type, except for * complex. */ if( im_cp_desc( out, in ) ) return( -1 ); switch( in->BandFmt ) { case IM_BANDFMT_CHAR: case IM_BANDFMT_SHORT: case IM_BANDFMT_INT: case IM_BANDFMT_FLOAT: case IM_BANDFMT_DOUBLE: /* No action. */ break; case IM_BANDFMT_COMPLEX: out->BandFmt = IM_BANDFMT_FLOAT; break; case IM_BANDFMT_DPCOMPLEX: out->BandFmt = IM_BANDFMT_DOUBLE; break; default: im_error( "im_abs", "%s", _( "unknown input type" ) ); return( -1 ); } /* Generate! */ if( im_wrapone( in, out, (im_wrapone_fn) abs_gen, in, NULL ) ) return( -1 ); return( 0 ); }
int im_copy_from( IMAGE *in, IMAGE *out, im_arch_type architecture ) { switch( architecture ) { case IM_ARCH_NATIVE: return( im_copy( in, out ) ); case IM_ARCH_BYTE_SWAPPED: return( im_copy_swap( in, out ) ); case IM_ARCH_LSB_FIRST: return( im_amiMSBfirst() ? im_copy_swap( in, out ) : im_copy( in, out ) ); case IM_ARCH_MSB_FIRST: return( im_amiMSBfirst() ? im_copy( in, out ) : im_copy_swap( in, out ) ); default: im_error( "im_copy_from", _( "bad architecture: %d" ), architecture ); return( -1 ); } }
static VALUE vips_write_internal(VALUE obj, VALUE path) { VipsImage *im_new; GetImg(obj, data, im); if (!(im_new = (VipsImage *)im_openout(RSTRING_PTR(path)))) vips_lib_error(); if (im_copy(im, im_new)) vips_lib_error(); im_close(im_new); return obj; }
/* Draw a set of lines with an ink and a mask. A non-inplace operation, handy * for nip2. */ int im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, int n, int *x1v, int *y1v, int *x2v, int *y2v ) { Rect mask_rect; int i; if( mask->Bands != 1 || mask->BandFmt != IM_BANDFMT_UCHAR || mask->Coding != IM_CODING_NONE ) { im_error( "im_lineset", "%s", _( "mask image not 1 band 8 bit uncoded" ) ); return( -1 ); } if( ink->Bands != in->Bands || ink->BandFmt != in->BandFmt || ink->Coding != in->Coding ) { im_error( "im_lineset", "%s", _( "ink image does not match in image" ) ); return( -1 ); } if( ink->Xsize != 1 || ink->Ysize != 1 ) { im_error( "im_lineset", "%s", _( "ink image not 1x1 pixels" ) ); return( -1 ); } /* Copy the image then fastline to it ... this will render to a "t" * usually. */ if( im_copy( in, out ) ) return( -1 ); mask_rect.left = mask->Xsize / 2; mask_rect.top = mask->Ysize / 2; mask_rect.width = mask->Xsize; mask_rect.height = mask->Ysize; if( im_incheck( ink ) || im_incheck( mask ) ) return( -1 ); for( i = 0; i < n; i++ ) { if( im_fastlineuser( out, x1v[i], y1v[i], x2v[i], y2v[i], im_plotmask, ink->data, mask->data, &mask_rect ) ) return( -1 ); } return( 0 ); }
/** * im_copy_swap: * @in: input image * @out: output image * * Copy an image, swapping byte order between little and big endian. This * really does change image pixels and does not just alter the header. * * See also: im_copy(), im_amiMSBfirst(), im_isMSBfirst(). * * Returns: 0 on success, -1 on error. */ int im_copy_swap( IMAGE *in, IMAGE *out ) { if( im_piocheck( in, out ) || im_check_uncoded( "im_copy_swap", in ) || im_cp_desc( out, in ) ) return( -1 ); switch( in->BandFmt ) { case IM_BANDFMT_CHAR: case IM_BANDFMT_UCHAR: if( im_copy( in, out ) ) return( -1 ); break; case IM_BANDFMT_SHORT: case IM_BANDFMT_USHORT: if( im_wrapone( in, out, (im_wrapone_fn) im_copy_swap2_gen, in, NULL ) ) return( -1 ); break; case IM_BANDFMT_INT: case IM_BANDFMT_UINT: case IM_BANDFMT_FLOAT: case IM_BANDFMT_COMPLEX: if( im_wrapone( in, out, (im_wrapone_fn) im_copy_swap4_gen, in, NULL ) ) return( -1 ); break; case IM_BANDFMT_DOUBLE: case IM_BANDFMT_DPCOMPLEX: if( im_wrapone( in, out, (im_wrapone_fn) im_copy_swap8_gen, in, NULL ) ) return( -1 ); break; default: im_error( "im_copy_swap", "%s", _( "unsupported image type" ) ); return( -1 ); } return( 0 ); }
/* Transform an n-band image with a 1-band processing function. */ int im__fftproc( IMAGE *dummy, IMAGE *in, IMAGE *out, im__fftproc_fn fn ) { if( im_pincheck( in ) || im_outcheck( out ) ) return( -1 ); if( in->Bands == 1 ) { if( fn( dummy, in, out ) ) return( -1 ); } else { IMAGE *acc; int b; for( acc = NULL, b = 0; b < in->Bands; b++ ) { IMAGE *t1 = im_open_local( dummy, "fwfftn:1", "p" ); IMAGE *t2 = im_open_local( dummy, "fwfftn:2", "p" ); if( !t1 || !t2 || im_extract_band( in, t1, b ) || fn( dummy, t1, t2 ) ) return( -1 ); if( !acc ) acc = t2; else { IMAGE *t3 = im_open_local( dummy, "fwfftn:3", "p" ); if( !t3 || im_bandjoin( acc, t2, t3 ) ) return( -1 ); acc = t3; } } if( im_copy( acc, out ) ) return( -1 ); } return( 0 ); }
/** * im_msb: * @in: input image * @out: output image * * Turn any integer image to 8-bit unsigned char by discarding all but the most * significant byte. * Signed values are converted to unsigned by adding 128. * * This operator also works for LABQ coding. * * See also: im_msb_band(). * * Returns: 0 on success, -1 on error */ int im_msb( IMAGE *in, IMAGE *out ) { Msb *msb; im_wrapone_fn func; if( in->Coding == IM_CODING_NONE && in->BandFmt == IM_BANDFMT_UCHAR ) return( im_copy( in, out ) ); if( im_piocheck( in, out ) || !(msb = IM_NEW( out, Msb )) ) return( -1 ); if( in->Coding == IM_CODING_NONE ) { if( im_check_int( "im_msb", in ) ) return( -1 ); msb->width = IM_IMAGE_SIZEOF_ELEMENT( in ); msb->index = im_amiMSBfirst() ? 0 : msb->width - 1; msb->repeat = in->Bands; if( vips_bandfmt_isuint( in->BandFmt ) ) func = (im_wrapone_fn) byte_select; else func = (im_wrapone_fn) byte_select_flip; } else if( IM_CODING_LABQ == in->Coding ) func = (im_wrapone_fn) msb_labq; else { im_error( "im_msb", "%s", _( "unknown coding" ) ); return( -1 ); } if( im_cp_desc( out, in ) ) return( -1 ); out->BandFmt = IM_BANDFMT_UCHAR; out->Coding = IM_CODING_NONE; return( im_wrapone( in, out, func, msb, NULL ) ); }
int im_msb (IMAGE * in, IMAGE * out) { #define FUNCTION_NAME "im_msb" size_t *params; im_wrapone_fn func; #define index (params[0]) #define width (params[1]) #define repeat (params[2]) if (im_piocheck (in, out)) return -1; /* Stops a used-before-set warning. */ params = NULL; if (IM_UNCODED (in)) { if (!IM_ANY_INT (in)) { im_error (FUNCTION_NAME, _("char, short or int only")); return -1; } params = IM_ARRAY (out, 3, size_t); if (!params) return -1; width = SIZEOF_BAND (in->BandFmt); #if G_BYTE_ORDER == G_BIG_ENDIAN index = 0; #else index = width - 1; #endif repeat = in->Bands; if (IM_UNSIGNED (in)) func = (im_wrapone_fn) byte_select; else func = (im_wrapone_fn) byte_select_flip; if (1 == width && (im_wrapone_fn) byte_select == func) { return im_copy (in, out); } } else if (IM_CODING_LABQ == in->Coding) func = (im_wrapone_fn) msb_labq; else { im_error (FUNCTION_NAME, _("unknown coding")); return -1; } if (im_cp_desc (out, in)) return -1; out->Bbits = sizeof (unsigned char) << 3; out->BandFmt = IM_BANDFMT_UCHAR; out->Coding = IM_CODING_NONE; return im_wrapone (in, out, func, (void *) params, NULL); #undef index #undef width #undef repeat #undef FUNCTION_NAME }
/* Use fftw2. */ static int invfft1( IMAGE *dummy, IMAGE *in, IMAGE *out ) { IMAGE *cmplx = im_open_local( dummy, "invfft1-1", "t" ); IMAGE *real = im_open_local( out, "invfft1-2", "t" ); const int half_width = in->Xsize / 2 + 1; /* Transform to halfcomplex here. */ double *half_complex = IM_ARRAY( dummy, in->Ysize * half_width * 2, double ); rfftwnd_plan plan; int x, y; double *q, *p; if( !cmplx || !real || !half_complex || im_pincheck( in ) || im_poutcheck( out ) ) return( -1 ); if( in->Coding != IM_CODING_NONE || in->Bands != 1 ) { im_error( "im_invfft", _( "one band uncoded only" ) ); return( -1 ); } /* Make dp complex image for input. */ if( im_clip2fmt( in, cmplx, IM_BANDFMT_DPCOMPLEX ) ) return( -1 ); /* Make mem buffer real image for output. */ if( im_cp_desc( real, in ) ) return( -1 ); real->BandFmt = IM_BANDFMT_DOUBLE; if( im_setupout( real ) ) return( -1 ); /* Build half-complex image. */ q = half_complex; for( y = 0; y < cmplx->Ysize; y++ ) { p = ((double *) cmplx->data) + y * in->Xsize * 2; for( x = 0; x < half_width; x++ ) { q[0] = p[0]; q[1] = p[1]; p += 2; q += 2; } } /* Make the plan for the transform. Yes, they really do use nx for * height and ny for width. */ if( !(plan = rfftw2d_create_plan( in->Ysize, in->Xsize, FFTW_BACKWARD, FFTW_MEASURE | FFTW_USE_WISDOM )) ) { im_error( "im_invfft", _( "unable to create transform plan" ) ); return( -1 ); } rfftwnd_one_complex_to_real( plan, (fftw_complex *) half_complex, (fftw_real *) real->data ); rfftwnd_destroy_plan( plan ); /* Copy to out. */ if( im_copy( real, out ) ) return( -1 ); return( 0 ); }
/* Convert to a saveable format. * * im__saveable_t gives the general type of image * we make: vanilla 1/3 bands (eg. PPM), with an optional alpha (eg. PNG), or * with CMYK as an option (eg. JPEG). * * format_table[] says how to convert each input format. * * Need to im_close() the result IMAGE. */ IMAGE * im__convert_saveable( IMAGE *in, im__saveable_t saveable, int format_table[10] ) { IMAGE *out; if( !(out = im_open( "convert-for-save", "p" )) ) return( NULL ); /* If this is an IM_CODING_LABQ, we can go straight to RGB. */ if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); static void *table = NULL; /* Make sure fast LabQ2disp tables are built. 7 is sRGB. */ if( !table ) table = im_LabQ2disp_build_table( NULL, im_col_displays( 7 ) ); if( !t || im_LabQ2disp_table( in, t, table ) ) { im_close( out ); return( NULL ); } in = t; } /* If this is an IM_CODING_RAD, we go to float RGB or XYZ. We should * probably un-gamma-correct the RGB :( */ if( in->Coding == IM_CODING_RAD ) { IMAGE *t; if( !(t = im_open_local( out, "conv:1", "p" )) || im_rad2float( in, t ) ) { im_close( out ); return( NULL ); } in = t; } /* Get the bands right. */ if( in->Coding == IM_CODING_NONE ) { if( in->Bands == 2 && saveable != IM__RGBA ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_band( in, t, 0 ) ) { im_close( out ); return( NULL ); } in = t; } else if( in->Bands > 3 && saveable == IM__RGB ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_bands( in, t, 0, 3 ) ) { im_close( out ); return( NULL ); } in = t; } else if( in->Bands > 4 && (saveable == IM__RGB_CMYK || saveable == IM__RGBA) ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_bands( in, t, 0, 4 ) ) { im_close( out ); return( NULL ); } in = t; } /* Else we have saveable IM__ANY and we don't chop bands down. */ } /* Interpret the Type field for colorimetric images. */ if( in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && in->Type == IM_TYPE_LABS ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabS2LabQ( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabQ2Lab( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding != IM_CODING_NONE ) { im_close( out ); return( NULL ); } if( in->Bands == 3 && in->Type == IM_TYPE_LCH ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_LCh2Lab( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_YXY ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Yxy2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_UCS ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_UCS2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_LAB ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Lab2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_XYZ ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_XYZ2disp( t[0], t[1], im_col_displays( 7 ) ) ) { im_close( out ); return( NULL ); } in = t[1]; } /* Cast to the output format. */ { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_clip2fmt( in, t, format_table[in->BandFmt] ) ) { im_close( out ); return( NULL ); } in = t; } if( im_copy( in, out ) ) { im_close( out ); return( NULL ); } return( out ); }
/* Call im_copy via arg vector. */ static int copy_vec( im_object *argv ) { return( im_copy( argv[0], argv[1] ) ); }
/* Make a mask image. */ static int build_freq_mask( IMAGE *out, int xs, int ys, ImMaskType flag, va_list ap ) { /* May be fewer than 4 args ... but extract them all anyway. Should be * safe. */ double p0 = va_arg( ap, double ); double p1 = va_arg( ap, double ); double p2 = va_arg( ap, double ); double p3 = va_arg( ap, double ); double p4 = va_arg( ap, double ); VipsImage *t; switch( flag ) { case IM_MASK_IDEAL_HIGHPASS: if( vips_mask_ideal( &t, xs, ys, p0, NULL ) ) return( -1 ); break; case IM_MASK_IDEAL_LOWPASS: if( vips_mask_ideal( &t, xs, ys, p0, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_HIGHPASS: if( vips_mask_butterworth( &t, xs, ys, p0, p1, p2, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_LOWPASS: if( vips_mask_butterworth( &t, xs, ys, p0, p1, p2, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_HIGHPASS: if( vips_mask_gaussian( &t, xs, ys, p0, p1, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_LOWPASS: if( vips_mask_gaussian( &t, xs, ys, p0, p1, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_IDEAL_RINGPASS: if( vips_mask_ideal_ring( &t, xs, ys, p0, p1, NULL ) ) return( -1 ); break; case IM_MASK_IDEAL_RINGREJECT: if( vips_mask_ideal_ring( &t, xs, ys, p0, p1, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_RINGPASS: if( vips_mask_butterworth_ring( &t, xs, ys, p0, p1, p2, p3, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_RINGREJECT: if( vips_mask_butterworth_ring( &t, xs, ys, p0, p1, p2, p3, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_RINGPASS: if( vips_mask_gaussian_ring( &t, xs, ys, p0, p1, p2, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_RINGREJECT: if( vips_mask_gaussian_ring( &t, xs, ys, p0, p1, p2, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_FRACTAL_FLT: if( vips_mask_fractal( &t, xs, ys, p0, NULL ) ) return( -1 ); break; case IM_MASK_IDEAL_BANDPASS: if( vips_mask_ideal_band( &t, xs, ys, p0, p1, p2, NULL ) ) return( -1 ); break; case IM_MASK_IDEAL_BANDREJECT: if( vips_mask_ideal_band( &t, xs, ys, p0, p1, p2, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_BANDPASS: if( vips_mask_butterworth_band( &t, xs, ys, p0, p1, p2, p3, p4, NULL ) ) return( -1 ); break; case IM_MASK_BUTTERWORTH_BANDREJECT: if( vips_mask_butterworth_band( &t, xs, ys, p0, p1, p2, p3, p4, "reject", TRUE, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_BANDPASS: if( vips_mask_gaussian_band( &t, xs, ys, p0, p1, p2, p3, NULL ) ) return( -1 ); break; case IM_MASK_GAUSS_BANDREJECT: if( vips_mask_gaussian_band( &t, xs, ys, p0, p1, p2, p3, "reject", TRUE, NULL ) ) return( -1 ); break; default: im_error( "im_freq_mask", "%s", _( "unimplemented mask type" ) ); return( -1 ); } if( im_copy( t, out ) ) { g_object_unref( t ); return( -1 ); } g_object_unref( t ); return( 0 ); }
int main (int argc, char **argv) { const int NTMPS = 3; VipsImage *in, *out; VipsImage *tmps[NTMPS]; INTMASK *mask; int stat; const char *ifile, *ofile; int extractTop = 100, extractBtm = 200; check(argc == 3, "Syntax: %s <input> <output>", argv[0]); ifile = argv[1]; ofile = argv[2]; timer_start(ifile, "Setup"); if (im_init_world (argv[0])) error_exit ("unable to start VIPS"); in = im_open( ifile, "r" ); if (!in) vips_error_exit( "unable to read %s", ifile ); check(in->Ysize > 5 && in->Xsize > 5, "Input image must be larger than 5 in both dimensions", extractBtm); stat = im_open_local_array(in, tmps, NTMPS, "tt", "p"); check(!stat, "Unable to create temps."); mask = mk_convmat(); timer_done(); /* Reduce the extraction size if it's bigger than the image. */ if (extractBtm + extractTop >= in->Ysize || extractBtm + extractTop >= in->Xsize) { extractTop = 2; extractBtm = 2; }/* if */ timer_start(ifile, "im_extract_area"); check( !im_extract_area(in, tmps[0], extractTop, extractTop, in->Xsize - extractBtm, in->Ysize - extractBtm), "extract failed."); timer_done(); timer_start(ifile, "im_affine"); check( !im_affine(tmps[0], tmps[1], 0.9, 0, 0, 0.9, 0, 0, 0, 0, in->Xsize * 0.9, in->Ysize * 0.9), "im_affine failed."); timer_done(); timer_start(ifile, "im_conv"); check( !im_conv (tmps[1], tmps[2], mask), "im_conv failed."); timer_done(); timer_start(ofile, "writing output"); out = im_open(ofile, "w"); check(!!out, "file output failed."); im_copy(tmps[2], out); timer_done(); timer_start(ofile, "teardown"); im_close(out); im_close(in); timer_done(); print_times(); return 0; }/* main */
/** * im_subsample: * @in: input image * @out: output image * @xshrink: horizontal shrink factor * @yshrink: vertical shrink factor * * Subsample an image by an integer fraction. This is fast nearest-neighbour * shrink. * * See also: im_shrink(), im_affinei(), im_zoom(). * * Returns: 0 on success, -1 on error. */ int im_subsample( IMAGE *in, IMAGE *out, int xshrink, int yshrink ) { SubsampleInfo *st; /* Check parameters. */ if( xshrink < 1 || yshrink < 1 ) { im_error( "im_subsample", "%s", _( "factors should both be >= 1" ) ); return( -1 ); } if( xshrink == 1 && yshrink == 1 ) return( im_copy( in, out ) ); if( im_piocheck( in, out ) || im_check_coding_known( "im_subsample", in ) ) return( -1 ); /* Prepare output. Note: we round the output width down! */ if( im_cp_desc( out, in ) ) return( -1 ); out->Xsize = in->Xsize / xshrink; out->Ysize = in->Ysize / yshrink; out->Xres = in->Xres / xshrink; out->Yres = in->Yres / yshrink; if( out->Xsize <= 0 || out->Ysize <= 0 ) { im_error( "im_subsample", "%s", _( "image has shrunk to nothing" ) ); return( -1 ); } /* Build and attach state struct. */ if( !(st = IM_NEW( out, SubsampleInfo )) ) return( -1 ); st->xshrink = xshrink; st->yshrink = yshrink; /* Set demand hints. We want THINSTRIP, as we will be demanding a * large area of input for each output line. */ if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) ) return( -1 ); /* Generate! If this is a very large shrink, then it's * probably faster to do it a pixel at a time. */ if( xshrink > 10 ) { if( im_generate( out, im_start_one, point_shrink_gen, im_stop_one, in, st ) ) return( -1 ); } else { if( im_generate( out, im_start_one, line_shrink_gen, im_stop_one, in, st ) ) return( -1 ); } return( 0 ); }
static int shrink_factor( IMAGE *in, IMAGE *out, int shrink, double residual, VipsInterpolate *interp ) { IMAGE *t[9]; VipsImage **s = (VipsImage **) vips_object_local_array( VIPS_OBJECT( out ), 1 ); IMAGE *x; int tile_width; int tile_height; int nlines; if( im_open_local_array( out, t, 9, "thumbnail", "p" ) ) return( -1 ); x = in; /* Unpack the two coded formats we support to float for processing. */ if( x->Coding == IM_CODING_LABQ ) { if( verbose ) printf( "unpacking LAB to RGB\n" ); if( im_LabQ2disp( x, t[1], im_col_displays( 7 ) ) ) return( -1 ); x = t[1]; } else if( x->Coding == IM_CODING_RAD ) { if( verbose ) printf( "unpacking Rad to float\n" ); if( im_rad2float( x, t[1] ) ) return( -1 ); x = t[1]; } if( im_shrink( x, t[2], shrink, shrink ) ) return( -1 ); /* We want to make sure we read the image sequentially. * However, the convolution we may be doing later will force us * into SMALLTILE or maybe FATSTRIP mode and that will break * sequentiality. * * So ... read into a cache where tiles are scanlines, and make sure * we keep enough scanlines to be able to serve a line of tiles. */ vips_get_tile_size( t[2], &tile_width, &tile_height, &nlines ); if( vips_tilecache( t[2], &s[0], "tile_width", t[2]->Xsize, "tile_height", 10, "max_tiles", (nlines * 2) / 10, "strategy", VIPS_CACHE_SEQUENTIAL, NULL ) || im_affinei_all( s[0], t[4], interp, residual, 0, 0, residual, 0, 0 ) ) return( -1 ); x = t[4]; /* If we are upsampling, don't sharpen, since nearest looks dumb * sharpened. */ if( shrink > 1 && residual <= 1.0 && !nosharpen ) { if( verbose ) printf( "sharpening thumbnail\n" ); if( im_conv( x, t[5], sharpen_filter() ) ) return( -1 ); x = t[5]; } /* Colour management: we can transform the image if we have an output * profile and an input profile. The input profile can be in the * image, or if there is no profile there, supplied by the user. */ if( export_profile && (im_header_get_typeof( x, IM_META_ICC_NAME ) || import_profile) ) { if( im_header_get_typeof( x, IM_META_ICC_NAME ) ) { if( verbose ) printf( "importing with embedded profile\n" ); if( im_icc_import_embedded( x, t[6], IM_INTENT_RELATIVE_COLORIMETRIC ) ) return( -1 ); } else { if( verbose ) printf( "importing with profile %s\n", import_profile ); if( im_icc_import( x, t[6], import_profile, IM_INTENT_RELATIVE_COLORIMETRIC ) ) return( -1 ); } if( verbose ) printf( "exporting with profile %s\n", export_profile ); if( im_icc_export_depth( t[6], t[7], 8, export_profile, IM_INTENT_RELATIVE_COLORIMETRIC ) ) return( -1 ); x = t[7]; } if( delete_profile ) { if( verbose ) printf( "deleting profile from output image\n" ); if( im_meta_get_typeof( x, IM_META_ICC_NAME ) && !im_meta_remove( x, IM_META_ICC_NAME ) ) return( -1 ); } if( im_copy( x, out ) ) return( -1 ); return( 0 ); }