#include "ruby_vips.h"
static ID id_perceptual, id_relative_colorimetric, id_saturation,
id_absolute_colorimetric;
/*
* call-seq:
* im.lab_to_lch -> image
*
* Turn Lab to LCh.
*/
VALUE
img_lab_to_lch(VALUE obj)
{
RUBY_VIPS_UNARY(im_Lab2LCh);
}
/*
* call-seq:
* im.lch_to_lab -> image
*
* Turn LCh to Lab.
*/
VALUE
img_lch_to_lab(VALUE obj)
{
RUBY_VIPS_UNARY(im_LCh2Lab);
}
/*
* call-seq:
* im.labq_to_xyz -> image
*
* Turn LabQ to XYZ.
*/
VALUE
img_labq_to_xyz(VALUE obj)
{
RUBY_VIPS_UNARY(im_LabQ2XYZ);
}
/*
* call-seq:
* im.rad_to_float -> image
*
* Unpack a RAD image to a three-band float image.
*/
VALUE
img_rad_to_float(VALUE obj)
{
RUBY_VIPS_UNARY(im_rad2float);
}
/*
* call-seq:
* im.float_to_rad -> image
*
* Convert a three-band float image to Radiance 32-bit packed format.
*/
VALUE
img_float_to_rad(VALUE obj)
{
RUBY_VIPS_UNARY(im_float2rad);
}
/*
* call-seq:
* im.lch_to_ucs -> image
*
* Turn LCh to UCS.
*/
VALUE
img_lch_to_ucs(VALUE obj)
{
RUBY_VIPS_UNARY(im_LCh2UCS);
}
/*
* call-seq:
* im.lab_to_labq -> image
*
* Turn Lab to LabQ.
*/
VALUE
img_lab_to_labq(VALUE obj)
{
RUBY_VIPS_UNARY(im_Lab2LabQ);
}
/*
* call-seq:
* im.lab_to_labs -> image
*
* Turn Lab to LabS.
*/
VALUE
img_lab_to_labs(VALUE obj)
{
RUBY_VIPS_UNARY(im_Lab2LabS);
}
/*
* call-seq:
* im.lab_to_xyz -> image
*
* Turn Lab to XYZ.
*/
VALUE
img_lab_to_xyz(VALUE obj)
{
RUBY_VIPS_UNARY(im_Lab2XYZ);
}
/*
* call-seq:
* im.lab_to_xyz_temp(x0, y0, z0) -> image
*
* Turn Lab to XYZ. x0, y0, z0 give the Lab colour
* temperature.
*/
VALUE
img_lab_to_xyz_temp(VALUE obj, VALUE x0, VALUE y0, VALUE z0)
{
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_Lab2XYZ_temp(im, im_new, NUM2DBL(x0), NUM2DBL(y0), NUM2DBL(z0)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.lab_to_ucs -> image
*
* Turn Lab to UCS.
*/
VALUE
img_lab_to_ucs(VALUE obj)
{
RUBY_VIPS_UNARY(im_Lab2UCS);
}
/*
* call-seq:
* im.labq_to_lab -> image
*
* Turn LabQ to Lab.
*/
VALUE
img_labq_to_lab(VALUE obj)
{
RUBY_VIPS_UNARY(im_LabQ2Lab);
}
/*
* call-seq:
* im.labq_to_labs -> image
*
* Turn LabQ to LabS.
*/
VALUE
img_labq_to_labs(VALUE obj)
{
RUBY_VIPS_UNARY(im_LabQ2LabS);
}
/*
* call-seq:
* im.labs_to_labq -> image
*
* Turn LabS to LabQ.
*/
VALUE
img_labs_to_labq(VALUE obj)
{
RUBY_VIPS_UNARY(im_LabS2LabQ);
}
/*
* call-seq:
* im.labs_to_lab -> image
*
* Turn LabS to Lab.
*/
VALUE
img_labs_to_lab(VALUE obj)
{
RUBY_VIPS_UNARY(im_LabS2Lab);
}
/*
* call-seq:
* im.ucs_to_xyz -> image
*
* Turn UCS to XYZ.
*/
VALUE
img_ucs_to_xyz(VALUE obj)
{
RUBY_VIPS_UNARY(im_UCS2XYZ);
}
/*
* call-seq:
* im.ucs_to_lch -> image
*
* Turn UCS to LCh.
*/
VALUE
img_ucs_to_lch(VALUE obj)
{
RUBY_VIPS_UNARY(im_UCS2LCh);
}
/*
* call-seq:
* im.ucs_to_lab -> image
*
* Turn UCS to Lab.
*/
VALUE
img_ucs_to_lab(VALUE obj)
{
RUBY_VIPS_UNARY(im_UCS2Lab);
}
/*
* call-seq:
* im.xyz_to_lab -> image
*
* Turn XYZ to Lab.
*/
VALUE
img_xyz_to_lab(VALUE obj)
{
RUBY_VIPS_UNARY(im_XYZ2Lab);
}
/*
* call-seq:
* im.xyz_to_lab_temp(x0, y0, z0) -> image
*
* Turn XYZ to LAB. x0, y0, z0 give the Lab colour
* temperature.
*/
VALUE
img_xyz_to_lab_temp(VALUE obj, VALUE x0, VALUE y0, VALUE z0)
{
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_XYZ2Lab_temp(im, im_new, NUM2DBL(x0), NUM2DBL(y0), NUM2DBL(z0)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.xyz_to_ucs -> image
*
* Turn XYZ to UCS.
*/
VALUE
img_xyz_to_ucs(VALUE obj)
{
RUBY_VIPS_UNARY(im_XYZ2UCS);
}
/*
* call-seq:
* im.srgb_to_xyz -> image
*
* Turn sRGB to XYZ.
*/
VALUE
img_srgb_to_xyz(VALUE obj)
{
RUBY_VIPS_UNARY(im_sRGB2XYZ);
}
/*
* call-seq:
* im.xyz_to_srgb -> image
*
* Turn XYZ to sRGB.
*/
VALUE
img_xyz_to_srgb(VALUE obj)
{
RUBY_VIPS_UNARY(im_XYZ2sRGB);
}
/*
* call-seq:
* im.yxy_to_xyz -> image
*
* Turn Yxy to XYZ.
*/
VALUE
img_yxy_to_xyz(VALUE obj)
{
RUBY_VIPS_UNARY(im_Yxy2XYZ);
}
/*
* call-seq:
* im.xyz_to_yxy -> image
*
* Turn XYZ to Yxy.
*/
VALUE
img_xyz_to_yxy(VALUE obj)
{
RUBY_VIPS_UNARY(im_XYZ2Yxy);
}
/*
* call-seq:
* im.decmc_from_lab(other_image) -> image
*
* Calculate dE CMC from two Lab images.
*/
VALUE
img_decmc_from_lab(VALUE obj, VALUE obj2)
{
RUBY_VIPS_BINARY(im_dECMC_fromLab);
}
/*
* call-seq:
* im.de00_from_lab(other_image) -> image
*
* Calculate CIE dE00 from two Lab images.
*/
VALUE
img_de00_from_lab(VALUE obj, VALUE obj2)
{
RUBY_VIPS_BINARY(im_dE00_fromLab);
}
/*
* call-seq:
* im.de_from_xyz(other_image) -> image
*
* Calculate CIELAB dE 1976 from a pair of XYZ images.
*/
VALUE
img_de_from_xyz(VALUE obj, VALUE obj2)
{
RUBY_VIPS_BINARY(im_dE_fromXYZ);
}
/*
* call-seq:
* im.de_from_lab(other_image) -> image
*
* Calculate CIE dE 1976 from two Lab images.
*/
VALUE
img_de_from_lab(VALUE obj, VALUE obj2)
{
RUBY_VIPS_BINARY(im_dE_fromLab);
}
/*
* call-seq:
* im.lab_morph(mask, l_offset, l_scale, a_scale, b_scale) -> image
*
* Morph an image in CIELAB colour space. Useful for certain types of gamut
* mapping, or correction of greyscales on some printers.
*
* We perform three adjustments.
*
* * cast
*
* Pass in mask containing CIELAB readings for a neutral greyscale.
* For example:
*
* mask = [
* [14.23, 4.8 , -3.95],
* [18.74, 2.76, -2.62],
* [23.46, 1.4 , -1.95],
* [27.46, 1.76, -2.01]
* ]
*
* Interpolation from this makes cast corrector. The top and tail are
* interpolated towards [0, 0, 0] and [100, 0, 0], intermediate values are
* interpolated along straight lines fitted between the specified points.
* Rows may be in any order (ie. they need not be sorted on L*).
*
* Each pixel is displaced in a/b by the amount specified for that L in the
* table.
*
* * L*
*
* Pass in l_scale and l_offset for L. L' = (L + offset) *
* scale.
*
* * saturation
*
* scale a and b by these amounts, eg. 1.5 increases saturation.
*
* Find the top two by generating and printing a greyscale. Find the bottom
* by printing a Macbeth and looking at a/b spread
*/
VALUE
img_lab_morph(VALUE obj, VALUE mask, VALUE l_offset, VALUE l_scale,
VALUE a_scale, VALUE b_scale)
{
DOUBLEMASK *dmask;
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
mask_arg2mask(mask, NULL, &dmask);
if( im_lab_morph(im, im_new, dmask, NUM2DBL(l_offset),
NUM2DBL(l_scale), NUM2DBL(a_scale), NUM2DBL(b_scale)) )
vips_lib_error();
return new;
}
VipsIntent
img_id_to_intent(ID rb)
{
if (rb == id_perceptual) return IM_INTENT_PERCEPTUAL;
else if (rb == id_relative_colorimetric) return IM_INTENT_RELATIVE_COLORIMETRIC;
else if (rb == id_saturation) return IM_INTENT_SATURATION;
else if (rb == id_absolute_colorimetric) return IM_INTENT_ABSOLUTE_COLORIMETRIC;
return (VipsIntent)NULL;
}
/*
* call-seq:
* im.icc_transform(input_filename, output_filename, intent) -> image
*
* Transform an image with the ICC library. The input image is moved to
* profile-connection space with the input profile and then to the output
* space with the output profile.
*
* Use Image#icc_import and Image#icc_export_depth to do either the first or
* second half of this operation in isolation.
*/
VALUE
img_icc_transform(VALUE obj, VALUE input_profile_filename,
VALUE output_profile_filename, VALUE intent)
{
ID id_intent = SYM2ID(intent);
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_icc_transform(im, im_new, StringValuePtr(input_profile_filename),
StringValuePtr(output_profile_filename), img_id_to_intent(id_intent)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.icc_import(input_filename, intent) -> image
*
* Import an image with the ICC library. The input image in device space
* is moved to D65 LAB with the input profile.
*/
VALUE
img_icc_import(VALUE obj, VALUE input_profile_filename, VALUE intent)
{
ID id_intent = SYM2ID(intent);
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_icc_import(im, im_new, StringValuePtr(input_profile_filename),
img_id_to_intent(id_intent)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.icc_import_embedded(intent) -> image
*
* Import an image with the ICC library. The input image in device space
* is moved to D65 LAB with the input profile from the input image header
* attached.
*/
VALUE
img_icc_import_embedded(VALUE obj, VALUE intent)
{
ID id_intent = SYM2ID(intent);
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_icc_import_embedded(im, im_new, img_id_to_intent(id_intent)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.icc_export_depth(depth, output_filename, intent) -> image
*
* Export an image with the ICC library. The input image in
* D65 LAB is transformed to device space using the supplied profile.
* depth can be 8 or 16, for 8 or 16-bit image export.
*/
VALUE
img_icc_export_depth(VALUE obj, VALUE depth, VALUE output_profile_filename,
VALUE intent)
{
ID id_intent = SYM2ID(intent);
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_icc_export_depth(im, im_new, NUM2INT(depth),
StringValuePtr(output_profile_filename), img_id_to_intent(id_intent)))
vips_lib_error();
return new;
}
/*
* call-seq:
* im.icc_ac2rc(depth, profile_filename) -> image
*
* Transform an image from absolute to relative colorimetry using the
* MediaWhitePoint stored in the ICC profile.
*/
VALUE
img_icc_ac2rc(VALUE obj, VALUE depth, VALUE profile_filename)
{
GetImg(obj, data, im);
OutImg(obj, new, data_new, im_new);
if (im_icc_ac2rc(im, im_new, StringValuePtr(profile_filename)))
vips_lib_error();
return new;
}
void
init_Image_colour()
{
id_perceptual = rb_intern("PERCEPTUAL");
id_relative_colorimetric = rb_intern("COLORIMETRIC");
id_saturation = rb_intern("SATURATION");
id_absolute_colorimetric = rb_intern("ABSOLUTE_COLORIMETRIC");
}