| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- #include <stdlib.h>
- #include <string.h>
- #include <vips/vips.h>
- #include <vips/foreign.h>
- #include <vips/vips7compat.h>
- /**
- * Starting libvips 7.41, VIPS_ANGLE_x has been renamed to VIPS_ANGLE_Dx
- * "to help python". So we provide the macro to correctly build for versions
- * before 7.41.x.
- * https://github.com/jcupitt/libvips/blob/master/ChangeLog#L128
- */
- #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
- #define VIPS_ANGLE_D0 VIPS_ANGLE_0
- #define VIPS_ANGLE_D90 VIPS_ANGLE_90
- #define VIPS_ANGLE_D180 VIPS_ANGLE_180
- #define VIPS_ANGLE_D270 VIPS_ANGLE_270
- #endif
- #define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"
- enum types {
- UNKNOWN = 0,
- JPEG,
- WEBP,
- PNG,
- TIFF,
- GIF,
- PDF,
- SVG,
- MAGICK
- };
- typedef struct {
- const char *Text;
- const char *Font;
- } WatermarkTextOptions;
- typedef struct {
- int Width;
- int DPI;
- int Margin;
- int NoReplicate;
- float Opacity;
- double Background[3];
- } WatermarkOptions;
- typedef struct {
- int Left;
- int Top;
- float Opacity;
- } WatermarkImageOptions;
- static unsigned long
- has_profile_embed(VipsImage *image) {
- return vips_image_get_typeof(image, VIPS_META_ICC_NAME);
- }
- static void
- remove_profile(VipsImage *image) {
- vips_image_remove(image, VIPS_META_ICC_NAME);
- }
- static gboolean
- with_interlace(int interlace) {
- return interlace > 0 ? TRUE : FALSE;
- }
- static int
- has_alpha_channel(VipsImage *image) {
- return (
- (image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
- (image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
- (image->Bands == 5 && image->Type == VIPS_INTERPRETATION_CMYK)
- ) ? 1 : 0;
- }
- /**
- * This method is here to handle the weird initialization of the vips lib.
- * libvips use a macro VIPS_INIT() that call vips__init() in version < 7.41,
- * or calls vips_init() in version >= 7.41.
- *
- * Anyway, it's not possible to build bimg on Debian Jessie with libvips 7.40.x,
- * as vips_init() is a macro to VIPS_INIT(), which is also a macro, hence, cgo
- * is unable to determine the return type of vips_init(), making the build impossible.
- * In order to correctly build bimg, for version < 7.41, we should undef vips_init and
- * creates a vips_init() method that calls VIPS_INIT().
- */
- #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
- #undef vips_init
- int
- vips_init(const char *argv0)
- {
- return VIPS_INIT(argv0);
- }
- #endif
- void
- vips_enable_cache_set_trace() {
- vips_cache_set_trace(TRUE);
- }
- int
- vips_affine_interpolator(VipsImage *in, VipsImage **out, double a, double b, double c, double d, VipsInterpolate *interpolator) {
- return vips_affine(in, out, a, b, c, d, "interpolate", interpolator, NULL);
- }
- int
- vips_jpegload_buffer_shrink(void *buf, size_t len, VipsImage **out, int shrink) {
- return vips_jpegload_buffer(buf, len, out, "shrink", shrink, NULL);
- }
- int
- vips_flip_bridge(VipsImage *in, VipsImage **out, int direction) {
- return vips_flip(in, out, direction, NULL);
- }
- int
- vips_shrink_bridge(VipsImage *in, VipsImage **out, double xshrink, double yshrink) {
- return vips_shrink(in, out, xshrink, yshrink, NULL);
- }
- int
- vips_type_find_bridge(int t) {
- if (t == GIF) {
- return vips_type_find("VipsOperation", "gifload");
- }
- if (t == PDF) {
- return vips_type_find("VipsOperation", "pdfload");
- }
- if (t == TIFF) {
- return vips_type_find("VipsOperation", "tiffload");
- }
- if (t == SVG) {
- return vips_type_find("VipsOperation", "svgload");
- }
- if (t == WEBP) {
- return vips_type_find("VipsOperation", "webpload");
- }
- if (t == PNG) {
- return vips_type_find("VipsOperation", "pngload");
- }
- if (t == JPEG) {
- return vips_type_find("VipsOperation", "jpegload");
- }
- if (t == MAGICK) {
- return vips_type_find("VipsOperation", "magickload");
- }
- return 0;
- }
- int
- vips_type_find_save_bridge(int t) {
- if (t == TIFF) {
- return vips_type_find("VipsOperation", "tiffsave_buffer");
- }
- if (t == WEBP) {
- return vips_type_find("VipsOperation", "webpsave_buffer");
- }
- if (t == PNG) {
- return vips_type_find("VipsOperation", "pngsave_buffer");
- }
- if (t == JPEG) {
- return vips_type_find("VipsOperation", "jpegsave_buffer");
- }
- return 0;
- }
- int
- vips_rotate(VipsImage *in, VipsImage **out, int angle) {
- int rotate = VIPS_ANGLE_D0;
- angle %= 360;
- if (angle == 45) {
- rotate = VIPS_ANGLE45_D45;
- } else if (angle == 90) {
- rotate = VIPS_ANGLE_D90;
- } else if (angle == 135) {
- rotate = VIPS_ANGLE45_D135;
- } else if (angle == 180) {
- rotate = VIPS_ANGLE_D180;
- } else if (angle == 225) {
- rotate = VIPS_ANGLE45_D225;
- } else if (angle == 270) {
- rotate = VIPS_ANGLE_D270;
- } else if (angle == 315) {
- rotate = VIPS_ANGLE45_D315;
- } else {
- angle = 0;
- }
- if (angle > 0 && angle % 90 != 0) {
- return vips_rot45(in, out, "angle", rotate, NULL);
- } else {
- return vips_rot(in, out, rotate, NULL);
- }
- }
- int
- vips_exif_orientation(VipsImage *image) {
- int orientation = 0;
- const char *exif;
- if (
- vips_image_get_typeof(image, EXIF_IFD0_ORIENTATION) != 0 &&
- !vips_image_get_string(image, EXIF_IFD0_ORIENTATION, &exif)
- ) {
- orientation = atoi(&exif[0]);
- }
- return orientation;
- }
- int
- interpolator_window_size(char const *name) {
- VipsInterpolate *interpolator = vips_interpolate_new(name);
- int window_size = vips_interpolate_get_window_size(interpolator);
- g_object_unref(interpolator);
- return window_size;
- }
- const char *
- vips_enum_nick_bridge(VipsImage *image) {
- return vips_enum_nick(VIPS_TYPE_INTERPRETATION, image->Type);
- }
- int
- vips_zoom_bridge(VipsImage *in, VipsImage **out, int xfac, int yfac) {
- return vips_zoom(in, out, xfac, yfac, NULL);
- }
- int
- vips_embed_bridge(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend, double r, double g, double b) {
- if (extend == VIPS_EXTEND_BACKGROUND) {
- double background[3] = {r, g, b};
- VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3);
- return vips_embed(in, out, left, top, width, height, "extend", extend, "background", vipsBackground, NULL);
- }
- return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
- }
- int
- vips_extract_area_bridge(VipsImage *in, VipsImage **out, int left, int top, int width, int height) {
- return vips_extract_area(in, out, left, top, width, height, NULL);
- }
- int
- vips_colourspace_issupported_bridge(VipsImage *in) {
- return vips_colourspace_issupported(in) ? 1 : 0;
- }
- VipsInterpretation
- vips_image_guess_interpretation_bridge(VipsImage *in) {
- return vips_image_guess_interpretation(in);
- }
- int
- vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space) {
- return vips_colourspace(in, out, space, NULL);
- }
- int
- vips_jpegsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace) {
- return vips_jpegsave_buffer(in, buf, len,
- "strip", strip,
- "Q", quality,
- "optimize_coding", TRUE,
- "interlace", with_interlace(interlace),
- NULL
- );
- }
- int
- vips_pngsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int compression, int quality, int interlace) {
- #if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
- return vips_pngsave_buffer(in, buf, len,
- "strip", FALSE,
- "compression", compression,
- "interlace", with_interlace(interlace),
- "filter", VIPS_FOREIGN_PNG_FILTER_NONE,
- NULL
- );
- #else
- return vips_pngsave_buffer(in, buf, len,
- "strip", FALSE,
- "compression", compression,
- "interlace", with_interlace(interlace),
- NULL
- );
- #endif
- }
- int
- vips_webpsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality) {
- return vips_webpsave_buffer(in, buf, len,
- "strip", strip,
- "Q", quality,
- NULL
- );
- }
- int
- vips_tiffsave_bridge(VipsImage *in, void **buf, size_t *len) {
- #if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 5)
- return vips_tiffsave_buffer(in, buf, len, NULL);
- #else
- return 0;
- #endif
- }
- int
- vips_is_16bit (VipsInterpretation interpretation) {
- return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
- }
- int
- vips_flatten_background_brigde(VipsImage *in, VipsImage **out, double r, double g, double b) {
- if (vips_is_16bit(in->Type)) {
- r = 65535 * r / 255;
- g = 65535 * g / 255;
- b = 65535 * b / 255;
- }
- double background[3] = {r, g, b};
- VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3);
- return vips_flatten(in, out,
- "background", vipsBackground,
- "max_alpha", vips_is_16bit(in->Type) ? 65535.0 : 255.0,
- NULL
- );
- }
- int
- vips_init_image (void *buf, size_t len, int imageType, VipsImage **out) {
- int code = 1;
- if (imageType == JPEG) {
- code = vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- } else if (imageType == PNG) {
- code = vips_pngload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- } else if (imageType == WEBP) {
- code = vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- } else if (imageType == TIFF) {
- code = vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- #if (VIPS_MAJOR_VERSION >= 8)
- #if (VIPS_MINOR_VERSION >= 3)
- } else if (imageType == GIF) {
- code = vips_gifload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- } else if (imageType == PDF) {
- code = vips_pdfload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- } else if (imageType == SVG) {
- code = vips_svgload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- #endif
- } else if (imageType == MAGICK) {
- code = vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
- #endif
- }
- return code;
- }
- int
- vips_watermark_replicate (VipsImage *orig, VipsImage *in, VipsImage **out) {
- VipsImage *cache = vips_image_new();
- if (
- vips_replicate(in, &cache,
- 1 + orig->Xsize / in->Xsize,
- 1 + orig->Ysize / in->Ysize, NULL) ||
- vips_crop(cache, out, 0, 0, orig->Xsize, orig->Ysize, NULL)
- ) {
- g_object_unref(cache);
- return 1;
- }
- g_object_unref(cache);
- return 0;
- }
- int
- vips_watermark(VipsImage *in, VipsImage **out, WatermarkTextOptions *to, WatermarkOptions *o) {
- double ones[3] = { 1, 1, 1 };
- VipsImage *base = vips_image_new();
- VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
- t[0] = in;
- // Make the mask.
- if (
- vips_text(&t[1], to->Text,
- "width", o->Width,
- "dpi", o->DPI,
- "font", to->Font,
- NULL) ||
- vips_linear1(t[1], &t[2], o->Opacity, 0.0, NULL) ||
- vips_cast(t[2], &t[3], VIPS_FORMAT_UCHAR, NULL) ||
- vips_embed(t[3], &t[4], 100, 100, t[3]->Xsize + o->Margin, t[3]->Ysize + o->Margin, NULL)
- ) {
- g_object_unref(base);
- return 1;
- }
- // Replicate if necessary
- if (o->NoReplicate != 1) {
- VipsImage *cache = vips_image_new();
- if (vips_watermark_replicate(t[0], t[4], &cache)) {
- g_object_unref(cache);
- g_object_unref(base);
- return 1;
- }
- g_object_unref(t[4]);
- t[4] = cache;
- }
- // Make the constant image to paint the text with.
- if (
- vips_black(&t[5], 1, 1, NULL) ||
- vips_linear(t[5], &t[6], ones, o->Background, 3, NULL) ||
- vips_cast(t[6], &t[7], VIPS_FORMAT_UCHAR, NULL) ||
- vips_copy(t[7], &t[8], "interpretation", t[0]->Type, NULL) ||
- vips_embed(t[8], &t[9], 0, 0, t[0]->Xsize, t[0]->Ysize, "extend", VIPS_EXTEND_COPY, NULL)
- ) {
- g_object_unref(base);
- return 1;
- }
- // Blend the mask and text and write to output.
- if (vips_ifthenelse(t[4], t[9], t[0], out, "blend", TRUE, NULL)) {
- g_object_unref(base);
- return 1;
- }
- g_object_unref(base);
- return 0;
- }
- int
- vips_gaussblur_bridge(VipsImage *in, VipsImage **out, double sigma, double min_ampl) {
- #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
- return vips_gaussblur(in, out, (int) sigma, NULL);
- #else
- return vips_gaussblur(in, out, sigma, NULL, "min_ampl", min_ampl, NULL);
- #endif
- }
- int
- vips_sharpen_bridge(VipsImage *in, VipsImage **out, int radius, double x1, double y2, double y3, double m1, double m2) {
- #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
- return vips_sharpen(in, out, radius, x1, y2, y3, m1, m2, NULL);
- #else
- return vips_sharpen(in, out, "radius", radius, "x1", x1, "y2", y2, "y3", y3, "m1", m1, "m2", m2, NULL);
- #endif
- }
- int
- vips_add_band(VipsImage *in, VipsImage **out, double c) {
- #if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 2))
- return vips_bandjoin_const1(in, out, c, NULL);
- #else
- VipsImage *base = vips_image_new();
- if (
- vips_black(&base, in->Xsize, in->Ysize, NULL) ||
- vips_linear1(base, &base, 1, c, NULL)) {
- g_object_unref(base);
- return 1;
- }
- g_object_unref(base);
- return vips_bandjoin2(in, base, out, c, NULL);
- #endif
- }
- int
- vips_watermark_image(VipsImage *in, VipsImage *sub, VipsImage **out, WatermarkImageOptions *o) {
- VipsImage *base = vips_image_new();
- VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
- // add in and sub for unreffing and later use
- t[0] = in;
- t[1] = sub;
- if (has_alpha_channel(in) == 0) {
- vips_add_band(in, &t[0], 255.0);
- // in is no longer in the array and won't be unreffed, so add it at the end
- t[8] = in;
- }
- if (has_alpha_channel(sub) == 0) {
- vips_add_band(sub, &t[1], 255.0);
- // sub is no longer in the array and won't be unreffed, so add it at the end
- t[9] = sub;
- }
- // Place watermark image in the right place and size it to the size of the
- // image that should be watermarked
- if (
- vips_embed(t[1], &t[2], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
- g_object_unref(base);
- return 1;
- }
- // Create a mask image based on the alpha band from the watermark image
- // and place it in the right position
- if (
- vips_extract_band(t[1], &t[3], t[1]->Bands - 1, "n", 1, NULL) ||
- vips_linear1(t[3], &t[4], o->Opacity, 0.0, NULL) ||
- vips_cast(t[4], &t[5], VIPS_FORMAT_UCHAR, NULL) ||
- vips_copy(t[5], &t[6], "interpretation", t[0]->Type, NULL) ||
- vips_embed(t[6], &t[7], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
- g_object_unref(base);
- return 1;
- }
- // Blend the mask and watermark image and write to output.
- if (vips_ifthenelse(t[7], t[2], t[0], out, "blend", TRUE, NULL)) {
- g_object_unref(base);
- return 1;
- }
- g_object_unref(base);
- return 0;
- }
- int
- vips_smartcrop_bridge(VipsImage *in, VipsImage **out, int width, int height) {
- #if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 5)
- return vips_smartcrop(in, out, width, height, NULL);
- #else
- return 0;
- #endif
- }
|