vips.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <vips/vips.h>
  4. #include <vips/foreign.h>
  5. #include <vips/vips7compat.h>
  6. /**
  7. * Starting libvips 7.41, VIPS_ANGLE_x has been renamed to VIPS_ANGLE_Dx
  8. * "to help python". So we provide the macro to correctly build for versions
  9. * before 7.41.x.
  10. * https://github.com/jcupitt/libvips/blob/master/ChangeLog#L128
  11. */
  12. #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
  13. #define VIPS_ANGLE_D0 VIPS_ANGLE_0
  14. #define VIPS_ANGLE_D90 VIPS_ANGLE_90
  15. #define VIPS_ANGLE_D180 VIPS_ANGLE_180
  16. #define VIPS_ANGLE_D270 VIPS_ANGLE_270
  17. #endif
  18. #define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"
  19. enum types {
  20. UNKNOWN = 0,
  21. JPEG,
  22. WEBP,
  23. PNG,
  24. TIFF,
  25. GIF,
  26. PDF,
  27. SVG,
  28. MAGICK
  29. };
  30. typedef struct {
  31. const char *Text;
  32. const char *Font;
  33. } WatermarkTextOptions;
  34. typedef struct {
  35. int Width;
  36. int DPI;
  37. int Margin;
  38. int NoReplicate;
  39. float Opacity;
  40. double Background[3];
  41. } WatermarkOptions;
  42. typedef struct {
  43. int Left;
  44. int Top;
  45. float Opacity;
  46. } WatermarkImageOptions;
  47. static unsigned long
  48. has_profile_embed(VipsImage *image) {
  49. return vips_image_get_typeof(image, VIPS_META_ICC_NAME);
  50. }
  51. static void
  52. remove_profile(VipsImage *image) {
  53. vips_image_remove(image, VIPS_META_ICC_NAME);
  54. }
  55. static gboolean
  56. with_interlace(int interlace) {
  57. return interlace > 0 ? TRUE : FALSE;
  58. }
  59. static int
  60. has_alpha_channel(VipsImage *image) {
  61. return (
  62. (image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
  63. (image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
  64. (image->Bands == 5 && image->Type == VIPS_INTERPRETATION_CMYK)
  65. ) ? 1 : 0;
  66. }
  67. /**
  68. * This method is here to handle the weird initialization of the vips lib.
  69. * libvips use a macro VIPS_INIT() that call vips__init() in version < 7.41,
  70. * or calls vips_init() in version >= 7.41.
  71. *
  72. * Anyway, it's not possible to build bimg on Debian Jessie with libvips 7.40.x,
  73. * as vips_init() is a macro to VIPS_INIT(), which is also a macro, hence, cgo
  74. * is unable to determine the return type of vips_init(), making the build impossible.
  75. * In order to correctly build bimg, for version < 7.41, we should undef vips_init and
  76. * creates a vips_init() method that calls VIPS_INIT().
  77. */
  78. #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
  79. #undef vips_init
  80. int
  81. vips_init(const char *argv0)
  82. {
  83. return VIPS_INIT(argv0);
  84. }
  85. #endif
  86. void
  87. vips_enable_cache_set_trace() {
  88. vips_cache_set_trace(TRUE);
  89. }
  90. int
  91. vips_affine_interpolator(VipsImage *in, VipsImage **out, double a, double b, double c, double d, VipsInterpolate *interpolator) {
  92. return vips_affine(in, out, a, b, c, d, "interpolate", interpolator, NULL);
  93. }
  94. int
  95. vips_jpegload_buffer_shrink(void *buf, size_t len, VipsImage **out, int shrink) {
  96. return vips_jpegload_buffer(buf, len, out, "shrink", shrink, NULL);
  97. }
  98. int
  99. vips_flip_bridge(VipsImage *in, VipsImage **out, int direction) {
  100. return vips_flip(in, out, direction, NULL);
  101. }
  102. int
  103. vips_shrink_bridge(VipsImage *in, VipsImage **out, double xshrink, double yshrink) {
  104. return vips_shrink(in, out, xshrink, yshrink, NULL);
  105. }
  106. int
  107. vips_type_find_bridge(int t) {
  108. if (t == GIF) {
  109. return vips_type_find("VipsOperation", "gifload");
  110. }
  111. if (t == PDF) {
  112. return vips_type_find("VipsOperation", "pdfload");
  113. }
  114. if (t == TIFF) {
  115. return vips_type_find("VipsOperation", "tiffload");
  116. }
  117. if (t == SVG) {
  118. return vips_type_find("VipsOperation", "svgload");
  119. }
  120. if (t == WEBP) {
  121. return vips_type_find("VipsOperation", "webpload");
  122. }
  123. if (t == PNG) {
  124. return vips_type_find("VipsOperation", "pngload");
  125. }
  126. if (t == JPEG) {
  127. return vips_type_find("VipsOperation", "jpegload");
  128. }
  129. if (t == MAGICK) {
  130. return vips_type_find("VipsOperation", "magickload");
  131. }
  132. return 0;
  133. }
  134. int
  135. vips_type_find_save_bridge(int t) {
  136. if (t == TIFF) {
  137. return vips_type_find("VipsOperation", "tiffsave_buffer");
  138. }
  139. if (t == WEBP) {
  140. return vips_type_find("VipsOperation", "webpsave_buffer");
  141. }
  142. if (t == PNG) {
  143. return vips_type_find("VipsOperation", "pngsave_buffer");
  144. }
  145. if (t == JPEG) {
  146. return vips_type_find("VipsOperation", "jpegsave_buffer");
  147. }
  148. return 0;
  149. }
  150. int
  151. vips_rotate(VipsImage *in, VipsImage **out, int angle) {
  152. int rotate = VIPS_ANGLE_D0;
  153. angle %= 360;
  154. if (angle == 45) {
  155. rotate = VIPS_ANGLE45_D45;
  156. } else if (angle == 90) {
  157. rotate = VIPS_ANGLE_D90;
  158. } else if (angle == 135) {
  159. rotate = VIPS_ANGLE45_D135;
  160. } else if (angle == 180) {
  161. rotate = VIPS_ANGLE_D180;
  162. } else if (angle == 225) {
  163. rotate = VIPS_ANGLE45_D225;
  164. } else if (angle == 270) {
  165. rotate = VIPS_ANGLE_D270;
  166. } else if (angle == 315) {
  167. rotate = VIPS_ANGLE45_D315;
  168. } else {
  169. angle = 0;
  170. }
  171. if (angle > 0 && angle % 90 != 0) {
  172. return vips_rot45(in, out, "angle", rotate, NULL);
  173. } else {
  174. return vips_rot(in, out, rotate, NULL);
  175. }
  176. }
  177. int
  178. vips_exif_orientation(VipsImage *image) {
  179. int orientation = 0;
  180. const char *exif;
  181. if (
  182. vips_image_get_typeof(image, EXIF_IFD0_ORIENTATION) != 0 &&
  183. !vips_image_get_string(image, EXIF_IFD0_ORIENTATION, &exif)
  184. ) {
  185. orientation = atoi(&exif[0]);
  186. }
  187. return orientation;
  188. }
  189. int
  190. interpolator_window_size(char const *name) {
  191. VipsInterpolate *interpolator = vips_interpolate_new(name);
  192. int window_size = vips_interpolate_get_window_size(interpolator);
  193. g_object_unref(interpolator);
  194. return window_size;
  195. }
  196. const char *
  197. vips_enum_nick_bridge(VipsImage *image) {
  198. return vips_enum_nick(VIPS_TYPE_INTERPRETATION, image->Type);
  199. }
  200. int
  201. vips_zoom_bridge(VipsImage *in, VipsImage **out, int xfac, int yfac) {
  202. return vips_zoom(in, out, xfac, yfac, NULL);
  203. }
  204. int
  205. vips_embed_bridge(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend, double r, double g, double b) {
  206. if (extend == VIPS_EXTEND_BACKGROUND) {
  207. double background[3] = {r, g, b};
  208. VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3);
  209. return vips_embed(in, out, left, top, width, height, "extend", extend, "background", vipsBackground, NULL);
  210. }
  211. return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
  212. }
  213. int
  214. vips_extract_area_bridge(VipsImage *in, VipsImage **out, int left, int top, int width, int height) {
  215. return vips_extract_area(in, out, left, top, width, height, NULL);
  216. }
  217. int
  218. vips_colourspace_issupported_bridge(VipsImage *in) {
  219. return vips_colourspace_issupported(in) ? 1 : 0;
  220. }
  221. VipsInterpretation
  222. vips_image_guess_interpretation_bridge(VipsImage *in) {
  223. return vips_image_guess_interpretation(in);
  224. }
  225. int
  226. vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space) {
  227. return vips_colourspace(in, out, space, NULL);
  228. }
  229. int
  230. vips_jpegsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace) {
  231. return vips_jpegsave_buffer(in, buf, len,
  232. "strip", strip,
  233. "Q", quality,
  234. "optimize_coding", TRUE,
  235. "interlace", with_interlace(interlace),
  236. NULL
  237. );
  238. }
  239. int
  240. vips_pngsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int compression, int quality, int interlace) {
  241. #if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
  242. return vips_pngsave_buffer(in, buf, len,
  243. "strip", FALSE,
  244. "compression", compression,
  245. "interlace", with_interlace(interlace),
  246. "filter", VIPS_FOREIGN_PNG_FILTER_NONE,
  247. NULL
  248. );
  249. #else
  250. return vips_pngsave_buffer(in, buf, len,
  251. "strip", FALSE,
  252. "compression", compression,
  253. "interlace", with_interlace(interlace),
  254. NULL
  255. );
  256. #endif
  257. }
  258. int
  259. vips_webpsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality) {
  260. return vips_webpsave_buffer(in, buf, len,
  261. "strip", strip,
  262. "Q", quality,
  263. NULL
  264. );
  265. }
  266. int
  267. vips_tiffsave_bridge(VipsImage *in, void **buf, size_t *len) {
  268. #if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 5)
  269. return vips_tiffsave_buffer(in, buf, len, NULL);
  270. #else
  271. return 0;
  272. #endif
  273. }
  274. int
  275. vips_is_16bit (VipsInterpretation interpretation) {
  276. return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
  277. }
  278. int
  279. vips_flatten_background_brigde(VipsImage *in, VipsImage **out, double r, double g, double b) {
  280. if (vips_is_16bit(in->Type)) {
  281. r = 65535 * r / 255;
  282. g = 65535 * g / 255;
  283. b = 65535 * b / 255;
  284. }
  285. double background[3] = {r, g, b};
  286. VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3);
  287. return vips_flatten(in, out,
  288. "background", vipsBackground,
  289. "max_alpha", vips_is_16bit(in->Type) ? 65535.0 : 255.0,
  290. NULL
  291. );
  292. }
  293. int
  294. vips_init_image (void *buf, size_t len, int imageType, VipsImage **out) {
  295. int code = 1;
  296. if (imageType == JPEG) {
  297. code = vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  298. } else if (imageType == PNG) {
  299. code = vips_pngload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  300. } else if (imageType == WEBP) {
  301. code = vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  302. } else if (imageType == TIFF) {
  303. code = vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  304. #if (VIPS_MAJOR_VERSION >= 8)
  305. #if (VIPS_MINOR_VERSION >= 3)
  306. } else if (imageType == GIF) {
  307. code = vips_gifload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  308. } else if (imageType == PDF) {
  309. code = vips_pdfload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  310. } else if (imageType == SVG) {
  311. code = vips_svgload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  312. #endif
  313. } else if (imageType == MAGICK) {
  314. code = vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
  315. #endif
  316. }
  317. return code;
  318. }
  319. int
  320. vips_watermark_replicate (VipsImage *orig, VipsImage *in, VipsImage **out) {
  321. VipsImage *cache = vips_image_new();
  322. if (
  323. vips_replicate(in, &cache,
  324. 1 + orig->Xsize / in->Xsize,
  325. 1 + orig->Ysize / in->Ysize, NULL) ||
  326. vips_crop(cache, out, 0, 0, orig->Xsize, orig->Ysize, NULL)
  327. ) {
  328. g_object_unref(cache);
  329. return 1;
  330. }
  331. g_object_unref(cache);
  332. return 0;
  333. }
  334. int
  335. vips_watermark(VipsImage *in, VipsImage **out, WatermarkTextOptions *to, WatermarkOptions *o) {
  336. double ones[3] = { 1, 1, 1 };
  337. VipsImage *base = vips_image_new();
  338. VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
  339. t[0] = in;
  340. // Make the mask.
  341. if (
  342. vips_text(&t[1], to->Text,
  343. "width", o->Width,
  344. "dpi", o->DPI,
  345. "font", to->Font,
  346. NULL) ||
  347. vips_linear1(t[1], &t[2], o->Opacity, 0.0, NULL) ||
  348. vips_cast(t[2], &t[3], VIPS_FORMAT_UCHAR, NULL) ||
  349. vips_embed(t[3], &t[4], 100, 100, t[3]->Xsize + o->Margin, t[3]->Ysize + o->Margin, NULL)
  350. ) {
  351. g_object_unref(base);
  352. return 1;
  353. }
  354. // Replicate if necessary
  355. if (o->NoReplicate != 1) {
  356. VipsImage *cache = vips_image_new();
  357. if (vips_watermark_replicate(t[0], t[4], &cache)) {
  358. g_object_unref(cache);
  359. g_object_unref(base);
  360. return 1;
  361. }
  362. g_object_unref(t[4]);
  363. t[4] = cache;
  364. }
  365. // Make the constant image to paint the text with.
  366. if (
  367. vips_black(&t[5], 1, 1, NULL) ||
  368. vips_linear(t[5], &t[6], ones, o->Background, 3, NULL) ||
  369. vips_cast(t[6], &t[7], VIPS_FORMAT_UCHAR, NULL) ||
  370. vips_copy(t[7], &t[8], "interpretation", t[0]->Type, NULL) ||
  371. vips_embed(t[8], &t[9], 0, 0, t[0]->Xsize, t[0]->Ysize, "extend", VIPS_EXTEND_COPY, NULL)
  372. ) {
  373. g_object_unref(base);
  374. return 1;
  375. }
  376. // Blend the mask and text and write to output.
  377. if (vips_ifthenelse(t[4], t[9], t[0], out, "blend", TRUE, NULL)) {
  378. g_object_unref(base);
  379. return 1;
  380. }
  381. g_object_unref(base);
  382. return 0;
  383. }
  384. int
  385. vips_gaussblur_bridge(VipsImage *in, VipsImage **out, double sigma, double min_ampl) {
  386. #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
  387. return vips_gaussblur(in, out, (int) sigma, NULL);
  388. #else
  389. return vips_gaussblur(in, out, sigma, NULL, "min_ampl", min_ampl, NULL);
  390. #endif
  391. }
  392. int
  393. vips_sharpen_bridge(VipsImage *in, VipsImage **out, int radius, double x1, double y2, double y3, double m1, double m2) {
  394. #if (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 41)
  395. return vips_sharpen(in, out, radius, x1, y2, y3, m1, m2, NULL);
  396. #else
  397. return vips_sharpen(in, out, "radius", radius, "x1", x1, "y2", y2, "y3", y3, "m1", m1, "m2", m2, NULL);
  398. #endif
  399. }
  400. int
  401. vips_add_band(VipsImage *in, VipsImage **out, double c) {
  402. #if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 2))
  403. return vips_bandjoin_const1(in, out, c, NULL);
  404. #else
  405. VipsImage *base = vips_image_new();
  406. if (
  407. vips_black(&base, in->Xsize, in->Ysize, NULL) ||
  408. vips_linear1(base, &base, 1, c, NULL)) {
  409. g_object_unref(base);
  410. return 1;
  411. }
  412. g_object_unref(base);
  413. return vips_bandjoin2(in, base, out, c, NULL);
  414. #endif
  415. }
  416. int
  417. vips_watermark_image(VipsImage *in, VipsImage *sub, VipsImage **out, WatermarkImageOptions *o) {
  418. VipsImage *base = vips_image_new();
  419. VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
  420. // add in and sub for unreffing and later use
  421. t[0] = in;
  422. t[1] = sub;
  423. if (has_alpha_channel(in) == 0) {
  424. vips_add_band(in, &t[0], 255.0);
  425. // in is no longer in the array and won't be unreffed, so add it at the end
  426. t[8] = in;
  427. }
  428. if (has_alpha_channel(sub) == 0) {
  429. vips_add_band(sub, &t[1], 255.0);
  430. // sub is no longer in the array and won't be unreffed, so add it at the end
  431. t[9] = sub;
  432. }
  433. // Place watermark image in the right place and size it to the size of the
  434. // image that should be watermarked
  435. if (
  436. vips_embed(t[1], &t[2], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
  437. g_object_unref(base);
  438. return 1;
  439. }
  440. // Create a mask image based on the alpha band from the watermark image
  441. // and place it in the right position
  442. if (
  443. vips_extract_band(t[1], &t[3], t[1]->Bands - 1, "n", 1, NULL) ||
  444. vips_linear1(t[3], &t[4], o->Opacity, 0.0, NULL) ||
  445. vips_cast(t[4], &t[5], VIPS_FORMAT_UCHAR, NULL) ||
  446. vips_copy(t[5], &t[6], "interpretation", t[0]->Type, NULL) ||
  447. vips_embed(t[6], &t[7], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
  448. g_object_unref(base);
  449. return 1;
  450. }
  451. // Blend the mask and watermark image and write to output.
  452. if (vips_ifthenelse(t[7], t[2], t[0], out, "blend", TRUE, NULL)) {
  453. g_object_unref(base);
  454. return 1;
  455. }
  456. g_object_unref(base);
  457. return 0;
  458. }
  459. int
  460. vips_smartcrop_bridge(VipsImage *in, VipsImage **out, int width, int height) {
  461. #if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 5)
  462. return vips_smartcrop(in, out, width, height, NULL);
  463. #else
  464. return 0;
  465. #endif
  466. }