vips.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. package main
  2. /*
  3. #cgo pkg-config: vips
  4. #cgo LDFLAGS: -s -w
  5. #cgo CFLAGS: -O3
  6. #include "vips.h"
  7. */
  8. import "C"
  9. import (
  10. "bytes"
  11. "context"
  12. "encoding/binary"
  13. "errors"
  14. "fmt"
  15. "math"
  16. "os"
  17. "runtime"
  18. "unsafe"
  19. )
  20. type vipsImage struct {
  21. VipsImage *C.VipsImage
  22. }
  23. var (
  24. vipsTypeSupportLoad = make(map[imageType]bool)
  25. vipsTypeSupportSave = make(map[imageType]bool)
  26. watermark *imageData
  27. )
  28. var vipsConf struct {
  29. JpegProgressive C.int
  30. PngInterlaced C.int
  31. PngQuantize C.int
  32. PngQuantizationColors C.int
  33. WatermarkOpacity C.double
  34. }
  35. func initVips() error {
  36. runtime.LockOSThread()
  37. defer runtime.UnlockOSThread()
  38. if err := C.vips_initialize(); err != 0 {
  39. C.vips_shutdown()
  40. return fmt.Errorf("unable to start vips!")
  41. }
  42. // Disable libvips cache. Since processing pipeline is fine tuned, we won't get much profit from it.
  43. // Enabled cache can cause SIGSEGV on Musl-based systems like Alpine.
  44. C.vips_cache_set_max_mem(0)
  45. C.vips_cache_set_max(0)
  46. C.vips_concurrency_set(1)
  47. // Vector calculations cause SIGSEGV sometimes when working with JPEG.
  48. // It's better to disable it since profit it quite small
  49. C.vips_vector_set_enabled(0)
  50. if len(os.Getenv("IMGPROXY_VIPS_LEAK_CHECK")) > 0 {
  51. C.vips_leak_set(C.gboolean(1))
  52. }
  53. if len(os.Getenv("IMGPROXY_VIPS_CACHE_TRACE")) > 0 {
  54. C.vips_cache_set_trace(C.gboolean(1))
  55. }
  56. for _, imgtype := range imageTypes {
  57. vipsTypeSupportLoad[imgtype] = int(C.vips_type_find_load_go(C.int(imgtype))) != 0
  58. vipsTypeSupportSave[imgtype] = int(C.vips_type_find_save_go(C.int(imgtype))) != 0
  59. }
  60. if conf.JpegProgressive {
  61. vipsConf.JpegProgressive = C.int(1)
  62. }
  63. if conf.PngInterlaced {
  64. vipsConf.PngInterlaced = C.int(1)
  65. }
  66. if conf.PngQuantize {
  67. vipsConf.PngQuantize = C.int(1)
  68. }
  69. vipsConf.PngQuantizationColors = C.int(conf.PngQuantizationColors)
  70. vipsConf.WatermarkOpacity = C.double(conf.WatermarkOpacity)
  71. if err := vipsLoadWatermark(); err != nil {
  72. C.vips_shutdown()
  73. return fmt.Errorf("Can't load watermark: %s", err)
  74. }
  75. return nil
  76. }
  77. func shutdownVips() {
  78. C.vips_shutdown()
  79. }
  80. func vipsGetMem() float64 {
  81. return float64(C.vips_tracked_get_mem())
  82. }
  83. func vipsGetMemHighwater() float64 {
  84. return float64(C.vips_tracked_get_mem_highwater())
  85. }
  86. func vipsGetAllocs() float64 {
  87. return float64(C.vips_tracked_get_allocs())
  88. }
  89. func vipsCleanup() {
  90. C.vips_cleanup()
  91. }
  92. func vipsError() error {
  93. return newUnexpectedError(C.GoString(C.vips_error_buffer()), 1)
  94. }
  95. func vipsLoadWatermark() (err error) {
  96. watermark, err = getWatermarkData()
  97. return
  98. }
  99. func gbool(b bool) C.gboolean {
  100. if b {
  101. return C.gboolean(1)
  102. }
  103. return C.gboolean(0)
  104. }
  105. func (img *vipsImage) Width() int {
  106. return int(img.VipsImage.Xsize)
  107. }
  108. func (img *vipsImage) Height() int {
  109. return int(img.VipsImage.Ysize)
  110. }
  111. func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale float64, pages int) error {
  112. var tmp *C.VipsImage
  113. err := C.int(0)
  114. switch imgtype {
  115. case imageTypeJPEG:
  116. err = C.vips_jpegload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(shrink), &tmp)
  117. case imageTypePNG:
  118. err = C.vips_pngload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
  119. case imageTypeWEBP:
  120. err = C.vips_webpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), C.int(pages), &tmp)
  121. case imageTypeGIF:
  122. err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(pages), &tmp)
  123. case imageTypeSVG:
  124. err = C.vips_svgload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), &tmp)
  125. case imageTypeHEIC, imageTypeAVIF:
  126. err = C.vips_heifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
  127. case imageTypeBMP:
  128. err = C.vips_bmpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
  129. case imageTypeTIFF:
  130. err = C.vips_tiffload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
  131. }
  132. if err != 0 {
  133. return vipsError()
  134. }
  135. C.swap_and_clear(&img.VipsImage, tmp)
  136. return nil
  137. }
  138. func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.CancelFunc, error) {
  139. if imgtype == imageTypeICO {
  140. b, err := img.SaveAsIco()
  141. return b, func() {}, err
  142. }
  143. var ptr unsafe.Pointer
  144. cancel := func() {
  145. C.g_free_go(&ptr)
  146. }
  147. err := C.int(0)
  148. imgsize := C.size_t(0)
  149. switch imgtype {
  150. case imageTypeJPEG:
  151. err = C.vips_jpegsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.JpegProgressive)
  152. case imageTypePNG:
  153. err = C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors)
  154. case imageTypeWEBP:
  155. err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
  156. case imageTypeGIF:
  157. err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
  158. case imageTypeAVIF:
  159. err = C.vips_avifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
  160. case imageTypeBMP:
  161. err = C.vips_bmpsave_go(img.VipsImage, &ptr, &imgsize)
  162. case imageTypeTIFF:
  163. err = C.vips_tiffsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
  164. }
  165. if err != 0 {
  166. C.g_free_go(&ptr)
  167. return nil, cancel, vipsError()
  168. }
  169. b := ptrToBytes(ptr, int(imgsize))
  170. return b, cancel, nil
  171. }
  172. func (img *vipsImage) SaveAsIco() ([]byte, error) {
  173. if img.Width() > 256 || img.Height() > 256 {
  174. return nil, errors.New("Image dimensions is too big. Max dimension size for ICO is 256")
  175. }
  176. var ptr unsafe.Pointer
  177. imgsize := C.size_t(0)
  178. defer func() {
  179. C.g_free_go(&ptr)
  180. }()
  181. if C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, 0, 0, 256) != 0 {
  182. return nil, vipsError()
  183. }
  184. b := ptrToBytes(ptr, int(imgsize))
  185. buf := new(bytes.Buffer)
  186. buf.Grow(22 + int(imgsize))
  187. // ICONDIR header
  188. if _, err := buf.Write([]byte{0, 0, 1, 0, 1, 0}); err != nil {
  189. return nil, err
  190. }
  191. // ICONDIRENTRY
  192. if _, err := buf.Write([]byte{
  193. byte(img.Width() % 256),
  194. byte(img.Height() % 256),
  195. }); err != nil {
  196. return nil, err
  197. }
  198. // Number of colors. Not supported in our case
  199. if err := buf.WriteByte(0); err != nil {
  200. return nil, err
  201. }
  202. // Reserved
  203. if err := buf.WriteByte(0); err != nil {
  204. return nil, err
  205. }
  206. // Color planes. Always 1 in our case
  207. if _, err := buf.Write([]byte{1, 0}); err != nil {
  208. return nil, err
  209. }
  210. // Bits per pixel
  211. if img.HasAlpha() {
  212. if _, err := buf.Write([]byte{32, 0}); err != nil {
  213. return nil, err
  214. }
  215. } else {
  216. if _, err := buf.Write([]byte{24, 0}); err != nil {
  217. return nil, err
  218. }
  219. }
  220. // Image data size
  221. if err := binary.Write(buf, binary.LittleEndian, uint32(imgsize)); err != nil {
  222. return nil, err
  223. }
  224. // Image data offset. Always 22 in our case
  225. if _, err := buf.Write([]byte{22, 0, 0, 0}); err != nil {
  226. return nil, err
  227. }
  228. if _, err := buf.Write(b); err != nil {
  229. return nil, err
  230. }
  231. return buf.Bytes(), nil
  232. }
  233. func (img *vipsImage) Clear() {
  234. if img.VipsImage != nil {
  235. C.clear_image(&img.VipsImage)
  236. }
  237. }
  238. func (img *vipsImage) Arrayjoin(in []*vipsImage) error {
  239. var tmp *C.VipsImage
  240. arr := make([]*C.VipsImage, len(in))
  241. for i, im := range in {
  242. arr[i] = im.VipsImage
  243. }
  244. if C.vips_arrayjoin_go(&arr[0], &tmp, C.int(len(arr))) != 0 {
  245. return vipsError()
  246. }
  247. C.swap_and_clear(&img.VipsImage, tmp)
  248. return nil
  249. }
  250. func vipsSupportAnimation(imgtype imageType) bool {
  251. return imgtype == imageTypeGIF || imgtype == imageTypeWEBP
  252. }
  253. func (img *vipsImage) IsAnimated() bool {
  254. return C.vips_is_animated(img.VipsImage) > 0
  255. }
  256. func (img *vipsImage) HasAlpha() bool {
  257. return C.vips_image_hasalpha_go(img.VipsImage) > 0
  258. }
  259. func (img *vipsImage) GetInt(name string) (int, error) {
  260. var i C.int
  261. if C.vips_image_get_int(img.VipsImage, cachedCString(name), &i) != 0 {
  262. return 0, vipsError()
  263. }
  264. return int(i), nil
  265. }
  266. func (img *vipsImage) GetIntDefault(name string, def int) (int, error) {
  267. if C.vips_image_get_typeof(img.VipsImage, cachedCString(name)) == 0 {
  268. return def, nil
  269. }
  270. return img.GetInt(name)
  271. }
  272. func (img *vipsImage) GetIntSlice(name string) ([]int, error) {
  273. var ptr unsafe.Pointer
  274. size := C.int(0)
  275. if C.vips_image_get_array_int_go(img.VipsImage, cachedCString(name), (**C.int)(unsafe.Pointer(&ptr)), &size) != 0 {
  276. return nil, vipsError()
  277. }
  278. if size == 0 {
  279. return []int{}, nil
  280. }
  281. cOut := (*[math.MaxInt32]C.int)(ptr)[:int(size):int(size)]
  282. out := make([]int, int(size))
  283. for i, el := range cOut {
  284. out[i] = int(el)
  285. }
  286. return out, nil
  287. }
  288. func (img *vipsImage) GetIntSliceDefault(name string, def []int) ([]int, error) {
  289. if C.vips_image_get_typeof(img.VipsImage, cachedCString(name)) == 0 {
  290. return def, nil
  291. }
  292. return img.GetIntSlice(name)
  293. }
  294. func (img *vipsImage) SetInt(name string, value int) {
  295. C.vips_image_set_int(img.VipsImage, cachedCString(name), C.int(value))
  296. }
  297. func (img *vipsImage) SetIntSlice(name string, value []int) {
  298. in := make([]C.int, len(value))
  299. for i, el := range value {
  300. in[i] = C.int(el)
  301. }
  302. C.vips_image_set_array_int_go(img.VipsImage, cachedCString(name), &in[0], C.int(len(value)))
  303. }
  304. func (img *vipsImage) CastUchar() error {
  305. var tmp *C.VipsImage
  306. if C.vips_image_get_format(img.VipsImage) != C.VIPS_FORMAT_UCHAR {
  307. if C.vips_cast_go(img.VipsImage, &tmp, C.VIPS_FORMAT_UCHAR) != 0 {
  308. return vipsError()
  309. }
  310. C.swap_and_clear(&img.VipsImage, tmp)
  311. }
  312. return nil
  313. }
  314. func (img *vipsImage) Rad2Float() error {
  315. var tmp *C.VipsImage
  316. if C.vips_image_get_coding(img.VipsImage) == C.VIPS_CODING_RAD {
  317. if C.vips_rad2float_go(img.VipsImage, &tmp) != 0 {
  318. return vipsError()
  319. }
  320. C.swap_and_clear(&img.VipsImage, tmp)
  321. }
  322. return nil
  323. }
  324. func (img *vipsImage) Resize(wscale, hscale float64, hasAlpa bool) error {
  325. var tmp *C.VipsImage
  326. if hasAlpa {
  327. if C.vips_resize_with_premultiply(img.VipsImage, &tmp, C.double(wscale), C.double(hscale)) != 0 {
  328. return vipsError()
  329. }
  330. } else {
  331. if C.vips_resize_go(img.VipsImage, &tmp, C.double(wscale), C.double(hscale)) != 0 {
  332. return vipsError()
  333. }
  334. }
  335. C.swap_and_clear(&img.VipsImage, tmp)
  336. return nil
  337. }
  338. func (img *vipsImage) Pixelate(pixels int) error {
  339. var tmp *C.VipsImage
  340. if C.vips_pixelate(img.VipsImage, &tmp, C.int(pixels)) != 0 {
  341. return vipsError()
  342. }
  343. C.swap_and_clear(&img.VipsImage, tmp)
  344. return nil
  345. }
  346. func (img *vipsImage) Orientation() C.int {
  347. return C.vips_get_orientation(img.VipsImage)
  348. }
  349. func (img *vipsImage) Rotate(angle int) error {
  350. var tmp *C.VipsImage
  351. vipsAngle := (angle / 90) % 4
  352. if C.vips_rot_go(img.VipsImage, &tmp, C.VipsAngle(vipsAngle)) != 0 {
  353. return vipsError()
  354. }
  355. C.vips_autorot_remove_angle(tmp)
  356. C.swap_and_clear(&img.VipsImage, tmp)
  357. return nil
  358. }
  359. func (img *vipsImage) Flip() error {
  360. var tmp *C.VipsImage
  361. if C.vips_flip_horizontal_go(img.VipsImage, &tmp) != 0 {
  362. return vipsError()
  363. }
  364. C.swap_and_clear(&img.VipsImage, tmp)
  365. return nil
  366. }
  367. func (img *vipsImage) Crop(left, top, width, height int) error {
  368. var tmp *C.VipsImage
  369. if C.vips_extract_area_go(img.VipsImage, &tmp, C.int(left), C.int(top), C.int(width), C.int(height)) != 0 {
  370. return vipsError()
  371. }
  372. C.swap_and_clear(&img.VipsImage, tmp)
  373. return nil
  374. }
  375. func (img *vipsImage) Extract(out *vipsImage, left, top, width, height int) error {
  376. if C.vips_extract_area_go(img.VipsImage, &out.VipsImage, C.int(left), C.int(top), C.int(width), C.int(height)) != 0 {
  377. return vipsError()
  378. }
  379. return nil
  380. }
  381. func (img *vipsImage) SmartCrop(width, height int) error {
  382. var tmp *C.VipsImage
  383. if C.vips_smartcrop_go(img.VipsImage, &tmp, C.int(width), C.int(height)) != 0 {
  384. return vipsError()
  385. }
  386. C.swap_and_clear(&img.VipsImage, tmp)
  387. return nil
  388. }
  389. func (img *vipsImage) Trim(threshold float64, smart bool, color rgbColor, equalHor bool, equalVer bool) error {
  390. var tmp *C.VipsImage
  391. if err := img.CopyMemory(); err != nil {
  392. return err
  393. }
  394. if C.vips_trim(img.VipsImage, &tmp, C.double(threshold),
  395. gbool(smart), C.double(color.R), C.double(color.G), C.double(color.B),
  396. gbool(equalHor), gbool(equalVer)) != 0 {
  397. return vipsError()
  398. }
  399. C.swap_and_clear(&img.VipsImage, tmp)
  400. return nil
  401. }
  402. func (img *vipsImage) EnsureAlpha() error {
  403. var tmp *C.VipsImage
  404. if C.vips_ensure_alpha(img.VipsImage, &tmp) != 0 {
  405. return vipsError()
  406. }
  407. C.swap_and_clear(&img.VipsImage, tmp)
  408. return nil
  409. }
  410. func (img *vipsImage) Flatten(bg rgbColor) error {
  411. var tmp *C.VipsImage
  412. if C.vips_flatten_go(img.VipsImage, &tmp, C.double(bg.R), C.double(bg.G), C.double(bg.B)) != 0 {
  413. return vipsError()
  414. }
  415. C.swap_and_clear(&img.VipsImage, tmp)
  416. return nil
  417. }
  418. func (img *vipsImage) Blur(sigma float32) error {
  419. var tmp *C.VipsImage
  420. if C.vips_gaussblur_go(img.VipsImage, &tmp, C.double(sigma)) != 0 {
  421. return vipsError()
  422. }
  423. C.swap_and_clear(&img.VipsImage, tmp)
  424. return nil
  425. }
  426. func (img *vipsImage) Sharpen(sigma float32) error {
  427. var tmp *C.VipsImage
  428. if C.vips_sharpen_go(img.VipsImage, &tmp, C.double(sigma)) != 0 {
  429. return vipsError()
  430. }
  431. C.swap_and_clear(&img.VipsImage, tmp)
  432. return nil
  433. }
  434. func (img *vipsImage) ImportColourProfile() error {
  435. var tmp *C.VipsImage
  436. if img.VipsImage.Coding != C.VIPS_CODING_NONE {
  437. return nil
  438. }
  439. if img.VipsImage.BandFmt != C.VIPS_FORMAT_UCHAR && img.VipsImage.BandFmt != C.VIPS_FORMAT_USHORT {
  440. return nil
  441. }
  442. if C.vips_has_embedded_icc(img.VipsImage) == 0 {
  443. // No embedded profile
  444. if img.VipsImage.Type != C.VIPS_INTERPRETATION_CMYK {
  445. // vips doesn't have built-in profile for other interpretations,
  446. // so we can't do anything here
  447. return nil
  448. }
  449. }
  450. if C.vips_icc_import_go(img.VipsImage, &tmp) == 0 {
  451. C.swap_and_clear(&img.VipsImage, tmp)
  452. } else {
  453. logWarning("Can't import ICC profile: %s", vipsError())
  454. }
  455. return nil
  456. }
  457. func (img *vipsImage) ExportColourProfile() error {
  458. var tmp *C.VipsImage
  459. // Don't export is there's no embedded profile or embedded profile is sRGB
  460. if C.vips_has_embedded_icc(img.VipsImage) == 0 || C.vips_icc_is_srgb_iec61966(img.VipsImage) == 1 {
  461. return nil
  462. }
  463. if C.vips_icc_export_go(img.VipsImage, &tmp) == 0 {
  464. C.swap_and_clear(&img.VipsImage, tmp)
  465. } else {
  466. logWarning("Can't export ICC profile: %s", vipsError())
  467. }
  468. return nil
  469. }
  470. func (img *vipsImage) ExportColourProfileToSRGB() error {
  471. var tmp *C.VipsImage
  472. // Don't export is there's no embedded profile or embedded profile is sRGB
  473. if C.vips_has_embedded_icc(img.VipsImage) == 0 || C.vips_icc_is_srgb_iec61966(img.VipsImage) == 1 {
  474. return nil
  475. }
  476. if C.vips_icc_export_srgb(img.VipsImage, &tmp) == 0 {
  477. C.swap_and_clear(&img.VipsImage, tmp)
  478. } else {
  479. logWarning("Can't export ICC profile: %s", vipsError())
  480. }
  481. return nil
  482. }
  483. func (img *vipsImage) TransformColourProfile() error {
  484. var tmp *C.VipsImage
  485. // Don't transform is there's no embedded profile or embedded profile is sRGB
  486. if C.vips_has_embedded_icc(img.VipsImage) == 0 || C.vips_icc_is_srgb_iec61966(img.VipsImage) == 1 {
  487. return nil
  488. }
  489. if C.vips_icc_transform_go(img.VipsImage, &tmp) == 0 {
  490. C.swap_and_clear(&img.VipsImage, tmp)
  491. } else {
  492. logWarning("Can't transform ICC profile: %s", vipsError())
  493. }
  494. return nil
  495. }
  496. func (img *vipsImage) RemoveColourProfile() error {
  497. var tmp *C.VipsImage
  498. if C.vips_icc_remove(img.VipsImage, &tmp) == 0 {
  499. C.swap_and_clear(&img.VipsImage, tmp)
  500. } else {
  501. logWarning("Can't remove ICC profile: %s", vipsError())
  502. }
  503. return nil
  504. }
  505. func (img *vipsImage) IsSRGB() bool {
  506. return img.VipsImage.Type == C.VIPS_INTERPRETATION_sRGB
  507. }
  508. func (img *vipsImage) LinearColourspace() error {
  509. return img.Colorspace(C.VIPS_INTERPRETATION_scRGB)
  510. }
  511. func (img *vipsImage) RgbColourspace() error {
  512. return img.Colorspace(C.VIPS_INTERPRETATION_sRGB)
  513. }
  514. func (img *vipsImage) Colorspace(colorspace C.VipsInterpretation) error {
  515. if img.VipsImage.Type != colorspace {
  516. var tmp *C.VipsImage
  517. if C.vips_colourspace_go(img.VipsImage, &tmp, colorspace) != 0 {
  518. return vipsError()
  519. }
  520. C.swap_and_clear(&img.VipsImage, tmp)
  521. }
  522. return nil
  523. }
  524. func (img *vipsImage) CopyMemory() error {
  525. var tmp *C.VipsImage
  526. if tmp = C.vips_image_copy_memory(img.VipsImage); tmp == nil {
  527. return vipsError()
  528. }
  529. C.swap_and_clear(&img.VipsImage, tmp)
  530. return nil
  531. }
  532. func (img *vipsImage) Replicate(width, height int) error {
  533. var tmp *C.VipsImage
  534. if C.vips_replicate_go(img.VipsImage, &tmp, C.int(width), C.int(height)) != 0 {
  535. return vipsError()
  536. }
  537. C.swap_and_clear(&img.VipsImage, tmp)
  538. return nil
  539. }
  540. func (img *vipsImage) Embed(width, height int, offX, offY int, bg rgbColor, transpBg bool) error {
  541. var tmp *C.VipsImage
  542. if err := img.RgbColourspace(); err != nil {
  543. return err
  544. }
  545. var bgc []C.double
  546. if transpBg {
  547. if !img.HasAlpha() {
  548. if C.vips_addalpha_go(img.VipsImage, &tmp) != 0 {
  549. return vipsError()
  550. }
  551. C.swap_and_clear(&img.VipsImage, tmp)
  552. }
  553. bgc = []C.double{C.double(0)}
  554. } else {
  555. bgc = []C.double{C.double(bg.R), C.double(bg.G), C.double(bg.B), 1.0}
  556. }
  557. bgn := minInt(int(img.VipsImage.Bands), len(bgc))
  558. if C.vips_embed_go(img.VipsImage, &tmp, C.int(offX), C.int(offY), C.int(width), C.int(height), &bgc[0], C.int(bgn)) != 0 {
  559. return vipsError()
  560. }
  561. C.swap_and_clear(&img.VipsImage, tmp)
  562. return nil
  563. }
  564. func (img *vipsImage) ApplyWatermark(wm *vipsImage, opacity float64) error {
  565. var tmp *C.VipsImage
  566. if C.vips_apply_watermark(img.VipsImage, wm.VipsImage, &tmp, C.double(opacity)) != 0 {
  567. return vipsError()
  568. }
  569. C.swap_and_clear(&img.VipsImage, tmp)
  570. return nil
  571. }
  572. func (img *vipsImage) Strip() error {
  573. var tmp *C.VipsImage
  574. if C.vips_strip(img.VipsImage, &tmp) != 0 {
  575. return vipsError()
  576. }
  577. C.swap_and_clear(&img.VipsImage, tmp)
  578. return nil
  579. }