vips.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. #include "vips.h"
  2. #include <string.h>
  3. #include <math.h>
  4. #define VIPS_SUPPORT_ARRAY_HEADERS \
  5. (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 9))
  6. #define VIPS_SUPPORT_AVIF \
  7. (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 9))
  8. #define VIPS_SUPPORT_PNG_BITDEPTH \
  9. (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 10))
  10. int
  11. vips_initialize() {
  12. return vips_init("imgproxy");
  13. }
  14. void
  15. clear_image(VipsImage **in) {
  16. if (G_IS_OBJECT(*in)) g_clear_object(in);
  17. }
  18. void
  19. g_free_go(void **buf) {
  20. g_free(*buf);
  21. }
  22. void
  23. swap_and_clear(VipsImage **in, VipsImage *out) {
  24. clear_image(in);
  25. *in = out;
  26. }
  27. int
  28. vips_type_find_load_go(int imgtype) {
  29. switch (imgtype)
  30. {
  31. case (JPEG):
  32. return vips_type_find("VipsOperation", "jpegload_buffer");
  33. case (PNG):
  34. return vips_type_find("VipsOperation", "pngload_buffer");
  35. case (WEBP):
  36. return vips_type_find("VipsOperation", "webpload_buffer");
  37. case (GIF):
  38. return vips_type_find("VipsOperation", "gifload_buffer");
  39. case (SVG):
  40. return vips_type_find("VipsOperation", "svgload_buffer");
  41. case (HEIC):
  42. return vips_type_find("VipsOperation", "heifload_buffer");
  43. case (AVIF):
  44. return vips_type_find("VipsOperation", "heifload_buffer");
  45. case (BMP):
  46. return vips_type_find("VipsOperation", "magickload_buffer");
  47. case (TIFF):
  48. return vips_type_find("VipsOperation", "tiffload_buffer");
  49. }
  50. return 0;
  51. }
  52. int
  53. vips_type_find_save_go(int imgtype) {
  54. switch (imgtype)
  55. {
  56. case (JPEG):
  57. return vips_type_find("VipsOperation", "jpegsave_buffer");
  58. case (PNG):
  59. return vips_type_find("VipsOperation", "pngsave_buffer");
  60. case (WEBP):
  61. return vips_type_find("VipsOperation", "webpsave_buffer");
  62. case (GIF):
  63. return vips_type_find("VipsOperation", "magicksave_buffer");
  64. #if VIPS_SUPPORT_AVIF
  65. case (AVIF):
  66. return vips_type_find("VipsOperation", "heifsave_buffer");
  67. #endif
  68. case (ICO):
  69. return vips_type_find("VipsOperation", "pngsave_buffer");
  70. case (BMP):
  71. return vips_type_find("VipsOperation", "magicksave_buffer");
  72. case (TIFF):
  73. return vips_type_find("VipsOperation", "tiffsave_buffer");
  74. }
  75. return 0;
  76. }
  77. int
  78. vips_jpegload_go(void *buf, size_t len, int shrink, VipsImage **out) {
  79. if (shrink > 1)
  80. return vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", shrink, NULL);
  81. return vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
  82. }
  83. int
  84. vips_pngload_go(void *buf, size_t len, VipsImage **out) {
  85. return vips_pngload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
  86. }
  87. int
  88. vips_webpload_go(void *buf, size_t len, double scale, int pages, VipsImage **out) {
  89. return vips_webpload_buffer(
  90. buf, len, out,
  91. "access", VIPS_ACCESS_SEQUENTIAL,
  92. "scale", scale,
  93. "n", pages,
  94. NULL
  95. );
  96. }
  97. int
  98. vips_gifload_go(void *buf, size_t len, int pages, VipsImage **out) {
  99. return vips_gifload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "n", pages, NULL);
  100. }
  101. int
  102. vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) {
  103. // libvips limits the minimal scale to 0.001, so we have to scale down dpi
  104. // for lower scale values
  105. double dpi = 72.0;
  106. if (scale < 0.001) {
  107. dpi *= VIPS_MAX(scale / 0.001, 0.001);
  108. scale = 0.001;
  109. }
  110. return vips_svgload_buffer(
  111. buf, len, out,
  112. "access", VIPS_ACCESS_SEQUENTIAL,
  113. "scale", scale,
  114. "dpi", dpi,
  115. NULL
  116. );
  117. }
  118. int
  119. vips_heifload_go(void *buf, size_t len, VipsImage **out) {
  120. return vips_heifload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
  121. }
  122. int
  123. vips_bmpload_go(void *buf, size_t len, VipsImage **out) {
  124. return vips_magickload_buffer(buf, len, out, NULL);
  125. }
  126. int
  127. vips_tiffload_go(void *buf, size_t len, VipsImage **out) {
  128. return vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
  129. }
  130. int
  131. vips_get_orientation(VipsImage *image) {
  132. int orientation;
  133. if (
  134. vips_image_get_typeof(image, VIPS_META_ORIENTATION) == G_TYPE_INT &&
  135. vips_image_get_int(image, VIPS_META_ORIENTATION, &orientation) == 0
  136. ) return orientation;
  137. return 1;
  138. }
  139. VipsBandFormat
  140. vips_band_format(VipsImage *in) {
  141. return in->BandFmt;
  142. }
  143. gboolean
  144. vips_is_animated(VipsImage * in) {
  145. return( vips_image_get_typeof(in, "page-height") != G_TYPE_INVALID &&
  146. vips_image_get_typeof(in, "gif-delay") != G_TYPE_INVALID &&
  147. vips_image_get_typeof(in, "gif-loop") != G_TYPE_INVALID );
  148. }
  149. int
  150. vips_image_get_array_int_go(VipsImage *image, const char *name, int **out, int *n) {
  151. #if VIPS_SUPPORT_ARRAY_HEADERS
  152. return vips_image_get_array_int(image, name, out, n);
  153. #else
  154. vips_error("vips_image_get_array_int_go", "Array headers are not supported (libvips 8.9+ reuired)");
  155. return 1;
  156. #endif
  157. }
  158. void
  159. vips_image_set_array_int_go(VipsImage *image, const char *name, const int *array, int n) {
  160. #if VIPS_SUPPORT_ARRAY_HEADERS
  161. vips_image_set_array_int(image, name, array, n);
  162. #endif
  163. }
  164. gboolean
  165. vips_image_hasalpha_go(VipsImage * in) {
  166. return vips_image_hasalpha(in);
  167. }
  168. int
  169. vips_addalpha_go(VipsImage *in, VipsImage **out) {
  170. return vips_addalpha(in, out, NULL);
  171. }
  172. int
  173. vips_copy_go(VipsImage *in, VipsImage **out) {
  174. return vips_copy(in, out, NULL);
  175. }
  176. int
  177. vips_cast_go(VipsImage *in, VipsImage **out, VipsBandFormat format) {
  178. return vips_cast(in, out, format, NULL);
  179. }
  180. int
  181. vips_rad2float_go(VipsImage *in, VipsImage **out) {
  182. return vips_rad2float(in, out, NULL);
  183. }
  184. int
  185. vips_resize_go(VipsImage *in, VipsImage **out, double wscale, double hscale) {
  186. return vips_resize(in, out, wscale, "vscale", hscale, NULL);
  187. }
  188. int
  189. vips_resize_with_premultiply(VipsImage *in, VipsImage **out, double wscale, double hscale) {
  190. VipsBandFormat format;
  191. VipsImage *tmp1, *tmp2;
  192. format = vips_band_format(in);
  193. if (vips_premultiply(in, &tmp1, NULL))
  194. return 1;
  195. if (vips_resize(tmp1, &tmp2, wscale, "vscale", hscale, NULL)) {
  196. clear_image(&tmp1);
  197. return 1;
  198. }
  199. swap_and_clear(&tmp1, tmp2);
  200. if (vips_unpremultiply(tmp1, &tmp2, NULL)) {
  201. clear_image(&tmp1);
  202. return 1;
  203. }
  204. swap_and_clear(&tmp1, tmp2);
  205. if (vips_cast(tmp1, out, format, NULL)) {
  206. clear_image(&tmp1);
  207. return 1;
  208. }
  209. clear_image(&tmp1);
  210. return 0;
  211. }
  212. int
  213. vips_icc_is_srgb_iec61966(VipsImage *in) {
  214. const void *data;
  215. size_t data_len;
  216. // 1998-12-01
  217. static char date[] = { 7, 206, 0, 2, 0, 9 };
  218. // 2.1
  219. static char version[] = { 2, 16, 0, 0 };
  220. if (vips_image_get_blob(in, VIPS_META_ICC_NAME, &data, &data_len))
  221. return FALSE;
  222. // Less than header size
  223. if (data_len < 128)
  224. return FALSE;
  225. // Predict it is sRGB IEC61966 2.1 by checking some header fields
  226. return ((memcmp(data + 48, "IEC ", 4) == 0) && // Device manufacturer
  227. (memcmp(data + 52, "sRGB", 4) == 0) && // Device model
  228. (memcmp(data + 80, "HP ", 4) == 0) && // Profile creator
  229. (memcmp(data + 24, date, 6) == 0) && // Date of creation
  230. (memcmp(data + 8, version, 4) == 0)); // Version
  231. }
  232. int
  233. vips_has_embedded_icc(VipsImage *in) {
  234. return vips_image_get_typeof(in, VIPS_META_ICC_NAME) != 0;
  235. }
  236. int
  237. vips_icc_import_go(VipsImage *in, VipsImage **out) {
  238. return vips_icc_import(in, out, "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL);
  239. }
  240. int
  241. vips_icc_export_go(VipsImage *in, VipsImage **out) {
  242. return vips_icc_export(in, out, NULL);
  243. }
  244. int
  245. vips_icc_export_srgb(VipsImage *in, VipsImage **out) {
  246. return vips_icc_export(in, out, "output_profile", "sRGB", NULL);
  247. }
  248. int
  249. vips_icc_transform_go(VipsImage *in, VipsImage **out) {
  250. return vips_icc_transform(in, out, "sRGB", "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL);
  251. }
  252. int
  253. vips_icc_remove(VipsImage *in, VipsImage **out) {
  254. if (vips_copy(in, out, NULL)) return 1;
  255. vips_image_remove(*out, VIPS_META_ICC_NAME);
  256. return 0;
  257. }
  258. int
  259. vips_colourspace_go(VipsImage *in, VipsImage **out, VipsInterpretation cs) {
  260. return vips_colourspace(in, out, cs, NULL);
  261. }
  262. int
  263. vips_rot_go(VipsImage *in, VipsImage **out, VipsAngle angle) {
  264. return vips_rot(in, out, angle, NULL);
  265. }
  266. int
  267. vips_flip_horizontal_go(VipsImage *in, VipsImage **out) {
  268. return vips_flip(in, out, VIPS_DIRECTION_HORIZONTAL, NULL);
  269. }
  270. int
  271. vips_smartcrop_go(VipsImage *in, VipsImage **out, int width, int height) {
  272. return vips_smartcrop(in, out, width, height, NULL);
  273. }
  274. int
  275. vips_gaussblur_go(VipsImage *in, VipsImage **out, double sigma) {
  276. return vips_gaussblur(in, out, sigma, NULL);
  277. }
  278. int
  279. vips_sharpen_go(VipsImage *in, VipsImage **out, double sigma) {
  280. return vips_sharpen(in, out, "sigma", sigma, NULL);
  281. }
  282. int
  283. vips_flatten_go(VipsImage *in, VipsImage **out, double r, double g, double b) {
  284. VipsArrayDouble *bg = vips_array_double_newv(3, r, g, b);
  285. int res = vips_flatten(in, out, "background", bg, NULL);
  286. vips_area_unref((VipsArea *)bg);
  287. return res;
  288. }
  289. int
  290. vips_extract_area_go(VipsImage *in, VipsImage **out, int left, int top, int width, int height) {
  291. return vips_extract_area(in, out, left, top, width, height, NULL);
  292. }
  293. int
  294. vips_trim(VipsImage *in, VipsImage **out, double threshold,
  295. gboolean smart, double r, double g, double b,
  296. gboolean equal_hor, gboolean equal_ver) {
  297. VipsImage *tmp;
  298. if (vips_image_hasalpha(in)) {
  299. if (vips_flatten(in, &tmp, NULL))
  300. return 1;
  301. } else {
  302. if (vips_copy(in, &tmp, NULL))
  303. return 1;
  304. }
  305. double *bg;
  306. int bgn;
  307. VipsArrayDouble *bga;
  308. if (smart) {
  309. if (vips_getpoint(tmp, &bg, &bgn, 0, 0, NULL)) {
  310. clear_image(&tmp);
  311. return 1;
  312. }
  313. bga = vips_array_double_new(bg, bgn);
  314. } else {
  315. bga = vips_array_double_newv(3, r, g, b);
  316. bg = 0;
  317. }
  318. int left, right, top, bot, width, height, diff;
  319. if (vips_find_trim(tmp, &left, &top, &width, &height, "background", bga, "threshold", threshold, NULL)) {
  320. clear_image(&tmp);
  321. vips_area_unref((VipsArea *)bga);
  322. g_free(bg);
  323. return 1;
  324. }
  325. if (equal_hor) {
  326. right = in->Xsize - left - width;
  327. diff = right - left;
  328. if (diff > 0) {
  329. width += diff;
  330. } else if (diff < 0) {
  331. left = right;
  332. width -= diff;
  333. }
  334. }
  335. if (equal_ver) {
  336. bot = in->Ysize - top - height;
  337. diff = bot - top;
  338. if (diff > 0) {
  339. height += diff;
  340. } else if (diff < 0) {
  341. top = bot;
  342. height -= diff;
  343. }
  344. }
  345. clear_image(&tmp);
  346. vips_area_unref((VipsArea *)bga);
  347. g_free(bg);
  348. if (width == 0 || height == 0) {
  349. return vips_copy(in, out, NULL);
  350. }
  351. return vips_extract_area(in, out, left, top, width, height, NULL);
  352. }
  353. int
  354. vips_replicate_go(VipsImage *in, VipsImage **out, int width, int height) {
  355. VipsImage *tmp;
  356. if (vips_replicate(in, &tmp, 1 + width / in->Xsize, 1 + height / in->Ysize, NULL))
  357. return 1;
  358. if (vips_extract_area(tmp, out, 0, 0, width, height, NULL)) {
  359. clear_image(&tmp);
  360. return 1;
  361. }
  362. clear_image(&tmp);
  363. return 0;
  364. }
  365. int
  366. vips_embed_go(VipsImage *in, VipsImage **out, int x, int y, int width, int height, double *bg, int bgn) {
  367. VipsArrayDouble *bga = vips_array_double_new(bg, bgn);
  368. int ret = vips_embed(
  369. in, out, x, y, width, height,
  370. "extend", VIPS_EXTEND_BACKGROUND,
  371. "background", bga,
  372. NULL
  373. );
  374. vips_area_unref((VipsArea *)bga);
  375. return ret;
  376. }
  377. int
  378. vips_ensure_alpha(VipsImage *in, VipsImage **out) {
  379. if (vips_image_hasalpha_go(in)) {
  380. return vips_copy(in, out, NULL);
  381. }
  382. return vips_bandjoin_const1(in, out, 255, NULL);
  383. }
  384. int
  385. vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, double opacity) {
  386. VipsImage *base = vips_image_new();
  387. VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 5);
  388. if (opacity < 1) {
  389. if (
  390. vips_extract_band(watermark, &t[0], 0, "n", watermark->Bands - 1, NULL) ||
  391. vips_extract_band(watermark, &t[1], watermark->Bands - 1, "n", 1, NULL) ||
  392. vips_linear1(t[1], &t[2], opacity, 0, NULL) ||
  393. vips_bandjoin2(t[0], t[2], &t[3], NULL)
  394. ) {
  395. clear_image(&base);
  396. return 1;
  397. }
  398. } else {
  399. if (vips_copy(watermark, &t[3], NULL)) {
  400. clear_image(&base);
  401. return 1;
  402. }
  403. }
  404. int res =
  405. vips_composite2(in, t[3], &t[4], VIPS_BLEND_MODE_OVER, "compositing_space", in->Type, NULL) ||
  406. vips_cast(t[4], out, vips_image_get_format(in), NULL);
  407. clear_image(&base);
  408. return res;
  409. }
  410. int
  411. vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n) {
  412. return vips_arrayjoin(in, out, n, "across", 1, NULL);
  413. }
  414. int
  415. vips_strip(VipsImage *in, VipsImage **out) {
  416. if (vips_copy(in, out, NULL)) return 1;
  417. gchar **fields = vips_image_get_fields(in);
  418. for (int i = 0; fields[i] != NULL; i++) {
  419. gchar *name = fields[i];
  420. if (strcmp(name, VIPS_META_ICC_NAME) == 0) continue;
  421. vips_image_remove(*out, name);
  422. }
  423. g_strfreev(fields);
  424. return 0;
  425. }
  426. int
  427. vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace) {
  428. return vips_jpegsave_buffer(
  429. in, buf, len,
  430. "Q", quality,
  431. "optimize_coding", TRUE,
  432. "interlace", interlace,
  433. NULL
  434. );
  435. }
  436. int
  437. vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors) {
  438. if (!quantize)
  439. return vips_pngsave_buffer(
  440. in, buf, len,
  441. "filter", VIPS_FOREIGN_PNG_FILTER_NONE,
  442. "interlace", interlace,
  443. NULL
  444. );
  445. int bitdepth = ceil(log2(colors));
  446. return vips_pngsave_buffer(
  447. in, buf, len,
  448. "filter", VIPS_FOREIGN_PNG_FILTER_NONE,
  449. "interlace", interlace,
  450. #if VIPS_SUPPORT_PNG_BITDEPTH
  451. "palette", quantize,
  452. "bitdepth", bitdepth,
  453. #else // VIPS_SUPPORT_PNG_BITDEPTH
  454. "palette", quantize,
  455. "colours", colors,
  456. #endif // VIPS_SUPPORT_PNG_BITDEPTH
  457. NULL
  458. );
  459. }
  460. int
  461. vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
  462. return vips_webpsave_buffer(
  463. in, buf, len,
  464. "Q", quality,
  465. NULL
  466. );
  467. }
  468. int
  469. vips_gifsave_go(VipsImage *in, void **buf, size_t *len) {
  470. return vips_magicksave_buffer(in, buf, len, "format", "gif", NULL);
  471. }
  472. int
  473. vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
  474. return vips_tiffsave_buffer(in, buf, len, "Q", quality, NULL);
  475. }
  476. int
  477. vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
  478. #if VIPS_SUPPORT_AVIF
  479. return vips_heifsave_buffer(in, buf, len, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
  480. #else
  481. vips_error("vips_avifsave_go", "Saving AVIF is not supported (libvips 8.9+ reuired)");
  482. return 1;
  483. #endif
  484. }
  485. int
  486. vips_bmpsave_go(VipsImage *in, void **buf, size_t *len) {
  487. return vips_magicksave_buffer(in, buf, len, "format", "bmp", NULL);
  488. }
  489. void
  490. vips_cleanup() {
  491. vips_error_clear();
  492. vips_thread_shutdown();
  493. }