build(deps): bump github.com/davidbyttow/govips/v2 from 2.16.0 to 2.17.0

Bumps [github.com/davidbyttow/govips/v2](https://github.com/davidbyttow/govips) from 2.16.0 to 2.17.0.
- [Release notes](https://github.com/davidbyttow/govips/releases)
- [Commits](https://github.com/davidbyttow/govips/compare/v2.16.0...v2.17.0)

---
updated-dependencies:
- dependency-name: github.com/davidbyttow/govips/v2
  dependency-version: 2.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2026-03-03 14:46:33 +00:00
committed by Ralf Haferkamp
parent 8b25a1daae
commit 110483b808
53 changed files with 13865 additions and 2586 deletions

2
go.mod
View File

@@ -15,7 +15,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.17.0
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e
github.com/davidbyttow/govips/v2 v2.16.0
github.com/davidbyttow/govips/v2 v2.17.0
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/gabriel-vasile/mimetype v1.4.13

26
go.sum
View File

@@ -278,8 +278,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidbyttow/govips/v2 v2.16.0 h1:1nH/Rbx8qZP1hd+oYL9fYQjAnm1+KorX9s07ZGseQmo=
github.com/davidbyttow/govips/v2 v2.16.0/go.mod h1:clH5/IDVmG5eVyc23qYpyi7kmOT0B/1QNTKtci4RkyM=
github.com/davidbyttow/govips/v2 v2.17.0 h1:TFAjcaEqYpumRoIz2m1Ptr9Fhdg3H0R3FKixKS+4Jo8=
github.com/davidbyttow/govips/v2 v2.17.0/go.mod h1:HF7B5oTeNolUjdBAYVIZQ8S5nhQd1CfDf0rMlYSMJv8=
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
@@ -566,7 +566,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
@@ -923,7 +922,6 @@ github.com/nats-io/nkeys v0.4.12/go.mod h1:MT59A1HYcjIcyQDJStTfaOY6vhy9XTUjOFo+S
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI=
github.com/nrdcg/desec v0.5.0/go.mod h1:2ejvMazkav1VdDbv2HeQO7w+Ta1CGHqzQr27ZBYTuEQ=
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
@@ -1371,11 +1369,9 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1392,7 +1388,6 @@ golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1416,9 +1411,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1469,10 +1461,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1498,9 +1488,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1584,21 +1571,17 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1613,8 +1596,6 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1677,8 +1658,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
@@ -1789,7 +1768,6 @@ gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UD
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

View File

@@ -1,71 +0,0 @@
#include "arithmetic.h"
int add(VipsImage *left, VipsImage *right, VipsImage **out) {
return vips_add(left, right, out, NULL);
}
int multiply(VipsImage *left, VipsImage *right, VipsImage **out) {
return vips_multiply(left, right, out, NULL);
}
int divide(VipsImage *left, VipsImage *right, VipsImage **out) {
return vips_divide(left, right, out, NULL);
}
int linear(VipsImage *in, VipsImage **out, double *a, double *b, int n) {
return vips_linear(in, out, a, b, n, NULL);
}
int linear1(VipsImage *in, VipsImage **out, double a, double b) {
return vips_linear1(in, out, a, b, NULL);
}
int invert_image(VipsImage *in, VipsImage **out) {
return vips_invert(in, out, NULL);
}
int average(VipsImage *in, double *out) {
return vips_avg(in, out, NULL);
}
int find_trim(VipsImage *in, int *left, int *top, int *width, int *height,
double threshold, double r, double g, double b) {
if (in->Type == VIPS_INTERPRETATION_RGB16 || in->Type == VIPS_INTERPRETATION_GREY16) {
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);
int code = vips_find_trim(in, left, top, width, height, "threshold", threshold, "background", vipsBackground, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int getpoint(VipsImage *in, double **vector, int n, int x, int y) {
return vips_getpoint(in, vector, &n, x, y, NULL);
}
int stats(VipsImage *in, VipsImage **out) {
return vips_stats(in, out, NULL);
}
int hist_find(VipsImage *in, VipsImage **out) {
return vips_hist_find(in, out, NULL);
}
int hist_cum(VipsImage *in, VipsImage **out) {
return vips_hist_cum(in, out, NULL);
}
int hist_norm(VipsImage *in, VipsImage **out) {
return vips_hist_norm(in, out, NULL);
}
int hist_entropy(VipsImage *in, double *out) {
return vips_hist_entropy(in, out, NULL);
}

View File

@@ -1,176 +0,0 @@
package vips
// #include "arithmetic.h"
import "C"
import "unsafe"
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-add
func vipsAdd(left *C.VipsImage, right *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("add")
var out *C.VipsImage
if err := C.add(left, right, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-multiply
func vipsMultiply(left *C.VipsImage, right *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("multiply")
var out *C.VipsImage
if err := C.multiply(left, right, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-divide
func vipsDivide(left *C.VipsImage, right *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("divide")
var out *C.VipsImage
if err := C.divide(left, right, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-linear
func vipsLinear(in *C.VipsImage, a, b []float64, n int) (*C.VipsImage, error) {
incOpCounter("linear")
var out *C.VipsImage
if err := C.linear(in, &out, (*C.double)(&a[0]), (*C.double)(&b[0]), C.int(n)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-linear1
func vipsLinear1(in *C.VipsImage, a, b float64) (*C.VipsImage, error) {
incOpCounter("linear1")
var out *C.VipsImage
if err := C.linear1(in, &out, C.double(a), C.double(b)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-invert
func vipsInvert(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("invert")
var out *C.VipsImage
if err := C.invert_image(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-avg
func vipsAverage(in *C.VipsImage) (float64, error) {
incOpCounter("average")
var out C.double
if err := C.average(in, &out); err != 0 {
return 0, handleVipsError()
}
return float64(out), nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-find-trim
func vipsFindTrim(in *C.VipsImage, threshold float64, backgroundColor *Color) (int, int, int, int, error) {
incOpCounter("findTrim")
var left, top, width, height C.int
if err := C.find_trim(in, &left, &top, &width, &height, C.double(threshold), C.double(backgroundColor.R),
C.double(backgroundColor.G), C.double(backgroundColor.B)); err != 0 {
return -1, -1, -1, -1, handleVipsError()
}
return int(left), int(top), int(width), int(height), nil
}
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-getpoint
func vipsGetPoint(in *C.VipsImage, n int, x int, y int) ([]float64, error) {
incOpCounter("getpoint")
var out *C.double
defer gFreePointer(unsafe.Pointer(out))
if err := C.getpoint(in, &out, C.int(n), C.int(x), C.int(y)); err != 0 {
return nil, handleVipsError()
}
// maximum n is 4
return (*[4]float64)(unsafe.Pointer(out))[:n:n], nil
}
// https://www.libvips.org/API/current/libvips-arithmetic.html#vips-stats
func vipsStats(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("stats")
var out *C.VipsImage
if err := C.stats(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-arithmetic.html#vips-hist-find
func vipsHistFind(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("histFind")
var out *C.VipsImage
if err := C.hist_find(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-histogram.html#vips-hist-norm
func vipsHistNorm(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("histNorm")
var out *C.VipsImage
if err := C.hist_norm(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-histogram.html#vips-hist-cum
func vipsHistCum(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("histCum")
var out *C.VipsImage
if err := C.hist_cum(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-histogram.html#vips-hist-entropy
func vipsHistEntropy(in *C.VipsImage) (float64, error) {
incOpCounter("histEntropy")
var out C.double
if err := C.hist_entropy(in, &out); err != 0 {
return 0, handleVipsError()
}
return float64(out), nil
}

View File

@@ -1,20 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html
#include <stdlib.h>
#include <vips/vips.h>
int add(VipsImage *left, VipsImage *right, VipsImage **out);
int multiply(VipsImage *left, VipsImage *right, VipsImage **out);
int divide(VipsImage *left, VipsImage *right, VipsImage **out);
int linear(VipsImage *in, VipsImage **out, double *a, double *b, int n);
int linear1(VipsImage *in, VipsImage **out, double a, double b);
int invert_image(VipsImage *in, VipsImage **out);
int average(VipsImage *in, double *out);
int find_trim(VipsImage *in, int *left, int *top, int *width, int *height,
double threshold, double r, double g, double b);
int getpoint(VipsImage *in, double **vector, int n, int x, int y);
int stats(VipsImage *in, VipsImage **out);
int hist_find(VipsImage *in, VipsImage **out);
int hist_cum(VipsImage *in, VipsImage **out);
int hist_norm(VipsImage *in, VipsImage **out);
int hist_entropy(VipsImage *in, double *out);

View File

@@ -1,22 +0,0 @@
#include "color.h"
#include <unistd.h>
int is_colorspace_supported(VipsImage *in) {
return vips_colourspace_issupported(in) ? 1 : 0;
}
int to_colorspace(VipsImage *in, VipsImage **out, VipsInterpretation space) {
return vips_colourspace(in, out, space, NULL);
}
// https://libvips.github.io/libvips/API/8.6/libvips-colour.html#vips-icc-transform
int icc_transform(VipsImage *in, VipsImage **out, const char *output_profile, const char *input_profile, VipsIntent intent,
int depth, gboolean embedded) {
return vips_icc_transform(
in, out, output_profile,
"input_profile", input_profile ? input_profile : "none",
"intent", intent,
"depth", depth ? depth : 8,
"embedded", embedded,
NULL);
}

View File

@@ -1,96 +0,0 @@
package vips
// #include "color.h"
import "C"
// Color represents an RGB
type Color struct {
R, G, B uint8
}
// ColorRGBA represents an RGB with alpha channel (A)
type ColorRGBA struct {
R, G, B, A uint8
}
// Interpretation represents VIPS_INTERPRETATION type
type Interpretation int
// Interpretation enum
const (
InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
InterpretationHistogram Interpretation = C.VIPS_INTERPRETATION_HISTOGRAM
InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
InterpretationLABQ Interpretation = C.VIPS_INTERPRETATION_LABQ
InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
InterpretationCMC Interpretation = C.VIPS_INTERPRETATION_CMC
InterpretationLCH Interpretation = C.VIPS_INTERPRETATION_LCH
InterpretationLABS Interpretation = C.VIPS_INTERPRETATION_LABS
InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
InterpretationYXY Interpretation = C.VIPS_INTERPRETATION_YXY
InterpretationFourier Interpretation = C.VIPS_INTERPRETATION_FOURIER
InterpretationGrey16 Interpretation = C.VIPS_INTERPRETATION_GREY16
InterpretationMatrix Interpretation = C.VIPS_INTERPRETATION_MATRIX
InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
InterpretationHSV Interpretation = C.VIPS_INTERPRETATION_HSV
)
// Intent represents VIPS_INTENT type
type Intent int
// Intent enum
const (
IntentPerceptual Intent = C.VIPS_INTENT_PERCEPTUAL
IntentRelative Intent = C.VIPS_INTENT_RELATIVE
IntentSaturation Intent = C.VIPS_INTENT_SATURATION
IntentAbsolute Intent = C.VIPS_INTENT_ABSOLUTE
IntentLast Intent = C.VIPS_INTENT_LAST
)
func vipsIsColorSpaceSupported(in *C.VipsImage) bool {
return C.is_colorspace_supported(in) == 1
}
// https://libvips.github.io/libvips/API/current/libvips-colour.html#vips-colourspace
func vipsToColorSpace(in *C.VipsImage, interpretation Interpretation) (*C.VipsImage, error) {
incOpCounter("to_colorspace")
var out *C.VipsImage
inter := C.VipsInterpretation(interpretation)
if err := C.to_colorspace(in, &out, inter); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsICCTransform(in *C.VipsImage, outputProfile string, inputProfile string, intent Intent, depth int,
embedded bool) (*C.VipsImage, error) {
var out *C.VipsImage
var cInputProfile *C.char
var cEmbedded C.gboolean
cOutputProfile := C.CString(outputProfile)
defer freeCString(cOutputProfile)
if inputProfile != "" {
cInputProfile = C.CString(inputProfile)
defer freeCString(cInputProfile)
}
if embedded {
cEmbedded = C.TRUE
}
if res := C.icc_transform(in, &out, cOutputProfile, cInputProfile, C.VipsIntent(intent), C.int(depth), cEmbedded); res != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,10 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-colour.html
#include <stdlib.h>
#include <vips/vips.h>
int is_colorspace_supported(VipsImage *in);
int to_colorspace(VipsImage *in, VipsImage **out, VipsInterpretation space);
int icc_transform(VipsImage *in, VipsImage **out, const char *output_profile, const char *input_profile, VipsIntent intent,
int depth, gboolean embedded);

View File

@@ -1,27 +0,0 @@
package vips
// #include <vips/vips.h>
import "C"
// ImageComposite image to composite param
type ImageComposite struct {
Image *ImageRef
BlendMode BlendMode
X, Y int
}
func toVipsCompositeStructs(r *ImageRef, datas []*ImageComposite) ([]*C.VipsImage, []C.int, []C.int, []C.int) {
ins := []*C.VipsImage{r.image}
modes := []C.int{}
xs := []C.int{}
ys := []C.int{}
for _, image := range datas {
ins = append(ins, image.Image.image)
modes = append(modes, C.int(image.BlendMode))
xs = append(xs, C.int(image.X))
ys = append(ys, C.int(image.Y))
}
return ins, modes, xs, ys
}

View File

@@ -1,380 +0,0 @@
#include "conversion.h"
int copy_image_changing_interpretation(VipsImage *in, VipsImage **out,
VipsInterpretation interpretation) {
return vips_copy(in, out, "interpretation", interpretation, NULL);
}
int copy_image_changing_resolution(VipsImage *in, VipsImage **out, double xres,
double yres) {
return vips_copy(in, out, "xres", xres, "yres", yres, NULL);
}
int copy_image(VipsImage *in, VipsImage **out) {
return vips_copy(in, out, NULL);
}
int embed_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend) {
return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
}
int embed_image_background(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, double r, double g, double b, double a) {
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
int code = vips_embed(in, out, left, top, width, height,
"extend", VIPS_EXTEND_BACKGROUND, "background", vipsBackground, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int embed_multi_page_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend) {
VipsObject *base = VIPS_OBJECT(vips_image_new());
int page_height = vips_image_get_page_height(in);
int in_width = in->Xsize;
int n_pages = in->Ysize / page_height;
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_embed(page[i], &page[i], left, top, width, height, "extend", extend, NULL)
) {
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
g_object_unref(base);
return 0;
}
int embed_multi_page_image_background(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, double r, double g, double b, double a) {
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
VipsObject *base = VIPS_OBJECT(vips_image_new());
int page_height = vips_image_get_page_height(in);
int in_width = in->Xsize;
int n_pages = in->Ysize / page_height;
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_embed(page[i], &page[i], left, top, width, height,
"extend", VIPS_EXTEND_BACKGROUND, "background", vipsBackground, NULL)
) {
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return 0;
}
int flip_image(VipsImage *in, VipsImage **out, int direction) {
return vips_flip(in, out, direction, NULL);
}
int recomb_image(VipsImage *in, VipsImage **out, VipsImage *m) {
return vips_recomb(in, out, m, NULL);
}
int extract_image_area(VipsImage *in, VipsImage **out, int left, int top,
int width, int height) {
return vips_extract_area(in, out, left, top, width, height, NULL);
}
int extract_area_multi_page(VipsImage *in, VipsImage **out, int left, int top, int width, int height) {
VipsObject *base = VIPS_OBJECT(vips_image_new());
int page_height = vips_image_get_page_height(in);
int n_pages = in->Ysize / page_height;
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if(vips_extract_area(in, &page[i], left, page_height * i + top, width, height, NULL)) {
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
g_object_unref(base);
return 0;
}
int extract_band(VipsImage *in, VipsImage **out, int band, int num) {
if (num > 0) {
return vips_extract_band(in, out, band, "n", num, NULL);
}
return vips_extract_band(in, out, band, NULL);
}
int rot_image(VipsImage *in, VipsImage **out, VipsAngle angle) {
return vips_rot(in, out, angle, NULL);
}
int autorot_image(VipsImage *in, VipsImage **out) {
return vips_autorot(in, out, NULL);
}
int zoom_image(VipsImage *in, VipsImage **out, int xfac, int yfac) {
return vips_zoom(in, out, xfac, yfac, NULL);
}
int bandjoin(VipsImage **in, VipsImage **out, int n) {
return vips_bandjoin(in, out, n, NULL);
}
int bandjoin_const(VipsImage *in, VipsImage **out, double constants[], int n) {
return vips_bandjoin_const(in, out, constants, n, NULL);
}
int similarity(VipsImage *in, VipsImage **out, double scale, double angle,
double r, double g, double b, double a, double idx, double idy,
double odx, double ody) {
if (is_16bit(in->Type)) {
r = 65535 * r / 255;
g = 65535 * g / 255;
b = 65535 * b / 255;
a = 65535 * a / 255;
}
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
// Ignore the alpha channel if the image doesn't have one
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
int code = vips_similarity(in, out, "scale", scale, "angle", angle,
"background", vipsBackground, "idx", idx, "idy",
idy, "odx", odx, "ody", ody, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int smartcrop(VipsImage *in, VipsImage **out, int width, int height,
int interesting) {
return vips_smartcrop(in, out, width, height, "interesting", interesting,
NULL);
}
int crop(VipsImage *in, VipsImage **out, int left, int top,
int width, int height) {
// resolve image pages
int page_height = vips_image_get_page_height(in);
int n_pages = in->Ysize / page_height;
if (n_pages <= 1) {
return vips_crop(in, out, left, top, width, height, NULL);
}
int in_width = in->Xsize;
VipsObject *base = VIPS_OBJECT(vips_image_new());
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_crop(page[i], &page[i], left, top, width, height, NULL)
) {
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
g_object_unref(base);
return 0;
}
int flatten_image(VipsImage *in, VipsImage **out, double r, double g,
double b) {
if (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);
int code = vips_flatten(in, out, "background", vipsBackground, "max_alpha",
is_16bit(in->Type) ? 65535.0 : 255.0, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int is_16bit(VipsInterpretation interpretation) {
return interpretation == VIPS_INTERPRETATION_RGB16 ||
interpretation == VIPS_INTERPRETATION_GREY16;
}
int add_alpha(VipsImage *in, VipsImage **out) {
return vips_addalpha(in, out, NULL);
}
int premultiply_alpha(VipsImage *in, VipsImage **out) {
return vips_premultiply(in, out, "max_alpha", max_alpha(in), NULL);
}
int unpremultiply_alpha(VipsImage *in, VipsImage **out) {
return vips_unpremultiply(in, out, NULL);
}
int cast(VipsImage *in, VipsImage **out, int bandFormat) {
return vips_cast(in, out, bandFormat, NULL);
}
double max_alpha(VipsImage *in) {
switch (in->BandFmt) {
case VIPS_FORMAT_USHORT:
return 65535;
case VIPS_FORMAT_FLOAT:
case VIPS_FORMAT_DOUBLE:
return 1.0;
default:
return 255;
}
}
int composite_image(VipsImage **in, VipsImage **out, int n, int *mode, int *x,
int *y) {
VipsArrayInt *xs = vips_array_int_new(x, n - 1);
VipsArrayInt *ys = vips_array_int_new(y, n - 1);
int code = vips_composite(in, out, n, mode, "x", xs, "y", ys, NULL);
vips_area_unref(VIPS_AREA(xs));
vips_area_unref(VIPS_AREA(ys));
return code;
}
int composite2_image(VipsImage *base, VipsImage *overlay, VipsImage **out,
int mode, gint x, gint y) {
return vips_composite2(base, overlay, out, mode, "x", x, "y", y, NULL);
}
int insert_image(VipsImage *main, VipsImage *sub, VipsImage **out, int x, int y, int expand, double r, double g, double b, double a) {
if (is_16bit(main->Type)) {
r = 65535 * r / 255;
g = 65535 * g / 255;
b = 65535 * b / 255;
a = 65535 * a / 255;
}
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
// Ignore the alpha channel if the image doesn't have one
if (main->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
int code = vips_insert(main, sub, out, x, y, "expand", expand, "background", vipsBackground, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int join(VipsImage *in1, VipsImage *in2, VipsImage **out, int direction) {
return vips_join(in1, in2, out, direction, NULL);
}
int arrayjoin(VipsImage **in, VipsImage **out, int n, int across) {
return vips_arrayjoin(in, out, n, "across", across, NULL);
}
int replicate(VipsImage *in, VipsImage **out, int across, int down) {
return vips_replicate(in, out, across, down, NULL);
}
int grid(VipsImage *in, VipsImage **out, int tileHeight, int across, int down){
return vips_grid(in, out, tileHeight, across, down, NULL);
}
int adjust_gamma(VipsImage *in, VipsImage **out, double g) {
return vips_gamma(in, out, "exponent", g, NULL);
}

View File

@@ -1,520 +0,0 @@
package vips
// #cgo CFLAGS: -std=c99
// #include "conversion.h"
import "C"
// BandFormat represents VIPS_FORMAT type
type BandFormat int
// BandFormat enum
const (
BandFormatNotSet BandFormat = C.VIPS_FORMAT_NOTSET
BandFormatUchar BandFormat = C.VIPS_FORMAT_UCHAR
BandFormatChar BandFormat = C.VIPS_FORMAT_CHAR
BandFormatUshort BandFormat = C.VIPS_FORMAT_USHORT
BandFormatShort BandFormat = C.VIPS_FORMAT_SHORT
BandFormatUint BandFormat = C.VIPS_FORMAT_UINT
BandFormatInt BandFormat = C.VIPS_FORMAT_INT
BandFormatFloat BandFormat = C.VIPS_FORMAT_FLOAT
BandFormatComplex BandFormat = C.VIPS_FORMAT_COMPLEX
BandFormatDouble BandFormat = C.VIPS_FORMAT_DOUBLE
BandFormatDpComplex BandFormat = C.VIPS_FORMAT_DPCOMPLEX
)
// BlendMode gives the various Porter-Duff and PDF blend modes.
// See https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode
type BlendMode int
// Constants define the various Porter-Duff and PDF blend modes.
// See https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode
const (
BlendModeClear BlendMode = C.VIPS_BLEND_MODE_CLEAR
BlendModeSource BlendMode = C.VIPS_BLEND_MODE_SOURCE
BlendModeOver BlendMode = C.VIPS_BLEND_MODE_OVER
BlendModeIn BlendMode = C.VIPS_BLEND_MODE_IN
BlendModeOut BlendMode = C.VIPS_BLEND_MODE_OUT
BlendModeAtop BlendMode = C.VIPS_BLEND_MODE_ATOP
BlendModeDest BlendMode = C.VIPS_BLEND_MODE_DEST
BlendModeDestOver BlendMode = C.VIPS_BLEND_MODE_DEST_OVER
BlendModeDestIn BlendMode = C.VIPS_BLEND_MODE_DEST_IN
BlendModeDestOut BlendMode = C.VIPS_BLEND_MODE_DEST_OUT
BlendModeDestAtop BlendMode = C.VIPS_BLEND_MODE_DEST_ATOP
BlendModeXOR BlendMode = C.VIPS_BLEND_MODE_XOR
BlendModeAdd BlendMode = C.VIPS_BLEND_MODE_ADD
BlendModeSaturate BlendMode = C.VIPS_BLEND_MODE_SATURATE
BlendModeMultiply BlendMode = C.VIPS_BLEND_MODE_MULTIPLY
BlendModeScreen BlendMode = C.VIPS_BLEND_MODE_SCREEN
BlendModeOverlay BlendMode = C.VIPS_BLEND_MODE_OVERLAY
BlendModeDarken BlendMode = C.VIPS_BLEND_MODE_DARKEN
BlendModeLighten BlendMode = C.VIPS_BLEND_MODE_LIGHTEN
BlendModeColorDodge BlendMode = C.VIPS_BLEND_MODE_COLOUR_DODGE
BlendModeColorBurn BlendMode = C.VIPS_BLEND_MODE_COLOUR_BURN
BlendModeHardLight BlendMode = C.VIPS_BLEND_MODE_HARD_LIGHT
BlendModeSoftLight BlendMode = C.VIPS_BLEND_MODE_SOFT_LIGHT
BlendModeDifference BlendMode = C.VIPS_BLEND_MODE_DIFFERENCE
BlendModeExclusion BlendMode = C.VIPS_BLEND_MODE_EXCLUSION
)
// Direction represents VIPS_DIRECTION type
type Direction int
// Direction enum
const (
DirectionHorizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
DirectionVertical Direction = C.VIPS_DIRECTION_VERTICAL
)
// Angle represents VIPS_ANGLE type
type Angle int
// Angle enum
const (
Angle0 Angle = C.VIPS_ANGLE_D0
Angle90 Angle = C.VIPS_ANGLE_D90
Angle180 Angle = C.VIPS_ANGLE_D180
Angle270 Angle = C.VIPS_ANGLE_D270
)
// Angle45 represents VIPS_ANGLE45 type
type Angle45 int
// Angle45 enum
const (
Angle45_0 Angle45 = C.VIPS_ANGLE45_D0
Angle45_45 Angle45 = C.VIPS_ANGLE45_D45
Angle45_90 Angle45 = C.VIPS_ANGLE45_D90
Angle45_135 Angle45 = C.VIPS_ANGLE45_D135
Angle45_180 Angle45 = C.VIPS_ANGLE45_D180
Angle45_225 Angle45 = C.VIPS_ANGLE45_D225
Angle45_270 Angle45 = C.VIPS_ANGLE45_D270
Angle45_315 Angle45 = C.VIPS_ANGLE45_D315
)
// ExtendStrategy represents VIPS_EXTEND type
type ExtendStrategy int
// ExtendStrategy enum
const (
ExtendBlack ExtendStrategy = C.VIPS_EXTEND_BLACK
ExtendCopy ExtendStrategy = C.VIPS_EXTEND_COPY
ExtendRepeat ExtendStrategy = C.VIPS_EXTEND_REPEAT
ExtendMirror ExtendStrategy = C.VIPS_EXTEND_MIRROR
ExtendWhite ExtendStrategy = C.VIPS_EXTEND_WHITE
ExtendBackground ExtendStrategy = C.VIPS_EXTEND_BACKGROUND
)
// Interesting represents VIPS_INTERESTING type
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsInteresting
type Interesting int
// Interesting constants represent areas of interest which smart cropping will crop based on.
const (
InterestingNone Interesting = C.VIPS_INTERESTING_NONE
InterestingCentre Interesting = C.VIPS_INTERESTING_CENTRE
InterestingEntropy Interesting = C.VIPS_INTERESTING_ENTROPY
InterestingAttention Interesting = C.VIPS_INTERESTING_ATTENTION
InterestingLow Interesting = C.VIPS_INTERESTING_LOW
InterestingHigh Interesting = C.VIPS_INTERESTING_HIGH
InterestingAll Interesting = C.VIPS_INTERESTING_ALL
InterestingLast Interesting = C.VIPS_INTERESTING_LAST
)
func vipsCopyImageChangingInterpretation(in *C.VipsImage, interpretation Interpretation) (*C.VipsImage, error) {
var out *C.VipsImage
if err := C.copy_image_changing_interpretation(in, &out, C.VipsInterpretation(interpretation)); int(err) != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsCopyImageChangingResolution(in *C.VipsImage, xres float64, yres float64) (*C.VipsImage, error) {
var out *C.VipsImage
if err := C.copy_image_changing_resolution(in, &out, C.double(xres), C.double(yres)); int(err) != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-copy
func vipsCopyImage(in *C.VipsImage) (*C.VipsImage, error) {
var out *C.VipsImage
if err := C.copy_image(in, &out); int(err) != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-embed
func vipsEmbed(in *C.VipsImage, left, top, width, height int, extend ExtendStrategy) (*C.VipsImage, error) {
incOpCounter("embed")
var out *C.VipsImage
if err := C.embed_image(in, &out, C.int(left), C.int(top), C.int(width), C.int(height), C.int(extend)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-embed
func vipsEmbedBackground(in *C.VipsImage, left, top, width, height int, backgroundColor *ColorRGBA) (*C.VipsImage, error) {
incOpCounter("embed")
var out *C.VipsImage
if err := C.embed_image_background(in, &out, C.int(left), C.int(top), C.int(width),
C.int(height), C.double(backgroundColor.R),
C.double(backgroundColor.G), C.double(backgroundColor.B), C.double(backgroundColor.A)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsEmbedMultiPage(in *C.VipsImage, left, top, width, height int, extend ExtendStrategy) (*C.VipsImage, error) {
incOpCounter("embedMultiPage")
var out *C.VipsImage
if err := C.embed_multi_page_image(in, &out, C.int(left), C.int(top), C.int(width), C.int(height), C.int(extend)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsEmbedMultiPageBackground(in *C.VipsImage, left, top, width, height int, backgroundColor *ColorRGBA) (*C.VipsImage, error) {
incOpCounter("embedMultiPageBackground")
var out *C.VipsImage
if err := C.embed_multi_page_image_background(in, &out, C.int(left), C.int(top), C.int(width),
C.int(height), C.double(backgroundColor.R),
C.double(backgroundColor.G), C.double(backgroundColor.B), C.double(backgroundColor.A)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-flip
func vipsFlip(in *C.VipsImage, direction Direction) (*C.VipsImage, error) {
incOpCounter("flip")
var out *C.VipsImage
if err := C.flip_image(in, &out, C.int(direction)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-recomb
func vipsRecomb(in *C.VipsImage, m *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("recomb")
var out *C.VipsImage
if err := C.recomb_image(in, &out, m); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-extract-area
func vipsExtractArea(in *C.VipsImage, left, top, width, height int) (*C.VipsImage, error) {
incOpCounter("extractArea")
var out *C.VipsImage
if err := C.extract_image_area(in, &out, C.int(left), C.int(top), C.int(width), C.int(height)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsExtractAreaMultiPage(in *C.VipsImage, left, top, width, height int) (*C.VipsImage, error) {
incOpCounter("extractAreaMultiPage")
var out *C.VipsImage
if err := C.extract_area_multi_page(in, &out, C.int(left), C.int(top), C.int(width), C.int(height)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-extract-band
func vipsExtractBand(in *C.VipsImage, band, num int) (*C.VipsImage, error) {
incOpCounter("extractBand")
var out *C.VipsImage
if err := C.extract_band(in, &out, C.int(band), C.int(num)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// http://libvips.github.io/libvips/API/current/libvips-resample.html#vips-similarity
func vipsSimilarity(in *C.VipsImage, scale float64, angle float64, color *ColorRGBA,
idx float64, idy float64, odx float64, ody float64) (*C.VipsImage, error) {
incOpCounter("similarity")
var out *C.VipsImage
if err := C.similarity(in, &out, C.double(scale), C.double(angle),
C.double(color.R), C.double(color.G), C.double(color.B), C.double(color.A),
C.double(idx), C.double(idy), C.double(odx), C.double(ody)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// http://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-smartcrop
func vipsSmartCrop(in *C.VipsImage, width int, height int, interesting Interesting) (*C.VipsImage, error) {
incOpCounter("smartcrop")
var out *C.VipsImage
if err := C.smartcrop(in, &out, C.int(width), C.int(height), C.int(interesting)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// http://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-crop
func vipsCrop(in *C.VipsImage, left int, top int, width int, height int) (*C.VipsImage, error) {
incOpCounter("crop")
var out *C.VipsImage
if err := C.crop(in, &out, C.int(left), C.int(top), C.int(width), C.int(height)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-rot
func vipsRotate(in *C.VipsImage, angle Angle) (*C.VipsImage, error) {
incOpCounter("rot")
var out *C.VipsImage
if err := C.rot_image(in, &out, C.VipsAngle(angle)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-autorot
func vipsAutoRotate(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("autorot")
var out *C.VipsImage
if err := C.autorot_image(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-zoom
func vipsZoom(in *C.VipsImage, xFactor, yFactor int) (*C.VipsImage, error) {
incOpCounter("zoom")
var out *C.VipsImage
if err := C.zoom_image(in, &out, C.int(xFactor), C.int(yFactor)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-bandjoin
func vipsBandJoin(ins []*C.VipsImage) (*C.VipsImage, error) {
incOpCounter("bandjoin")
var out *C.VipsImage
if err := C.bandjoin(&ins[0], &out, C.int(len(ins))); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// http://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-bandjoin-const
func vipsBandJoinConst(in *C.VipsImage, constants []float64) (*C.VipsImage, error) {
incOpCounter("bandjoin_const")
var out *C.VipsImage
if err := C.bandjoin_const(in, &out, (*C.double)(&constants[0]), C.int(len(constants))); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-flatten
func vipsFlatten(in *C.VipsImage, color *Color) (*C.VipsImage, error) {
incOpCounter("flatten")
var out *C.VipsImage
err := C.flatten_image(in, &out, C.double(color.R), C.double(color.G), C.double(color.B))
if int(err) != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsAddAlpha(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("addAlpha")
var out *C.VipsImage
if err := C.add_alpha(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-premultiply
func vipsPremultiplyAlpha(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("premultiplyAlpha")
var out *C.VipsImage
if err := C.premultiply_alpha(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-unpremultiply
func vipsUnpremultiplyAlpha(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("unpremultiplyAlpha")
var out *C.VipsImage
if err := C.unpremultiply_alpha(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsCast(in *C.VipsImage, bandFormat BandFormat) (*C.VipsImage, error) {
incOpCounter("cast")
var out *C.VipsImage
if err := C.cast(in, &out, C.int(bandFormat)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-composite
func vipsComposite(ins []*C.VipsImage, modes []C.int, xs, ys []C.int) (*C.VipsImage, error) {
incOpCounter("composite_multi")
var out *C.VipsImage
if err := C.composite_image(&ins[0], &out, C.int(len(ins)), &modes[0], &xs[0], &ys[0]); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-composite2
func vipsComposite2(base *C.VipsImage, overlay *C.VipsImage, mode BlendMode, x, y int) (*C.VipsImage, error) {
incOpCounter("composite")
var out *C.VipsImage
if err := C.composite2_image(base, overlay, &out, C.int(mode), C.gint(x), C.gint(y)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsInsert(main *C.VipsImage, sub *C.VipsImage, x, y int, expand bool, background *ColorRGBA) (*C.VipsImage, error) {
incOpCounter("insert")
var out *C.VipsImage
if background == nil {
background = &ColorRGBA{R: 0.0, G: 0.0, B: 0.0, A: 255.0}
}
expandInt := 0
if expand {
expandInt = 1
}
if err := C.insert_image(main, sub, &out, C.int(x), C.int(y), C.int(expandInt), C.double(background.R), C.double(background.G), C.double(background.B), C.double(background.A)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-join
func vipsJoin(input1 *C.VipsImage, input2 *C.VipsImage, dir Direction) (*C.VipsImage, error) {
incOpCounter("join")
var out *C.VipsImage
defer C.g_object_unref(C.gpointer(input1))
defer C.g_object_unref(C.gpointer(input2))
if err := C.join(input1, input2, &out, C.int(dir)); err != 0 {
return nil, handleVipsError()
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-arrayjoin
func vipsArrayJoin(inputs []*C.VipsImage, across int) (*C.VipsImage, error) {
incOpCounter("arrayjoin")
var out *C.VipsImage
if err := C.arrayjoin(&inputs[0], &out, C.int(len(inputs)), C.int(across)); err != 0 {
return nil, handleVipsError()
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-conversion.html#vips-replicate
func vipsReplicate(in *C.VipsImage, across int, down int) (*C.VipsImage, error) {
incOpCounter("replicate")
var out *C.VipsImage
if err := C.replicate(in, &out, C.int(across), C.int(down)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-conversion.html#vips-grid
func vipsGrid(in *C.VipsImage, tileHeight, across, down int) (*C.VipsImage, error) {
incOpCounter("grid")
var out *C.VipsImage
if err := C.grid(in, &out, C.int(tileHeight), C.int(across), C.int(down)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsGamma(image *C.VipsImage, gamma float64) (*C.VipsImage, error) {
incOpCounter("gamma")
var out *C.VipsImage
if err := C.adjust_gamma(image, &out, C.double(gamma)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,70 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-conversion.html
#include <stdlib.h>
#include <vips/vips.h>
int copy_image_changing_interpretation(VipsImage *in, VipsImage **out,
VipsInterpretation interpretation);
int copy_image_changing_resolution(VipsImage *in, VipsImage **out, double xres,
double yres);
int copy_image(VipsImage *in, VipsImage **out);
int embed_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend);
int embed_image_background(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, double r, double g, double b, double a);
int embed_multi_page_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend);
int embed_multi_page_image_background(VipsImage *in, VipsImage **out, int left, int top,
int width, int height, double r, double g, double b, double a);
int flip_image(VipsImage *in, VipsImage **out, int direction);
int recomb_image(VipsImage *in, VipsImage **out, VipsImage *m);
int extract_image_area(VipsImage *in, VipsImage **out, int left, int top,
int width, int height);
int extract_area_multi_page(VipsImage *in, VipsImage **out, int left, int top,
int width, int height);
int extract_band(VipsImage *in, VipsImage **out, int band, int num);
int rot_image(VipsImage *in, VipsImage **out, VipsAngle angle);
int autorot_image(VipsImage *in, VipsImage **out);
int zoom_image(VipsImage *in, VipsImage **out, int xfac, int yfac);
int smartcrop(VipsImage *in, VipsImage **out, int width, int height,
int interesting);
int crop(VipsImage *in, VipsImage **out, int left, int top,
int width, int height);
int bandjoin(VipsImage **in, VipsImage **out, int n);
int bandjoin_const(VipsImage *in, VipsImage **out, double constants[], int n);
int similarity(VipsImage *in, VipsImage **out, double scale, double angle,
double r, double g, double b, double a, double idx, double idy,
double odx, double ody);
int flatten_image(VipsImage *in, VipsImage **out, double r, double g, double b);
int add_alpha(VipsImage *in, VipsImage **out);
int premultiply_alpha(VipsImage *in, VipsImage **out);
int unpremultiply_alpha(VipsImage *in, VipsImage **out);
int cast(VipsImage *in, VipsImage **out, int bandFormat);
double max_alpha(VipsImage *in);
int composite_image(VipsImage **in, VipsImage **out, int n, int *mode, int *x,
int *y);
int composite2_image(VipsImage *base, VipsImage *overlay, VipsImage **out,
int mode, gint x, gint y);
int insert_image(VipsImage *main, VipsImage *sub, VipsImage **out, int x, int y,
int expand, double r, double g, double b, double a);
int join(VipsImage *in1, VipsImage *in2, VipsImage **out, int direction);
int arrayjoin(VipsImage **in, VipsImage **out, int n, int across);
int is_16bit(VipsInterpretation interpretation);
int replicate(VipsImage *in, VipsImage **out, int across, int down);
int grid(VipsImage *in, VipsImage **out, int tileHeight, int across, int down);
int adjust_gamma(VipsImage *in, VipsImage **out, double g);

View File

@@ -1,14 +0,0 @@
#include "convolution.h"
int gaussian_blur_image(VipsImage *in, VipsImage **out, double sigma, double min_ampl) {
return vips_gaussblur(in, out, sigma, "min_ampl", min_ampl, NULL);
}
int sharpen_image(VipsImage *in, VipsImage **out, double sigma, double x1,
double m2) {
return vips_sharpen(in, out, "sigma", sigma, "x1", x1, "m2", m2, NULL);
}
int sobel_image(VipsImage *in, VipsImage **out) {
return vips_sobel(in, out, NULL);
}

View File

@@ -1,40 +0,0 @@
package vips
// #include "convolution.h"
import "C"
// https://libvips.github.io/libvips/API/current/libvips-convolution.html#vips-gaussblur
func vipsGaussianBlur(in *C.VipsImage, sigma, minAmpl float64) (*C.VipsImage, error) {
incOpCounter("gaussblur")
var out *C.VipsImage
if err := C.gaussian_blur_image(in, &out, C.double(sigma), C.double(minAmpl)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-convolution.html#vips-sharpen
func vipsSharpen(in *C.VipsImage, sigma float64, x1 float64, m2 float64) (*C.VipsImage, error) {
incOpCounter("sharpen")
var out *C.VipsImage
if err := C.sharpen_image(in, &out, C.double(sigma), C.double(x1), C.double(m2)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-convolution.html#vips-sobel
func vipsSobel(in *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("sobel")
var out *C.VipsImage
if err := C.sobel_image(in, &out); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,9 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-convolution.html
#include <stdlib.h>
#include <vips/vips.h>
int gaussian_blur_image(VipsImage *in, VipsImage **out, double sigma, double min_ampl);
int sharpen_image(VipsImage *in, VipsImage **out, double sigma, double x1,
double m2);
int sobel_image(VipsImage *in, VipsImage **out);

View File

@@ -1,24 +0,0 @@
// clang-format off
// include order matters
#include "lang.h"
#include "create.h"
// clang-format on
// https://libvips.github.io/libvips/API/current/libvips-create.html#vips-xyz
int xyz(VipsImage **out, int width, int height) {
return vips_xyz(out, width, height, NULL);
}
// http://libvips.github.io/libvips/API/current/libvips-create.html#vips-black
int black(VipsImage **out, int width, int height) {
return vips_black(out, width, height, NULL);
}
// https://libvips.github.io/libvips/API/current/libvips-create.html#vips-identity
int identity(VipsImage **out, int ushort) {
if (ushort > 0) {
return vips_identity(out, "ushort", TRUE, NULL);
} else {
return vips_identity(out, NULL);
}
}

View File

@@ -1,37 +0,0 @@
package vips
// #include "create.h"
import "C"
// https://libvips.github.io/libvips/API/current/libvips-create.html#vips-xyz
func vipsXYZ(width int, height int) (*C.VipsImage, error) {
var out *C.VipsImage
if err := C.xyz(&out, C.int(width), C.int(height)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// http://libvips.github.io/libvips/API/current/libvips-create.html#vips-black
func vipsBlack(width int, height int) (*C.VipsImage, error) {
var out *C.VipsImage
if err := C.black(&out, C.int(width), C.int(height)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-create.html#vips-identity
func vipsIdentity(ushort bool) (*C.VipsImage, error) {
var out *C.VipsImage
ushortInt := C.int(boolToInt(ushort))
if err := C.identity(&out, ushortInt); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,12 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-create.html
// clang-format off
// include order matters
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/foreign.h>
// clang-format on
int xyz(VipsImage **out, int width, int height);
int black(VipsImage **out, int width, int height);
int identity(VipsImage **out, int ushort);

View File

@@ -1,24 +0,0 @@
#include "draw.h"
#include "conversion.h"
int draw_rect(VipsImage *in, double r, double g, double b, double a, int left,
int top, int width, int height, int fill) {
if (is_16bit(in->Type)) {
r = 65535 * r / 255;
g = 65535 * g / 255;
b = 65535 * b / 255;
a = 65535 * a / 255;
}
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
if (in->Bands <= 3) {
return vips_draw_rect(in, background, 3, left, top, width, height, "fill",
fill, NULL);
} else {
return vips_draw_rect(in, backgroundRGBA, 4, left, top, width, height,
"fill", fill, NULL);
}
}

View File

@@ -1,21 +0,0 @@
package vips
// #include "draw.h"
import "C"
// https://libvips.github.io/libvips/API/current/libvips-draw.html#vips-draw-rect
func vipsDrawRect(in *C.VipsImage, color ColorRGBA, left int, top int, width int, height int, fill bool) error {
incOpCounter("draw_rect")
fillBit := 0
if fill {
fillBit = 1
}
if err := C.draw_rect(in, C.double(color.R), C.double(color.G), C.double(color.B), C.double(color.A),
C.int(left), C.int(top), C.int(width), C.int(height), C.int(fillBit)); err != 0 {
return handleImageError(in)
}
return nil
}

View File

@@ -1,7 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-draw.html
#include <stdlib.h>
#include <vips/vips.h>
int draw_rect(VipsImage *in, double r, double g, double b, double a, int left,
int top, int width, int height, int fill);

View File

@@ -29,50 +29,50 @@ int load_image_buffer(LoadParams *params, void *buf, size_t len,
// shrink: int, fail: bool, autorotate: bool
code = vips_jpegload_buffer(buf, len, out, "fail", params->fail,
"autorotate", params->autorotate, "shrink",
params->jpegShrink, NULL);
params->jpegShrink, "access", params->access, NULL);
} else if (imageType == PNG) {
code = vips_pngload_buffer(buf, len, out, NULL);
code = vips_pngload_buffer(buf, len, out, "access", params->access, NULL);
} else if (imageType == WEBP) {
// page: int, n: int, scale: double
code = vips_webpload_buffer(buf, len, out, "page", params->page, "n",
params->n, NULL);
params->n, "access", params->access, NULL);
} else if (imageType == TIFF) {
// page: int, n: int, autorotate: bool, subifd: int
code =
vips_tiffload_buffer(buf, len, out, "page", params->page, "n",
params->n, "autorotate", params->autorotate, NULL);
params->n, "autorotate", params->autorotate, "access", params->access, NULL);
} else if (imageType == GIF) {
// page: int, n: int, scale: double
code = vips_gifload_buffer(buf, len, out, "page", params->page, "n",
params->n, NULL);
params->n, "access", params->access, NULL);
} else if (imageType == PDF) {
// page: int, n: int, dpi: double, scale: double, background: color
code = vips_pdfload_buffer(buf, len, out, "page", params->page, "n",
params->n, "dpi", params->dpi, NULL);
params->n, "dpi", params->dpi, "access", params->access, NULL);
} else if (imageType == SVG) {
// dpi: double, scale: double, unlimited: bool
code = vips_svgload_buffer(buf, len, out, "dpi", params->dpi, "unlimited",
params->svgUnlimited, NULL);
params->svgUnlimited, "access", params->access, NULL);
} else if (imageType == HEIF) {
// added autorotate on load as currently it addresses orientation issues
// https://github.com/libvips/libvips/pull/1680
// page: int, n: int, thumbnail: bool
code = vips_heifload_buffer(buf, len, out, "page", params->page, "n",
params->n, "thumbnail", params->heifThumbnail,
"autorotate", TRUE, NULL);
"autorotate", TRUE, "access", params->access, NULL);
} else if (imageType == MAGICK) {
// page: int, n: int, density: string
code = vips_magickload_buffer(buf, len, out, "page", params->page, "n",
params->n, NULL);
params->n, "access", params->access, NULL);
} else if (imageType == AVIF) {
code = vips_heifload_buffer(buf, len, out, "page", params->page, "n",
params->n, "thumbnail", params->heifThumbnail,
"autorotate", params->autorotate, NULL);
"autorotate", params->autorotate, "access", params->access, NULL);
}
#if (VIPS_MAJOR_VERSION >= 8) && (VIPS_MINOR_VERSION >= 11)
else if (imageType == JP2K) {
code = vips_jp2kload_buffer(buf, len, out, "page", params->page, NULL);
code = vips_jp2kload_buffer(buf, len, out, "page", params->page, "access", params->access, NULL);
}
#endif
@@ -100,17 +100,20 @@ int set_jpegload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_BOOL(operation, params->autorotate, "autorotate");
MAYBE_SET_BOOL(operation, params->fail, "fail");
MAYBE_SET_INT(operation, params->jpegShrink, "shrink");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
int set_pngload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_BOOL(operation, params->fail, "fail");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
int set_webpload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
@@ -118,12 +121,14 @@ int set_tiffload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_BOOL(operation, params->autorotate, "autorotate");
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
int set_gifload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
@@ -131,12 +136,14 @@ int set_pdfload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_DOUBLE(operation, params->dpi, "dpi");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
int set_svgload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_BOOL(operation, params->svgUnlimited, "unlimited");
MAYBE_SET_DOUBLE(operation, params->dpi, "dpi");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
@@ -145,11 +152,13 @@ int set_heifload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_BOOL(operation, params->heifThumbnail, "thumbnail");
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
int set_jp2kload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
@@ -161,6 +170,7 @@ int set_jxlload_options(VipsOperation *operation, LoadParams *params) {
int set_magickload_options(VipsOperation *operation, LoadParams *params) {
MAYBE_SET_INT(operation, params->page, "page");
MAYBE_SET_INT(operation, params->n, "n");
MAYBE_SET_INT(operation, params->access, "access");
return 0;
}
@@ -319,7 +329,10 @@ int set_tiffsave_options(VipsOperation *operation, SaveParams *params) {
// https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-magicksave-buffer
int set_magicksave_options(VipsOperation *operation, SaveParams *params) {
int ret = vips_object_set(VIPS_OBJECT(operation), "format", "GIF", "bitdepth", params->gifBitdepth, NULL);
int ret = vips_object_set(VIPS_OBJECT(operation), "format", params->magickFormat,
"optimize_gif_frames", params->magickOptimizeGifFrames,
"optimize_gif_transparency", params->magickOptimizeGifTransparency,
"bitdepth", params->magickBitDepth, NULL);
if (!ret && params->quality) {
ret = vips_object_set(VIPS_OBJECT(operation), "quality", params->quality,
@@ -481,6 +494,11 @@ int save_to_buffer(SaveParams *params) {
#if (VIPS_MAJOR_VERSION >= 8) && (VIPS_MINOR_VERSION >= 12)
return save_buffer("gifsave_buffer", params, set_gifsave_options);
#else
// Gif save through ImageMagick below Vips Version 8.12
params->magickFormat="GIF";
params->magickOptimizeGifFrames=FALSE;
params->magickOptimizeGifTransparency=FALSE;
params->magickBitDepth=params->gifBitdepth;
return save_buffer("magicksave_buffer", params, set_magicksave_options);
#endif
case AVIF:
@@ -489,6 +507,8 @@ int save_to_buffer(SaveParams *params) {
return save_buffer("jp2ksave_buffer", params, set_jp2ksave_options);
case JXL:
return save_buffer("jxlsave_buffer", params, set_jxlsave_options);
case MAGICK:
return save_buffer("magicksave_buffer", params, set_magicksave_options);
default:
g_warning("Unsupported output type given: %d", params->outputFormat);
}
@@ -509,6 +529,7 @@ LoadParams create_load_params(ImageType inputFormat) {
.jpegShrink = defaultParam,
.heifThumbnail = defaultParam,
.svgUnlimited = defaultParam,
.access = defaultParam,
};
return p;
}

View File

@@ -5,13 +5,13 @@ import "C"
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"golang.org/x/image/bmp"
"golang.org/x/net/html/charset"
"image/png"
"math"
"runtime"
"unsafe"
"golang.org/x/net/html/charset"
)
// SubsampleMode correlates to a libvips subsample mode
@@ -44,8 +44,15 @@ const (
ImageTypeAVIF ImageType = C.AVIF
ImageTypeJP2K ImageType = C.JP2K
ImageTypeJXL ImageType = C.JXL
ImageTypePSD ImageType = C.PSD
)
// Types which should be deligated to ImageMagick loader
var imageMagickTypes = map[ImageType]bool{
ImageTypeBMP: true,
ImageTypePSD: true,
}
var imageTypeExtensionMap = map[ImageType]string{
ImageTypeGIF: ".gif",
ImageTypeJPEG: ".jpeg",
@@ -60,6 +67,7 @@ var imageTypeExtensionMap = map[ImageType]string{
ImageTypeAVIF: ".avif",
ImageTypeJP2K: ".jp2",
ImageTypeJXL: ".jxl",
ImageTypePSD: ".psd",
}
// ImageTypes defines the various image types supported by govips
@@ -77,6 +85,7 @@ var ImageTypes = map[ImageType]string{
ImageTypeAVIF: "heif",
ImageTypeJP2K: "jp2k",
ImageTypeJXL: "jxl",
ImageTypePSD: "psd",
}
// TiffCompression represents method for compressing a tiff at export
@@ -118,6 +127,15 @@ const (
PngFilterAll PngFilter = C.VIPS_FOREIGN_PNG_FILTER_ALL
)
// Access represents how libvips opens files.
// See https://www.libvips.org/API/current/How-it-opens-files.html
const (
AccessRandom int = C.VIPS_ACCESS_RANDOM
AccessSequential int = C.VIPS_ACCESS_SEQUENTIAL
AccessSequentialUnbuffered int = C.VIPS_ACCESS_SEQUENTIAL_UNBUFFERED
AccessLast int = C.VIPS_ACCESS_LAST
)
// FileExt returns the canonical extension for the ImageType
func (i ImageType) FileExt() string {
if ext, ok := imageTypeExtensionMap[i]; ok {
@@ -130,6 +148,11 @@ func (i ImageType) FileExt() string {
func IsTypeSupported(imageType ImageType) bool {
startupIfNeeded()
// BMP is supported via the magick loader
if imageType == ImageTypeBMP {
return supportedImageTypes[ImageTypeMagick]
}
return supportedImageTypes[imageType]
}
@@ -161,6 +184,10 @@ func DetermineImageType(buf []byte) ImageType {
return ImageTypeJXL
} else if isPDF(buf) {
return ImageTypePDF
} else if isICO(buf) {
return ImageTypeMagick
} else if isPSD(buf) {
return ImageTypePSD
} else {
return ImageTypeUnknown
}
@@ -200,12 +227,18 @@ func isWEBP(buf []byte) bool {
// https://github.com/strukturag/libheif/blob/master/libheif/heif.cc
var ftyp = []byte("ftyp")
var heic = []byte("heic")
var heix = []byte("heix")
var heim = []byte("heim")
var heis = []byte("heis")
var mif1 = []byte("mif1")
var msf1 = []byte("msf1")
var avif = []byte("avif")
func isHEIF(buf []byte) bool {
return bytes.Equal(buf[4:8], ftyp) && (bytes.Equal(buf[8:12], heic) ||
bytes.Equal(buf[8:12], heix) ||
bytes.Equal(buf[8:12], heim) ||
bytes.Equal(buf[8:12], heis) ||
bytes.Equal(buf[8:12], mif1) ||
bytes.Equal(buf[8:12], msf1)) ||
isAVIF(buf)
@@ -266,7 +299,29 @@ var jxlHeader = []byte("\xff\x0a")
var jxlHeaderISOBMFF = []byte("\x00\x00\x00\x0C\x4A\x58\x4C\x20\x0D\x0A\x87\x0A")
func isJXL(buf []byte) bool {
return bytes.HasPrefix(buf, jxlHeader) || bytes.HasPrefix(buf, jxlHeaderISOBMFF)
if len(buf) >= 2 && buf[0] == 0xFF && buf[1] == 0x0A {
return true
}
if len(buf) >= 8 && bytes.Equal(buf[4:8], []byte("JXL ")) {
return true
}
return false
}
var icoHeader = []byte("\x00\x00\x01\x00")
func isICO(buf []byte) bool {
return bytes.HasPrefix(buf, icoHeader)
}
var psdHeader = []byte("\x38\x42\x50\x53")
func isPSD(buf []byte) bool {
return bytes.HasPrefix(buf, psdHeader)
}
func isNeedToChangeLoaderToMagick(t ImageType) bool {
return imageMagickTypes[t]
}
func vipsLoadFromBuffer(buf []byte, params *ImportParams) (*C.VipsImage, ImageType, ImageType, error) {
@@ -274,18 +329,12 @@ func vipsLoadFromBuffer(buf []byte, params *ImportParams) (*C.VipsImage, ImageTy
// Reference src here so it's not garbage collected during image initialization.
defer runtime.KeepAlive(src)
var err error
originalType := DetermineImageType(src)
currentType := originalType
if originalType == ImageTypeBMP {
src, err = bmpToPNG(src)
if err != nil {
return nil, currentType, originalType, err
}
currentType = ImageTypePNG
// Map image types which are not supported by libvips itself to ImageMagick
if isNeedToChangeLoaderToMagick(originalType) {
currentType = ImageTypeMagick
}
if !IsTypeSupported(currentType) {
@@ -302,24 +351,6 @@ func vipsLoadFromBuffer(buf []byte, params *ImportParams) (*C.VipsImage, ImageTy
return importParams.outputImage, currentType, originalType, nil
}
func bmpToPNG(src []byte) ([]byte, error) {
i, err := bmp.Decode(bytes.NewReader(src))
if err != nil {
return nil, err
}
var w bytes.Buffer
pngEnc := png.Encoder{
CompressionLevel: png.NoCompression,
}
err = pngEnc.Encode(&w, i)
if err != nil {
return nil, err
}
return w.Bytes(), nil
}
func maybeSetBoolParam(p BoolParameter, cp *C.Param) {
if p.IsSet() {
C.set_bool_param(cp, toGboolean(p.Get()))
@@ -342,6 +373,7 @@ func createImportParams(format ImageType, params *ImportParams) C.LoadParams {
maybeSetIntParam(params.JpegShrinkFactor, &p.jpegShrink)
maybeSetBoolParam(params.HeifThumbnail, &p.heifThumbnail)
maybeSetBoolParam(params.SvgUnlimited, &p.svgUnlimited)
maybeSetIntParam(params.Access, &p.access)
if params.Density.IsSet() {
C.set_double_param(&p.dpi, C.gdouble(params.Density.Get()))
@@ -416,8 +448,16 @@ func vipsSaveTIFFToBuffer(in *C.VipsImage, params TiffExportParams) ([]byte, err
p.tiffCompression = C.VipsForeignTiffCompression(params.Compression)
p.tiffPyramid = C.int(boolToInt(params.Pyramid))
p.tiffTile = C.int(boolToInt(params.Tile))
p.tiffTileHeight = C.int(params.TileHeight)
p.tiffTileWidth = C.int(params.TileWidth)
tileHeight := params.TileHeight
tileWidth := params.TileWidth
if tileHeight <= 0 {
tileHeight = 256
}
if tileWidth <= 0 {
tileWidth = 256
}
p.tiffTileHeight = C.int(tileHeight)
p.tiffTileWidth = C.int(tileWidth)
return vipsSaveToBuffer(p)
}
@@ -500,6 +540,24 @@ func vipsSaveJxlToBuffer(in *C.VipsImage, params JxlExportParams) ([]byte, error
return vipsSaveToBuffer(p)
}
func vipsSaveMagickToBuffer(in *C.VipsImage, params MagickExportParams) ([]byte, error) {
incOpCounter("save_magick_buffer")
if params.Format == "" {
return nil, errors.New("magick format required")
}
p := C.create_save_params(C.MAGICK)
p.inputImage = in
p.outputFormat = C.MAGICK
p.quality = C.int(params.Quality)
p.magickFormat = C.CString(params.Format)
p.magickOptimizeGifFrames = C.int(boolToInt(params.OptimizeGifFrames))
p.magickOptimizeGifTransparency = C.int(boolToInt(params.OptimizeGifTransparency))
p.magickBitDepth = C.int(params.BitDepth)
return vipsSaveToBuffer(p)
}
func vipsSaveToBuffer(params C.struct_SaveParams) ([]byte, error) {
if err := C.save_to_buffer(&params); err != 0 {
return nil, handleSaveBufferError(params.outputBuffer)

View File

@@ -26,7 +26,8 @@ typedef enum types {
BMP,
AVIF,
JP2K,
JXL
JXL,
PSD,
} ImageType;
typedef enum ParamType {
@@ -66,6 +67,7 @@ typedef struct LoadParams {
Param jpegShrink;
Param heifThumbnail;
Param svgUnlimited;
Param access;
} LoadParams;
@@ -134,6 +136,12 @@ typedef struct SaveParams {
double jxlDistance;
int jxlEffort;
BOOL jxlLossless;
// MAGICK
char *magickFormat;
BOOL magickOptimizeGifFrames;
BOOL magickOptimizeGifTransparency;
int magickBitDepth;
} SaveParams;
SaveParams create_save_params(ImageType outputFormat);

View File

@@ -0,0 +1,139 @@
// Code generated by vipsgen. DO NOT EDIT.
//
// Enum types needed by generated code that are not yet defined in the
// hand-written codebase. These will move to gen_enums.go in Phase 4.
package vips
// #include <vips/vips.h>
import "C"
// Precision represents VipsPrecision for controlling computation precision.
type Precision int
const (
PrecisionInteger Precision = C.VIPS_PRECISION_INTEGER
PrecisionFloat Precision = C.VIPS_PRECISION_FLOAT
PrecisionApproximate Precision = C.VIPS_PRECISION_APPROXIMATE
)
// Combine represents VipsCombine for combining operations.
type Combine int
const (
CombineMax Combine = C.VIPS_COMBINE_MAX
CombineSum Combine = C.VIPS_COMBINE_SUM
CombineMin Combine = C.VIPS_COMBINE_MIN
)
// CombineMode represents VipsCombineMode for draw combine operations.
type CombineMode int
const (
CombineModeSet CombineMode = C.VIPS_COMBINE_MODE_SET
CombineModeAdd CombineMode = C.VIPS_COMBINE_MODE_ADD
)
// OperationBoolean represents VipsOperationBoolean for boolean operations.
type OperationBoolean int
const (
OperationBooleanAnd OperationBoolean = C.VIPS_OPERATION_BOOLEAN_AND
OperationBooleanOr OperationBoolean = C.VIPS_OPERATION_BOOLEAN_OR
OperationBooleanEor OperationBoolean = C.VIPS_OPERATION_BOOLEAN_EOR
OperationBooleanLshift OperationBoolean = C.VIPS_OPERATION_BOOLEAN_LSHIFT
OperationBooleanRshift OperationBoolean = C.VIPS_OPERATION_BOOLEAN_RSHIFT
)
// OperationComplex represents VipsOperationComplex for complex operations.
type OperationComplex int
const (
OperationComplexPolar OperationComplex = C.VIPS_OPERATION_COMPLEX_POLAR
OperationComplexRect OperationComplex = C.VIPS_OPERATION_COMPLEX_RECT
OperationComplexConj OperationComplex = C.VIPS_OPERATION_COMPLEX_CONJ
)
// OperationComplex2 represents VipsOperationComplex2 for binary complex operations.
type OperationComplex2 int
const (
OperationComplex2CrossPhase OperationComplex2 = C.VIPS_OPERATION_COMPLEX2_CROSS_PHASE
)
// OperationComplexget represents VipsOperationComplexget for getting complex components.
type OperationComplexget int
const (
OperationComplexgetReal OperationComplexget = C.VIPS_OPERATION_COMPLEXGET_REAL
OperationComplexgetImag OperationComplexget = C.VIPS_OPERATION_COMPLEXGET_IMAG
)
// OperationMath represents VipsOperationMath for math operations.
type OperationMath int
const (
OperationMathSin OperationMath = C.VIPS_OPERATION_MATH_SIN
OperationMathCos OperationMath = C.VIPS_OPERATION_MATH_COS
OperationMathTan OperationMath = C.VIPS_OPERATION_MATH_TAN
OperationMathAsin OperationMath = C.VIPS_OPERATION_MATH_ASIN
OperationMathAcos OperationMath = C.VIPS_OPERATION_MATH_ACOS
OperationMathAtan OperationMath = C.VIPS_OPERATION_MATH_ATAN
OperationMathLog OperationMath = C.VIPS_OPERATION_MATH_LOG
OperationMathLog10 OperationMath = C.VIPS_OPERATION_MATH_LOG10
OperationMathExp OperationMath = C.VIPS_OPERATION_MATH_EXP
OperationMathExp10 OperationMath = C.VIPS_OPERATION_MATH_EXP10
)
// OperationMath2 represents VipsOperationMath2 for binary math operations.
type OperationMath2 int
const (
OperationMath2Pow OperationMath2 = C.VIPS_OPERATION_MATH2_POW
OperationMath2Wop OperationMath2 = C.VIPS_OPERATION_MATH2_WOP
OperationMath2Atan2 OperationMath2 = C.VIPS_OPERATION_MATH2_ATAN2
)
// OperationRelational represents VipsOperationRelational for relational operations.
type OperationRelational int
const (
OperationRelationalEqual OperationRelational = C.VIPS_OPERATION_RELATIONAL_EQUAL
OperationRelationalNoteq OperationRelational = C.VIPS_OPERATION_RELATIONAL_NOTEQ
OperationRelationalLess OperationRelational = C.VIPS_OPERATION_RELATIONAL_LESS
OperationRelationalLesseq OperationRelational = C.VIPS_OPERATION_RELATIONAL_LESSEQ
OperationRelationalMore OperationRelational = C.VIPS_OPERATION_RELATIONAL_MORE
OperationRelationalMoreeq OperationRelational = C.VIPS_OPERATION_RELATIONAL_MOREEQ
)
// OperationRound represents VipsOperationRound for rounding operations.
type OperationRound int
const (
OperationRoundRint OperationRound = C.VIPS_OPERATION_ROUND_RINT
OperationRoundCeil OperationRound = C.VIPS_OPERATION_ROUND_CEIL
OperationRoundFloor OperationRound = C.VIPS_OPERATION_ROUND_FLOOR
)
// OperationMorphology represents VipsOperationMorphology for morphological operations.
type OperationMorphology int
const (
OperationMorphologyErode OperationMorphology = C.VIPS_OPERATION_MORPHOLOGY_ERODE
OperationMorphologyDilate OperationMorphology = C.VIPS_OPERATION_MORPHOLOGY_DILATE
)
// FailOn represents VipsFailOn for controlling error handling on load.
type FailOn int
const (
FailOnNone FailOn = C.VIPS_FAIL_ON_NONE
FailOnTruncated FailOn = C.VIPS_FAIL_ON_TRUNCATED
FailOnError FailOn = C.VIPS_FAIL_ON_ERROR
FailOnWarning FailOn = C.VIPS_FAIL_ON_WARNING
)
// ForeignKeep represents VipsForeignKeep flags for controlling metadata retention.
type ForeignKeep int
// Note: ForeignKeep is a flags (bitmask) type. Values combined with |.

View File

@@ -0,0 +1,3 @@
package vips
//go:generate go run ../cmd/vipsgen --generate --output=.

5228
vendor/github.com/davidbyttow/govips/v2/vips/generated.c generated vendored Normal file

File diff suppressed because it is too large Load Diff

5001
vendor/github.com/davidbyttow/govips/v2/vips/generated.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1181
vendor/github.com/davidbyttow/govips/v2/vips/generated.h generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ package vips
// #include "govips.h"
import "C"
import (
"errors"
"fmt"
"os"
"runtime"
@@ -56,9 +57,9 @@ type Config struct {
// Startup sets up the libvips support and ensures the versions are correct. Pass in nil for
// default configuration.
func Startup(config *Config) {
func Startup(config *Config) error {
if hasShutdown {
panic("govips cannot be stopped and restarted")
return errors.New("govips cannot be stopped and restarted")
}
initLock.Lock()
@@ -69,15 +70,15 @@ func Startup(config *Config) {
if running {
govipsLog("govips", LogLevelInfo, "warning libvips already started")
return
return nil
}
if MajorVersion < 8 {
panic("govips requires libvips version 8.10+")
return errors.New("govips requires libvips version 8.10+")
}
if MajorVersion == 8 && MinorVersion < 10 {
panic("govips requires libvips version 8.10+")
return errors.New("govips requires libvips version 8.10+")
}
cName := C.CString("govips")
@@ -93,7 +94,7 @@ func Startup(config *Config) {
err := C.vips_init(cName)
if err != 0 {
panic(fmt.Sprintf("Failed to start vips code=%v", err))
return fmt.Errorf("failed to start vips code=%v", err)
}
running = true
@@ -147,6 +148,7 @@ func Startup(config *Config) {
int(C.vips_cache_get_max())))
initTypes()
return nil
}
func enableLogging() {
@@ -234,7 +236,9 @@ func ReadVipsMemStats(stats *MemoryStats) {
func startupIfNeeded() {
if !running {
govipsLog("govips", LogLevelInfo, "libvips was forcibly started automatically, consider calling Startup/Shutdown yourself")
Startup(nil)
if err := Startup(nil); err != nil {
panic(err)
}
}
}

View File

@@ -1,122 +0,0 @@
#include "header.h"
#include <unistd.h>
unsigned long has_icc_profile(VipsImage *in) {
return vips_image_get_typeof(in, VIPS_META_ICC_NAME);
}
unsigned long get_icc_profile(VipsImage *in, const void **data,
size_t *dataLength) {
return image_get_blob(in, VIPS_META_ICC_NAME, data, dataLength);
}
gboolean remove_icc_profile(VipsImage *in) {
return vips_image_remove(in, VIPS_META_ICC_NAME);
}
unsigned long has_iptc(VipsImage *in) {
return vips_image_get_typeof(in, VIPS_META_IPTC_NAME);
}
char **image_get_fields(VipsImage *in) { return vips_image_get_fields(in); }
void image_set_string(VipsImage *in, const char *name, const char *str) {
vips_image_set_string(in, name, str);
}
unsigned long image_get_string(VipsImage *in, const char *name,
const char **out) {
return vips_image_get_string(in, name, out);
}
unsigned long image_get_as_string(VipsImage *in, const char *name, char **out) {
return vips_image_get_as_string(in, name, out);
}
void remove_field(VipsImage *in, char *field) { vips_image_remove(in, field); }
int get_meta_orientation(VipsImage *in) {
int orientation = 0;
if (vips_image_get_typeof(in, VIPS_META_ORIENTATION) != 0) {
vips_image_get_int(in, VIPS_META_ORIENTATION, &orientation);
}
return orientation;
}
void remove_meta_orientation(VipsImage *in) {
vips_image_remove(in, VIPS_META_ORIENTATION);
}
void set_meta_orientation(VipsImage *in, int orientation) {
vips_image_set_int(in, VIPS_META_ORIENTATION, orientation);
}
// https://libvips.github.io/libvips/API/current/libvips-header.html#vips-image-get-n-pages
int get_image_n_pages(VipsImage *in) {
int n_pages = 0;
n_pages = vips_image_get_n_pages(in);
return n_pages;
}
void set_image_n_pages(VipsImage *in, int n_pages) {
vips_image_set_int(in, VIPS_META_N_PAGES, n_pages);
}
// https://www.libvips.org/API/current/libvips-header.html#vips-image-get-page-height
int get_page_height(VipsImage *in) {
int page_height = 0;
page_height = vips_image_get_page_height(in);
return page_height;
}
void set_page_height(VipsImage *in, int height) {
vips_image_set_int(in, VIPS_META_PAGE_HEIGHT, height);
}
int get_meta_loader(const VipsImage *in, const char **out) {
return vips_image_get_string(in, VIPS_META_LOADER, out);
}
int get_image_delay(VipsImage *in, int **out) {
return vips_image_get_array_int(in, "delay", out, NULL);
}
void set_image_delay(VipsImage *in, const int *array, int n) {
return vips_image_set_array_int(in, "delay", array, n);
}
void image_set_double(VipsImage *in, const char *name, double i) {
vips_image_set_double(in, name, i);
}
unsigned long image_get_double(VipsImage *in, const char *name, double *out) {
return vips_image_get_double(in, name, out);
}
void image_set_int(VipsImage *in, const char *name, int i) {
vips_image_set_int(in, name, i);
}
unsigned long image_get_int(VipsImage *in, const char *name, int *out) {
return vips_image_get_int(in, name, out);
}
void image_set_blob(VipsImage *in, const char *name, const void *data,
size_t dataLength) {
vips_image_set_blob_copy(in, name, data, dataLength);
}
unsigned long image_get_blob(VipsImage *in, const char *name, const void **data,
size_t *dataLength) {
if (vips_image_get_typeof(in, name) == 0) {
return 0;
}
if (vips_image_get_blob(in, name, data, dataLength)) {
return -1;
}
return 0;
}

View File

@@ -1,289 +0,0 @@
package vips
// #include "header.h"
import "C"
import (
"strings"
"unsafe"
)
func vipsHasICCProfile(in *C.VipsImage) bool {
return int(C.has_icc_profile(in)) != 0
}
func vipsGetICCProfile(in *C.VipsImage) ([]byte, bool) {
var bufPtr unsafe.Pointer
var dataLength C.size_t
if int(C.get_icc_profile(in, &bufPtr, &dataLength)) != 0 {
return nil, false
}
buf := C.GoBytes(bufPtr, C.int(dataLength))
return buf, true
}
func vipsRemoveICCProfile(in *C.VipsImage) bool {
return fromGboolean(C.remove_icc_profile(in))
}
func vipsHasIPTC(in *C.VipsImage) bool {
return int(C.has_iptc(in)) != 0
}
func vipsImageGetFields(in *C.VipsImage) (fields []string) {
const maxFields = 256
rawFields := C.image_get_fields(in)
defer C.g_strfreev(rawFields)
cFields := (*[maxFields]*C.char)(unsafe.Pointer(rawFields))[:maxFields:maxFields]
for _, field := range cFields {
if field == nil {
break
}
fields = append(fields, C.GoString(field))
}
return
}
func vipsImageGetExifData(in *C.VipsImage) map[string]string {
fields := vipsImageGetFields(in)
exifData := map[string]string{}
for _, field := range fields {
if strings.HasPrefix(field, "exif") {
exifData[field] = vipsImageGetString(in, field)
}
}
return exifData
}
func vipsRemoveMetadata(in *C.VipsImage, keep ...string) {
fields := vipsImageGetFields(in)
retain := append(keep, technicalMetadata...)
for _, field := range fields {
if contains(retain, field) {
continue
}
cField := C.CString(field)
C.remove_field(in, cField)
C.free(unsafe.Pointer(cField))
}
}
var technicalMetadata = []string{
C.VIPS_META_ICC_NAME,
C.VIPS_META_ORIENTATION,
C.VIPS_META_N_PAGES,
C.VIPS_META_PAGE_HEIGHT,
}
func contains(a []string, x string) bool {
for _, n := range a {
if x == n {
return true
}
}
return false
}
func vipsGetMetaOrientation(in *C.VipsImage) int {
return int(C.get_meta_orientation(in))
}
func vipsRemoveMetaOrientation(in *C.VipsImage) {
C.remove_meta_orientation(in)
}
func vipsSetMetaOrientation(in *C.VipsImage, orientation int) {
C.set_meta_orientation(in, C.int(orientation))
}
func vipsGetImageNPages(in *C.VipsImage) int {
return int(C.get_image_n_pages(in))
}
func vipsSetImageNPages(in *C.VipsImage, pages int) {
C.set_image_n_pages(in, C.int(pages))
}
func vipsGetPageHeight(in *C.VipsImage) int {
return int(C.get_page_height(in))
}
func vipsSetPageHeight(in *C.VipsImage, height int) {
C.set_page_height(in, C.int(height))
}
func vipsImageGetMetaLoader(in *C.VipsImage) (string, bool) {
var out *C.char
defer freeCString(out)
code := int(C.get_meta_loader(in, &out))
return C.GoString(out), code == 0
}
func vipsImageGetDelay(in *C.VipsImage, n int) ([]int, error) {
incOpCounter("imageGetDelay")
var out *C.int
defer gFreePointer(unsafe.Pointer(out))
if err := C.get_image_delay(in, &out); err != 0 {
return nil, handleVipsError()
}
return fromCArrayInt(out, n), nil
}
func vipsImageSetDelay(in *C.VipsImage, data []C.int) error {
incOpCounter("imageSetDelay")
if n := len(data); n > 0 {
C.set_image_delay(in, &data[0], C.int(n))
}
return nil
}
// vipsDetermineImageTypeFromMetaLoader determine the image type from vips-loader metadata
func vipsDetermineImageTypeFromMetaLoader(in *C.VipsImage) ImageType {
vipsLoader, ok := vipsImageGetMetaLoader(in)
if vipsLoader == "" || !ok {
return ImageTypeUnknown
}
if strings.HasPrefix(vipsLoader, "jpeg") {
return ImageTypeJPEG
}
if strings.HasPrefix(vipsLoader, "png") {
return ImageTypePNG
}
if strings.HasPrefix(vipsLoader, "gif") {
return ImageTypeGIF
}
if strings.HasPrefix(vipsLoader, "svg") {
return ImageTypeSVG
}
if strings.HasPrefix(vipsLoader, "webp") {
return ImageTypeWEBP
}
if strings.HasPrefix(vipsLoader, "jp2k") {
return ImageTypeJP2K
}
if strings.HasPrefix(vipsLoader, "jxl") {
return ImageTypeJXL
}
if strings.HasPrefix(vipsLoader, "magick") {
return ImageTypeMagick
}
if strings.HasPrefix(vipsLoader, "tiff") {
return ImageTypeTIFF
}
if strings.HasPrefix(vipsLoader, "heif") {
return ImageTypeHEIF
}
if strings.HasPrefix(vipsLoader, "pdf") {
return ImageTypePDF
}
return ImageTypeUnknown
}
func vipsImageSetBlob(in *C.VipsImage, name string, data []byte) {
cData := unsafe.Pointer(&data)
cDataLength := C.size_t(len(data))
cField := C.CString(name)
defer freeCString(cField)
C.image_set_blob(in, cField, cData, cDataLength)
}
func vipsImageGetBlob(in *C.VipsImage, name string) []byte {
var bufPtr unsafe.Pointer
var dataLength C.size_t
cField := C.CString(name)
defer freeCString(cField)
if int(C.image_get_blob(in, cField, &bufPtr, &dataLength)) != 0 {
return nil
}
buf := C.GoBytes(bufPtr, C.int(dataLength))
return buf
}
func vipsImageSetDouble(in *C.VipsImage, name string, f float64) {
cField := C.CString(name)
defer freeCString(cField)
cDouble := C.double(f)
C.image_set_double(in, cField, cDouble)
}
func vipsImageGetDouble(in *C.VipsImage, name string) float64 {
cField := C.CString(name)
defer freeCString(cField)
var cDouble C.double
if int(C.image_get_double(in, cField, &cDouble)) == 0 {
return float64(cDouble)
}
return 0
}
func vipsImageSetInt(in *C.VipsImage, name string, i int) {
cField := C.CString(name)
defer freeCString(cField)
cInt := C.int(i)
C.image_set_int(in, cField, cInt)
}
func vipsImageGetInt(in *C.VipsImage, name string) int {
cField := C.CString(name)
defer freeCString(cField)
var cInt C.int
if int(C.image_get_int(in, cField, &cInt)) == 0 {
return int(cInt)
}
return 0
}
func vipsImageSetString(in *C.VipsImage, name string, str string) {
cField := C.CString(name)
defer freeCString(cField)
cStr := C.CString(str)
defer freeCString(cStr)
C.image_set_string(in, cField, cStr)
}
func vipsImageGetString(in *C.VipsImage, name string) string {
cField := C.CString(name)
defer freeCString(cField)
var cFieldValue *C.char
defer freeCString(cFieldValue)
if int(C.image_get_string(in, cField, &cFieldValue)) == 0 {
return C.GoString(cFieldValue)
}
return ""
}
func vipsImageGetAsString(in *C.VipsImage, name string) string {
cField := C.CString(name)
defer freeCString(cField)
var cFieldValue *C.char
defer freeCString(cFieldValue)
if int(C.image_get_as_string(in, cField, &cFieldValue)) == 0 {
return C.GoString(cFieldValue)
}
return ""
}

View File

@@ -1,41 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-header.html
#include <stdlib.h>
#include <vips/vips.h>
unsigned long has_icc_profile(VipsImage *in);
unsigned long get_icc_profile(VipsImage *in, const void **data,
size_t *dataLength);
int remove_icc_profile(VipsImage *in);
unsigned long has_iptc(VipsImage *in);
char **image_get_fields(VipsImage *in);
void image_set_string(VipsImage *in, const char *name, const char *str);
unsigned long image_get_string(VipsImage *in, const char *name,
const char **out);
unsigned long image_get_as_string(VipsImage *in, const char *name, char **out);
void remove_field(VipsImage *in, char *field);
int get_meta_orientation(VipsImage *in);
void remove_meta_orientation(VipsImage *in);
void set_meta_orientation(VipsImage *in, int orientation);
int get_image_n_pages(VipsImage *in);
void set_image_n_pages(VipsImage *in, int n_pages);
int get_page_height(VipsImage *in);
void set_page_height(VipsImage *in, int height);
int get_meta_loader(const VipsImage *in, const char **out);
int get_image_delay(VipsImage *in, int **out);
void set_image_delay(VipsImage *in, const int *array, int n);
void image_set_blob(VipsImage *in, const char *name, const void *data,
size_t dataLength);
unsigned long image_get_blob(VipsImage *in, const char *name, const void **data,
size_t *dataLength);
void image_set_double(VipsImage *in, const char *name, double i);
unsigned long image_get_double(VipsImage *in, const char *name, double *out);
void image_set_int(VipsImage *in, const char *name, int i);
unsigned long image_get_int(VipsImage *in, const char *name, int *out);

View File

@@ -677,16 +677,14 @@ func ensureLoadICCPath(name *string) (err error) {
return
}
var tempDirOnce sync.Once
var tempDirErr error
func getTemporaryDirectory() (string, error) {
if temporaryDirectory != "" {
return temporaryDirectory, nil
}
var err error
temporaryDirectory, err = os.MkdirTemp("", "govips-")
if err != nil {
return "", err
}
return temporaryDirectory, nil
tempDirOnce.Do(func() {
temporaryDirectory, tempDirErr = os.MkdirTemp("", "govips-")
})
return temporaryDirectory, tempDirErr
}
var lockIcc sync.Mutex

View File

@@ -7,3 +7,10 @@ void clear_image(VipsImage **image) {
// https://docs.gtk.org/gobject/method.Object.unref.html
if (G_IS_OBJECT(*image)) g_object_unref(*image);
}
VipsImage *create_image_from_memory_copy(const void *data, size_t size,
int width, int height, int bands,
VipsBandFormat format) {
return vips_image_new_from_memory_copy(data, size, width, height, bands,
format);
}

View File

@@ -8,7 +8,9 @@ import (
"errors"
"fmt"
"image"
"image/draw"
_ "image/gif"
"math"
_ "image/jpeg"
_ "image/png"
"io"
@@ -18,6 +20,8 @@ import (
"strings"
"sync"
"unsafe"
_ "golang.org/x/image/webp"
)
const GaussBlurDefaultMinAMpl = 0.2
@@ -113,6 +117,7 @@ type ImportParams struct {
JpegShrinkFactor IntParameter
HeifThumbnail BoolParameter
SvgUnlimited BoolParameter
Access IntParameter
}
// NewImportParams creates default ImportParams
@@ -149,6 +154,9 @@ func (i *ImportParams) OptionString() string {
if v := i.HeifThumbnail; v.IsSet() {
values = append(values, "thumbnail="+boolToStr(v.Get()))
}
if v := i.Access; v.IsSet() {
values = append(values, "access="+strconv.Itoa(v.Get()))
}
return strings.Join(values, ",")
}
@@ -325,16 +333,24 @@ func NewTiffExportParams() *TiffExportParams {
}
}
// GifExportParams are options when exporting a GIF to file or buffer
// Please note that if vips version is above 8.12, then `vips_gifsave_buffer` is used, and only `Dither`, `Effort`, `Bitdepth` is used.
// If vips version is below 8.12, then `vips_magicksave_buffer` is used, and only `Bitdepth`, `Quality` is used.
// StripMetadata does nothing to Gif images.
// GifExportParams are options when exporting a GIF to file or buffer.
//
// For vips 8.12+, native gifsave is used. The relevant parameters are Dither,
// Effort, and Bitdepth. Quality is ignored because native gifsave does not
// support a quality parameter.
//
// For vips below 8.12, magicksave is used as a fallback. The relevant
// parameters are Quality and Bitdepth.
//
// StripMetadata has no effect on GIF images.
type GifExportParams struct {
StripMetadata bool
Quality int
Dither float64
Effort int
Bitdepth int
// Quality is only used with vips < 8.12 (magicksave fallback).
// Ignored by native gifsave in vips 8.12+.
Quality int
Dither float64
Effort int
Bitdepth int
}
// NewGifExportParams creates default values for an export of a GIF image.
@@ -424,6 +440,22 @@ func NewJxlExportParams() *JxlExportParams {
}
}
// MagickExportParams are options when exporting an image to file or buffer by ImageMagick.
type MagickExportParams struct {
Quality int
Format string
OptimizeGifFrames bool
OptimizeGifTransparency bool
BitDepth int
}
// NewMagickExportParams creates default values for an export of an image by ImageMagick.
func NewMagickExportParams() *MagickExportParams {
return &MagickExportParams{
Quality: 75,
}
}
// NewImageFromReader loads an ImageRef from the given reader
func NewImageFromReader(r io.Reader) (*ImageRef, error) {
buf, err := io.ReadAll(r)
@@ -538,7 +570,7 @@ func (r *ImageRef) Metadata() *ImageMetadata {
// Copy creates a new copy of the given image.
func (r *ImageRef) Copy() (*ImageRef, error) {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return nil, err
}
@@ -548,7 +580,7 @@ func (r *ImageRef) Copy() (*ImageRef, error) {
// Copy creates a new copy of the given image with the new X and Y resolution (PPI).
func (r *ImageRef) CopyChangingResolution(xres, yres float64) (*ImageRef, error) {
out, err := vipsCopyImageChangingResolution(r.image, xres, yres)
out, err := vipsGenCopy(r.image, &CopyOptions{Xres: &xres, Yres: &yres})
if err != nil {
return nil, err
}
@@ -558,7 +590,7 @@ func (r *ImageRef) CopyChangingResolution(xres, yres float64) (*ImageRef, error)
// Copy creates a new copy of the given image with the interpretation.
func (r *ImageRef) CopyChangingInterpretation(interpretation Interpretation) (*ImageRef, error) {
out, err := vipsCopyImageChangingInterpretation(r.image, interpretation)
out, err := vipsGenCopy(r.image, &CopyOptions{Interpretation: &interpretation})
if err != nil {
return nil, err
}
@@ -569,20 +601,20 @@ func (r *ImageRef) CopyChangingInterpretation(interpretation Interpretation) (*I
// XYZ creates a two-band uint32 image where the elements in the first band have the value of their x coordinate
// and elements in the second band have their y coordinate.
func XYZ(width, height int) (*ImageRef, error) {
vipsImage, err := vipsXYZ(width, height)
vipsImage, err := vipsGenXyz(width, height, nil)
return newImageRef(vipsImage, ImageTypeUnknown, ImageTypeUnknown, nil), err
}
// Identity creates an identity lookup table, which will leave an image unchanged when applied with Maplut.
// Each entry in the table has a value equal to its position.
func Identity(ushort bool) (*ImageRef, error) {
img, err := vipsIdentity(ushort)
img, err := vipsGenIdentity(&IdentityOptions{Ushort: &ushort})
return newImageRef(img, ImageTypeUnknown, ImageTypeUnknown, nil), err
}
// Black creates a new black image of the specified size
func Black(width, height int) (*ImageRef, error) {
vipsImage, err := vipsBlack(width, height)
vipsImage, err := vipsGenBlack(width, height, nil)
imageRef := &ImageRef{
image: vipsImage,
}
@@ -590,6 +622,44 @@ func Black(width, height int) (*ImageRef, error) {
return imageRef, err
}
// Grey creates a horizontal gradient image (ramp from black to white).
// When uchar is true, pixel values are 0-255 uint8; when false, 0.0-1.0 float.
// Useful for creating gradient overlays when combined with rotation, BandJoin, and Composite.
func Grey(width, height int, uchar bool) (*ImageRef, error) {
img, err := vipsGenGrey(width, height, &GreyOptions{Uchar: &uchar})
if err != nil {
return nil, err
}
return newImageRef(img, ImageTypeUnknown, ImageTypeUnknown, nil), nil
}
// NewTransparentCanvas creates a fully transparent RGBA image of the given dimensions.
// The image is in sRGB color space with 4 bands (RGBA), all channels set to 0.
func NewTransparentCanvas(width, height int) (*ImageRef, error) {
ref, err := Black(width, height)
if err != nil {
return nil, err
}
if err := ref.ToColorSpace(InterpretationSRGB); err != nil {
ref.Close()
return nil, err
}
if err := ref.BandJoinConst([]float64{0}); err != nil {
ref.Close()
return nil, err
}
return ref, nil
}
// Text draws the string text to an image.
func Text(params *TextParams) (*ImageRef, error) {
img, err := vipsText(params)
return newImageRef(img, ImageTypeUnknown, ImageTypeUnknown, nil), err
}
func newImageRef(vipsImage *C.VipsImage, currentFormat ImageType, originalFormat ImageType, buf []byte) *ImageRef {
imageRef := &ImageRef{
image: vipsImage,
@@ -653,6 +723,7 @@ func (r *ImageRef) Bands() int {
// HasProfile returns if the image has an ICC profile embedded.
func (r *ImageRef) HasProfile() bool {
defer runtime.KeepAlive(r)
return vipsHasICCProfile(r.image)
}
@@ -663,16 +734,19 @@ func (r *ImageRef) HasICCProfile() bool {
// HasIPTC returns a boolean whether the image in question has IPTC data associated with it.
func (r *ImageRef) HasIPTC() bool {
defer runtime.KeepAlive(r)
return vipsHasIPTC(r.image)
}
// HasAlpha returns if the image has an alpha layer.
func (r *ImageRef) HasAlpha() bool {
defer runtime.KeepAlive(r)
return vipsHasAlpha(r.image)
}
// Orientation returns the orientation number as it appears in the EXIF, if present
func (r *ImageRef) Orientation() int {
defer runtime.KeepAlive(r)
return vipsGetMetaOrientation(r.image)
}
@@ -683,7 +757,7 @@ func (r *ImageRef) GetOrientation() int {
// SetOrientation sets the orientation in the EXIF header of the associated image.
func (r *ImageRef) SetOrientation(orientation int) error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -696,7 +770,7 @@ func (r *ImageRef) SetOrientation(orientation int) error {
// RemoveOrientation removes the EXIF orientation information of the image.
func (r *ImageRef) RemoveOrientation() error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -749,6 +823,7 @@ func (r *ImageRef) ColorSpace() Interpretation {
// IsColorSpaceSupported returns a boolean whether the image's color space is supported by libvips.
func (r *ImageRef) IsColorSpaceSupported() bool {
defer runtime.KeepAlive(r)
return vipsIsColorSpaceSupported(r.image)
}
@@ -761,6 +836,7 @@ func (r *ImageRef) Pages() int {
return 1
}
defer runtime.KeepAlive(r)
return vipsGetImageNPages(r.image)
}
@@ -772,7 +848,7 @@ func (r *ImageRef) GetPages() int {
// SetPages sets the number of pages in the Image
// For animated images this corresponds to the number of frames
func (r *ImageRef) SetPages(pages int) error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -785,19 +861,21 @@ func (r *ImageRef) SetPages(pages int) error {
// PageHeight return the height of a single page
func (r *ImageRef) PageHeight() int {
defer runtime.KeepAlive(r)
return vipsGetPageHeight(r.image)
}
// GetPageHeight return the height of a single page
// Deprecated use PageHeight() instead
func (r *ImageRef) GetPageHeight() int {
defer runtime.KeepAlive(r)
return vipsGetPageHeight(r.image)
}
// SetPageHeight set the height of a page
// For animated images this is used when "unrolling" back to frames
func (r *ImageRef) SetPageHeight(height int) error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -810,6 +888,7 @@ func (r *ImageRef) SetPageHeight(height int) error {
// PageDelay get the page delay array for animation
func (r *ImageRef) PageDelay() ([]int, error) {
defer runtime.KeepAlive(r)
n := vipsGetImageNPages(r.image)
if n <= 1 {
// should not call if not multi page
@@ -820,6 +899,7 @@ func (r *ImageRef) PageDelay() ([]int, error) {
// SetPageDelay set the page delay array for animation
func (r *ImageRef) SetPageDelay(delay []int) error {
defer runtime.KeepAlive(r)
var data []C.int
for _, d := range delay {
data = append(data, C.int(d))
@@ -827,6 +907,31 @@ func (r *ImageRef) SetPageDelay(delay []int) error {
return vipsImageSetDelay(r.image, data)
}
// Loop returns the loop count for animated images.
// A value of 0 means infinite looping.
func (r *ImageRef) Loop() int {
defer runtime.KeepAlive(r)
return vipsImageGetLoop(r.image)
}
// SetLoop sets the loop count for animated images.
// A value of 0 means infinite looping.
func (r *ImageRef) SetLoop(loop int) error {
defer runtime.KeepAlive(r)
vipsImageSetLoop(r.image, loop)
return nil
}
// Background get the background of image.
func (r *ImageRef) Background() ([]float64, error) {
defer runtime.KeepAlive(r)
out, err := vipsImageGetBackground(r.image)
if err != nil {
return nil, err
}
return out, nil
}
// Export creates a byte array of the image for use.
// The function returns a byte array that can be written to a file e.g. via os.WriteFile().
// N.B. govips does not currently have built-in support for directly exporting to a file.
@@ -1060,6 +1165,21 @@ func (r *ImageRef) ExportJxl(params *JxlExportParams) ([]byte, *ImageMetadata, e
return buf, r.newMetadata(ImageTypeJXL), nil
}
// ExportMagick exports the image as Format set in param to a buffer.
func (r *ImageRef) ExportMagick(params *MagickExportParams) ([]byte, *ImageMetadata, error) {
if params == nil {
params = NewMagickExportParams()
params.Format = "JPG"
}
buf, err := vipsSaveMagickToBuffer(r.image, *params)
if err != nil {
return nil, nil, err
}
return buf, r.newMetadata(ImageTypeMagick), nil
}
// CompositeMulti composites the given overlay image on top of the associated image with provided blending mode.
func (r *ImageRef) CompositeMulti(ins []*ImageComposite) error {
out, err := vipsComposite(toVipsCompositeStructs(r, ins))
@@ -1072,7 +1192,7 @@ func (r *ImageRef) CompositeMulti(ins []*ImageComposite) error {
// Composite composites the given overlay image on top of the associated image with provided blending mode.
func (r *ImageRef) Composite(overlay *ImageRef, mode BlendMode, x, y int) error {
out, err := vipsComposite2(r.image, overlay.image, mode, x, y)
out, err := vipsGenComposite2(r.image, overlay.image, mode, &Composite2Options{X: &x, Y: &y})
if err != nil {
return err
}
@@ -1082,7 +1202,11 @@ func (r *ImageRef) Composite(overlay *ImageRef, mode BlendMode, x, y int) error
// Insert draws the image on top of the associated image at the given coordinates.
func (r *ImageRef) Insert(sub *ImageRef, x, y int, expand bool, background *ColorRGBA) error {
out, err := vipsInsert(r.image, sub.image, x, y, expand, background)
insertOpts := &InsertOptions{Expand: &expand}
if background != nil {
insertOpts.Background = []float64{float64(background.R), float64(background.G), float64(background.B), float64(background.A)}
}
out, err := vipsGenInsert(r.image, sub.image, x, y, insertOpts)
if err != nil {
return err
}
@@ -1107,7 +1231,7 @@ func (r *ImageRef) ArrayJoin(images []*ImageRef, across int) error {
for i := range inputs {
inputs[i] = allImages[i].image
}
out, err := vipsArrayJoin(inputs, across)
out, err := vipsGenArrayjoin(inputs, &ArrayjoinOptions{Across: &across})
if err != nil {
return err
}
@@ -1117,7 +1241,7 @@ func (r *ImageRef) ArrayJoin(images []*ImageRef, across int) error {
// Mapim resamples an image using index to look up pixels
func (r *ImageRef) Mapim(index *ImageRef) error {
out, err := vipsMapim(r.image, index.image)
out, err := vipsGenMapim(r.image, index.image, nil)
if err != nil {
return err
}
@@ -1127,7 +1251,7 @@ func (r *ImageRef) Mapim(index *ImageRef) error {
// Maplut maps an image through another image acting as a LUT (Look Up Table)
func (r *ImageRef) Maplut(lut *ImageRef) error {
out, err := vipsMaplut(r.image, lut.image)
out, err := vipsGenMaplut(r.image, lut.image, nil)
if err != nil {
return err
}
@@ -1137,7 +1261,7 @@ func (r *ImageRef) Maplut(lut *ImageRef) error {
// ExtractBand extracts one or more bands out of the image (replacing the associated ImageRef)
func (r *ImageRef) ExtractBand(band int, num int) error {
out, err := vipsExtractBand(r.image, band, num)
out, err := vipsGenExtractBand(r.image, band, &ExtractBandOptions{N: &num})
if err != nil {
return err
}
@@ -1147,7 +1271,8 @@ func (r *ImageRef) ExtractBand(band int, num int) error {
// ExtractBandToImage extracts one or more bands out of the image to a new image
func (r *ImageRef) ExtractBandToImage(band int, num int) (*ImageRef, error) {
out, err := vipsExtractBand(r.image, band, num)
defer runtime.KeepAlive(r)
out, err := vipsGenExtractBand(r.image, band, &ExtractBandOptions{N: &num})
if err != nil {
return nil, err
}
@@ -1161,7 +1286,7 @@ func (r *ImageRef) BandJoin(images ...*ImageRef) error {
vipsImages = append(vipsImages, vipsImage.image)
}
out, err := vipsBandJoin(vipsImages)
out, err := vipsGenBandjoin(vipsImages)
if err != nil {
return err
}
@@ -1171,9 +1296,11 @@ func (r *ImageRef) BandJoin(images ...*ImageRef) error {
// BandSplit split an n-band image into n separate images..
func (r *ImageRef) BandSplit() ([]*ImageRef, error) {
defer runtime.KeepAlive(r)
var out []*ImageRef
n := 1
for i := 0; i < r.Bands(); i++ {
img, err := vipsExtractBand(r.image, i, 1)
img, err := vipsGenExtractBand(r.image, i, &ExtractBandOptions{N: &n})
if err != nil {
return out, err
}
@@ -1184,7 +1311,10 @@ func (r *ImageRef) BandSplit() ([]*ImageRef, error) {
// BandJoinConst appends a set of constant bands to an image.
func (r *ImageRef) BandJoinConst(constants []float64) error {
out, err := vipsBandJoinConst(r.image, constants)
if len(constants) == 0 {
return errors.New("BandJoinConst: empty constants slice")
}
out, err := vipsGenBandjoinConst(r.image, constants)
if err != nil {
return err
}
@@ -1215,7 +1345,7 @@ func (r *ImageRef) PremultiplyAlpha() error {
band := r.BandFormat()
out, err := vipsPremultiplyAlpha(r.image)
out, err := vipsGenPremultiply(r.image, nil)
if err != nil {
return err
}
@@ -1233,13 +1363,13 @@ func (r *ImageRef) UnpremultiplyAlpha() error {
return nil
}
unpremultiplied, err := vipsUnpremultiplyAlpha(r.image)
unpremultiplied, err := vipsGenUnpremultiply(r.image, nil)
if err != nil {
return err
}
defer clearImage(unpremultiplied)
out, err := vipsCast(unpremultiplied, r.preMultiplication.bandFormat)
out, err := vipsGenCast(unpremultiplied, r.preMultiplication.bandFormat, nil)
if err != nil {
return err
}
@@ -1251,7 +1381,7 @@ func (r *ImageRef) UnpremultiplyAlpha() error {
// Cast converts the image to a target band format
func (r *ImageRef) Cast(format BandFormat) error {
out, err := vipsCast(r.image, format)
out, err := vipsGenCast(r.image, format, nil)
if err != nil {
return err
}
@@ -1261,7 +1391,7 @@ func (r *ImageRef) Cast(format BandFormat) error {
// Add calculates a sum of the image + addend and stores it back in the image
func (r *ImageRef) Add(addend *ImageRef) error {
out, err := vipsAdd(r.image, addend.image)
out, err := vipsGenAdd(r.image, addend.image)
if err != nil {
return err
}
@@ -1271,7 +1401,7 @@ func (r *ImageRef) Add(addend *ImageRef) error {
// Multiply calculates the product of the image * multiplier and stores it back in the image
func (r *ImageRef) Multiply(multiplier *ImageRef) error {
out, err := vipsMultiply(r.image, multiplier.image)
out, err := vipsGenMultiply(r.image, multiplier.image)
if err != nil {
return err
}
@@ -1281,7 +1411,7 @@ func (r *ImageRef) Multiply(multiplier *ImageRef) error {
// Divide calculates the product of the image / denominator and stores it back in the image
func (r *ImageRef) Divide(denominator *ImageRef) error {
out, err := vipsDivide(r.image, denominator.image)
out, err := vipsGenDivide(r.image, denominator.image)
if err != nil {
return err
}
@@ -1296,7 +1426,7 @@ func (r *ImageRef) Linear(a, b []float64) error {
return errors.New("a and b must be of same length")
}
out, err := vipsLinear(r.image, a, b, len(a))
out, err := vipsGenLinear(r.image, a, b, nil)
if err != nil {
return err
}
@@ -1307,7 +1437,7 @@ func (r *ImageRef) Linear(a, b []float64) error {
// Linear1 runs Linear() with a single constant.
// See https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-linear1
func (r *ImageRef) Linear1(a, b float64) error {
out, err := vipsLinear1(r.image, a, b)
out, err := vipsGenLinear(r.image, []float64{a}, []float64{b}, nil)
if err != nil {
return err
}
@@ -1318,7 +1448,7 @@ func (r *ImageRef) Linear1(a, b float64) error {
// Adjusts the image's gamma value.
// See https://www.libvips.org/API/current/libvips-conversion.html#vips-gamma
func (r *ImageRef) Gamma(gamma float64) error {
out, err := vipsGamma(r.image, gamma)
out, err := vipsGenGamma(r.image, &GammaOptions{Exponent: &gamma})
if err != nil {
return err
}
@@ -1352,7 +1482,7 @@ func GetRotationAngleFromExif(orientation int) (Angle, bool) {
// Thus, calling AutoRotate for HEIF images is not needed.
// todo: use https://www.libvips.org/API/current/libvips-conversion.html#vips-autorot-remove-angle
func (r *ImageRef) AutoRotate() error {
out, err := vipsAutoRotate(r.image)
out, _, _, err := vipsGenAutorot(r.image)
if err != nil {
return err
}
@@ -1381,6 +1511,7 @@ func (r *ImageRef) ExtractArea(left, top, width, height int) error {
// GetICCProfile retrieves the ICC profile data (if any) from the image.
func (r *ImageRef) GetICCProfile() []byte {
defer runtime.KeepAlive(r)
bytes, _ := vipsGetICCProfile(r.image)
return bytes
}
@@ -1388,7 +1519,7 @@ func (r *ImageRef) GetICCProfile() []byte {
// RemoveICCProfile removes the ICC Profile information from the image.
// Typically, browsers and other software assume images without profile to be in the sRGB color space.
func (r *ImageRef) RemoveICCProfile() error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -1469,7 +1600,7 @@ func (r *ImageRef) OptimizeICCProfile() error {
// N.B. this function won't remove the ICC profile, orientation and pages metadata
// because govips needs it to correctly display the image.
func (r *ImageRef) RemoveMetadata(keep ...string) error {
out, err := vipsCopyImage(r.image)
out, err := vipsGenCopy(r.image, nil)
if err != nil {
return err
}
@@ -1486,42 +1617,52 @@ func (r *ImageRef) ImageFields() []string {
}
func (r *ImageRef) GetFields() []string {
defer runtime.KeepAlive(r)
return vipsImageGetFields(r.image)
}
func (r *ImageRef) SetBlob(name string, data []byte) {
defer runtime.KeepAlive(r)
vipsImageSetBlob(r.image, name, data)
}
func (r *ImageRef) GetBlob(name string) []byte {
defer runtime.KeepAlive(r)
return vipsImageGetBlob(r.image, name)
}
func (r *ImageRef) SetDouble(name string, f float64) {
defer runtime.KeepAlive(r)
vipsImageSetDouble(r.image, name, f)
}
func (r *ImageRef) GetDouble(name string) float64 {
defer runtime.KeepAlive(r)
return vipsImageGetDouble(r.image, name)
}
func (r *ImageRef) SetInt(name string, i int) {
defer runtime.KeepAlive(r)
vipsImageSetInt(r.image, name, i)
}
func (r *ImageRef) GetInt(name string) int {
defer runtime.KeepAlive(r)
return vipsImageGetInt(r.image, name)
}
func (r *ImageRef) SetString(name string, str string) {
defer runtime.KeepAlive(r)
vipsImageSetString(r.image, name, str)
}
func (r *ImageRef) GetString(name string) string {
defer runtime.KeepAlive(r)
return vipsImageGetString(r.image, name)
}
func (r *ImageRef) GetAsString(name string) string {
defer runtime.KeepAlive(r)
return vipsImageGetAsString(r.image, name)
}
@@ -1536,6 +1677,7 @@ func (r *ImageRef) HasExif() bool {
}
func (r *ImageRef) GetExif() map[string]string {
defer runtime.KeepAlive(r)
return vipsImageGetExifData(r.image)
}
@@ -1551,7 +1693,11 @@ func (r *ImageRef) ToColorSpace(interpretation Interpretation) error {
// Flatten removes the alpha channel from the image and replaces it with the background color
func (r *ImageRef) Flatten(backgroundColor *Color) error {
out, err := vipsFlatten(r.image, backgroundColor)
opts := &FlattenOptions{}
if backgroundColor != nil {
opts.Background = []float64{float64(backgroundColor.R), float64(backgroundColor.G), float64(backgroundColor.B)}
}
out, err := vipsGenFlatten(r.image, opts)
if err != nil {
return err
}
@@ -1569,7 +1715,7 @@ func (r *ImageRef) GaussianBlur(sigmas ...float64) error {
if len(sigmas) >= 2 {
minAmpl = sigmas[1]
}
out, err := vipsGaussianBlur(r.image, sigma, minAmpl)
out, err := vipsGenGaussblur(r.image, sigma, &GaussblurOptions{MinAmpl: &minAmpl})
if err != nil {
return err
}
@@ -1582,7 +1728,7 @@ func (r *ImageRef) GaussianBlur(sigmas ...float64) error {
// x1: flat/jaggy threshold
// m2: slope for jaggy areas
func (r *ImageRef) Sharpen(sigma float64, x1 float64, m2 float64) error {
out, err := vipsSharpen(r.image, sigma, x1, m2)
out, err := vipsGenSharpen(r.image, &SharpenOptions{Sigma: &sigma, X1: &x1, M2: &m2})
if err != nil {
return err
}
@@ -1592,7 +1738,7 @@ func (r *ImageRef) Sharpen(sigma float64, x1 float64, m2 float64) error {
// Apply Sobel edge detector to the image.
func (r *ImageRef) Sobel() error {
out, err := vipsSobel(r.image)
out, err := vipsGenSobel(r.image)
if err != nil {
return err
}
@@ -1676,7 +1822,7 @@ func (r *ImageRef) ModulateHSV(brightness, saturation float64, hue int) error {
// Invert inverts the image
func (r *ImageRef) Invert() error {
out, err := vipsInvert(r.image)
out, err := vipsGenInvert(r.image)
if err != nil {
return err
}
@@ -1686,7 +1832,8 @@ func (r *ImageRef) Invert() error {
// Average finds the average value in an image
func (r *ImageRef) Average() (float64, error) {
out, err := vipsAverage(r.image)
defer runtime.KeepAlive(r)
out, err := vipsGenAvg(r.image)
if err != nil {
return 0, err
}
@@ -1696,12 +1843,14 @@ func (r *ImageRef) Average() (float64, error) {
// FindTrim returns the bounding box of the non-border part of the image
// Returned values are left, top, width, height
func (r *ImageRef) FindTrim(threshold float64, backgroundColor *Color) (int, int, int, int, error) {
defer runtime.KeepAlive(r)
return vipsFindTrim(r.image, threshold, backgroundColor)
}
// GetPoint reads a single pixel on an image.
// The pixel values are returned in a slice of length n.
func (r *ImageRef) GetPoint(x int, y int) ([]float64, error) {
defer runtime.KeepAlive(r)
n := 3
if vipsHasAlpha(r.image) {
n = 4
@@ -1719,7 +1868,7 @@ func (r *ImageRef) GetPoint(x int, y int) ([]float64, error) {
//
// If there is more than one maxima or minima, one of them will be chosen at random.
func (r *ImageRef) Stats() error {
out, err := vipsStats(r.image)
out, err := vipsGenStats(r.image)
if err != nil {
return err
}
@@ -1731,7 +1880,7 @@ func (r *ImageRef) Stats() error {
// Find the histogram for all bands (producing a one-band histogram).
// char and uchar images are cast to uchar before histogramming, all other image types are cast to ushort.
func (r *ImageRef) HistogramFind() error {
out, err := vipsHistFind(r.image)
out, err := vipsGenHistFind(r.image, nil)
if err != nil {
return err
}
@@ -1741,7 +1890,7 @@ func (r *ImageRef) HistogramFind() error {
// HistogramCumulative form cumulative histogram.
func (r *ImageRef) HistogramCumulative() error {
out, err := vipsHistCum(r.image)
out, err := vipsGenHistCum(r.image)
if err != nil {
return err
}
@@ -1753,7 +1902,7 @@ func (r *ImageRef) HistogramCumulative() error {
// The maximum of each band becomes equal to the maximum index, so for example the max for a uchar
// image becomes 255. Normalise each band separately.
func (r *ImageRef) HistogramNormalise() error {
out, err := vipsHistNorm(r.image)
out, err := vipsGenHistNorm(r.image)
if err != nil {
return err
}
@@ -1765,11 +1914,13 @@ func (r *ImageRef) HistogramNormalise() error {
// `-sum(p * log2(p))`
// where p is histogram-value / sum-of-histogram-values.
func (r *ImageRef) HistogramEntropy() (float64, error) {
return vipsHistEntropy(r.image)
defer runtime.KeepAlive(r)
return vipsGenHistEntropy(r.image)
}
// DrawRect draws an (optionally filled) rectangle with a single colour
func (r *ImageRef) DrawRect(ink ColorRGBA, left int, top int, width int, height int, fill bool) error {
defer runtime.KeepAlive(r)
err := vipsDrawRect(r.image, ink, left, top, width, height, fill)
if err != nil {
return err
@@ -1777,11 +1928,50 @@ func (r *ImageRef) DrawRect(ink ColorRGBA, left int, top int, width int, height
return nil
}
// Subtract calculate subtract operation between two images.
func (r *ImageRef) Subtract(in2 *ImageRef) error {
out, err := vipsGenSubtract(r.image, in2.image)
if err != nil {
return err
}
r.setImage(out)
return nil
}
// Abs calculate abs operation.
func (r *ImageRef) Abs() error {
out, err := vipsGenAbs(r.image)
if err != nil {
return err
}
r.setImage(out)
return nil
}
// Project calculate project operation.
func (r *ImageRef) Project() (*ImageRef, *ImageRef, error) {
defer runtime.KeepAlive(r)
col, row, err := vipsGenProject(r.image)
if err != nil {
return nil, nil, err
}
return newImageRef(col, r.format, r.originalFormat, nil), newImageRef(row, r.format, r.originalFormat, nil), nil
}
// Min finds the minimum value in an image.
func (r *ImageRef) Min() (float64, int, int, error) {
defer runtime.KeepAlive(r)
return vipsMin(r.image)
}
// Rank does rank filtering on an image. A window of size width by height is passed over the image.
// At each position, the pixels inside the window are sorted into ascending order and the pixel at position
// index is output. index numbers from 0.
func (r *ImageRef) Rank(width int, height int, index int) error {
out, err := vipsRank(r.image, width, height, index)
out, err := vipsGenRank(r.image, width, height, index)
if err != nil {
return err
}
@@ -1815,7 +2005,7 @@ func (r *ImageRef) ResizeWithVScale(hScale, vScale float64, kernel Kernel) error
if vScale != -1 {
scale = vScale
}
newPageHeight := int(float64(pageHeight)*scale + 0.5)
newPageHeight := int(math.Round(float64(pageHeight) * scale))
if err := r.SetPageHeight(newPageHeight); err != nil {
return err
}
@@ -1909,7 +2099,7 @@ func (r *ImageRef) EmbedBackgroundRGBA(left, top, width, height int, backgroundC
// Zoom zooms the image by repeating pixels (fast nearest-neighbour)
func (r *ImageRef) Zoom(xFactor int, yFactor int) error {
out, err := vipsZoom(r.image, xFactor, yFactor)
out, err := vipsGenZoom(r.image, xFactor, yFactor)
if err != nil {
return err
}
@@ -1917,6 +2107,16 @@ func (r *ImageRef) Zoom(xFactor int, yFactor int) error {
return nil
}
func (r *ImageRef) Gravity(gravity Gravity, width int, height int) error {
out, err := vipsGenGravity(r.image, gravity, width, height, nil)
if err != nil {
return err
}
r.setImage(out)
return nil
}
// Flip flips the image either horizontally or vertically based on the parameter
func (r *ImageRef) Flip(direction Direction) error {
out, err := vipsFlip(r.image, direction)
@@ -1945,7 +2145,7 @@ func (r *ImageRef) Recomb(matrix [][]float64) error {
}
// Flatten the matrix
var matrixValues []float64
matrixValues := make([]float64, 0, numBands*numBands)
for _, row := range matrix {
for _, value := range row {
matrixValues = append(matrixValues, value)
@@ -1958,6 +2158,7 @@ func (r *ImageRef) Recomb(matrix [][]float64) error {
// Create a VipsImage from the matrix in memory
matrixImage := C.vips_image_new_from_memory(matrixPtr, matrixSize, C.int(numBands), C.int(numBands), 1, C.VIPS_FORMAT_DOUBLE)
defer clearImage(matrixImage)
// Check for any Vips errors
errMsg := C.GoString(C.vips_error_buffer())
@@ -1967,7 +2168,8 @@ func (r *ImageRef) Recomb(matrix [][]float64) error {
}
// Recombine the image using the matrix
out, err := vipsRecomb(r.image, matrixImage)
out, err := vipsGenRecomb(r.image, matrixImage)
runtime.KeepAlive(matrixValues)
if err != nil {
return err
}
@@ -1999,7 +2201,7 @@ func (r *ImageRef) Rotate(angle Angle) error {
}
out, err := vipsRotate(r.image, angle)
out, err := vipsGenRot(r.image, angle)
if err != nil {
return err
}
@@ -2029,7 +2231,7 @@ func (r *ImageRef) Similarity(scale float64, angle float64, backgroundColor *Col
// Grid tiles the image pages into a matrix across*down
func (r *ImageRef) Grid(tileHeight, across, down int) error {
out, err := vipsGrid(r.image, tileHeight, across, down)
out, err := vipsGenGrid(r.image, tileHeight, across, down)
if err != nil {
return err
}
@@ -2069,7 +2271,7 @@ func (r *ImageRef) Label(labelParams *LabelParams) error {
// Replicate repeats an image many times across and down
func (r *ImageRef) Replicate(across int, down int) error {
out, err := vipsReplicate(r.image, across, down)
out, err := vipsGenReplicate(r.image, across, down)
if err != nil {
return err
}
@@ -2079,6 +2281,7 @@ func (r *ImageRef) Replicate(across int, down int) error {
// ToBytes writes the image to memory in VIPs format and returns the raw bytes, useful for storage.
func (r *ImageRef) ToBytes() ([]byte, error) {
defer runtime.KeepAlive(r)
var cSize C.size_t
cData := C.vips_image_write_to_memory(r.image, &cSize)
if cData == nil {
@@ -2092,7 +2295,9 @@ func (r *ImageRef) ToBytes() ([]byte, error) {
func (r *ImageRef) determineInputICCProfile() (inputProfile string) {
if r.Interpretation() == InterpretationCMYK {
inputProfile = "cmyk"
if !r.HasICCProfile() {
inputProfile = "cmyk"
}
}
return
}
@@ -2113,6 +2318,139 @@ func (r *ImageRef) ToImage(params *ExportParams) (image.Image, error) {
return img, nil
}
// ToGoImage converts a vips image directly to a Go image.Image without encoding.
// This is significantly faster than ToImage() which round-trips through JPEG/PNG.
// The resulting image will be in sRGB color space with 8-bit depth.
func (r *ImageRef) ToGoImage() (image.Image, error) {
defer runtime.KeepAlive(r)
// Work on a copy to avoid mutating the receiver
tmp, err := vipsGenCopy(r.image, nil)
if err != nil {
return nil, err
}
defer clearImage(tmp)
// Convert to sRGB if needed (keep B_W for grayscale)
interp := Interpretation(int(tmp.Type))
if interp != InterpretationSRGB && interp != InterpretationBW {
out, err := vipsToColorSpace(tmp, InterpretationSRGB)
if err != nil {
return nil, err
}
clearImage(tmp)
tmp = out
}
// Cast to uchar if needed
if BandFormat(int(tmp.BandFmt)) != BandFormatUchar {
out, err := vipsGenCast(tmp, BandFormatUchar, nil)
if err != nil {
return nil, err
}
clearImage(tmp)
tmp = out
}
// Extract raw pixel data
var cSize C.size_t
cData := C.vips_image_write_to_memory(tmp, &cSize)
if cData == nil {
return nil, errors.New("failed to write image to memory")
}
defer C.free(cData)
width := int(tmp.Xsize)
height := int(tmp.Ysize)
bands := int(tmp.Bands)
pixels := C.GoBytes(unsafe.Pointer(cData), C.int(cSize))
switch bands {
case 1:
img := image.NewGray(image.Rect(0, 0, width, height))
copy(img.Pix, pixels)
return img, nil
case 2:
// Grayscale + alpha
img := image.NewNRGBA(image.Rect(0, 0, width, height))
srcIdx := 0
dstIdx := 0
for srcIdx+1 < len(pixels) {
v := pixels[srcIdx]
img.Pix[dstIdx] = v
img.Pix[dstIdx+1] = v
img.Pix[dstIdx+2] = v
img.Pix[dstIdx+3] = pixels[srcIdx+1]
srcIdx += 2
dstIdx += 4
}
return img, nil
case 3:
// RGB, add opaque alpha
img := image.NewNRGBA(image.Rect(0, 0, width, height))
srcIdx := 0
dstIdx := 0
for srcIdx+2 < len(pixels) {
img.Pix[dstIdx] = pixels[srcIdx]
img.Pix[dstIdx+1] = pixels[srcIdx+1]
img.Pix[dstIdx+2] = pixels[srcIdx+2]
img.Pix[dstIdx+3] = 255
srcIdx += 3
dstIdx += 4
}
return img, nil
case 4:
img := image.NewNRGBA(image.Rect(0, 0, width, height))
copy(img.Pix, pixels)
return img, nil
default:
return nil, fmt.Errorf("unsupported number of bands: %d", bands)
}
}
// NewImageFromGoImage creates a new ImageRef from a Go image.Image.
// The image is normalized to NRGBA (non-premultiplied RGBA, 8-bit) and
// imported into libvips in sRGB color space.
func NewImageFromGoImage(img image.Image) (*ImageRef, error) {
startupIfNeeded()
bounds := img.Bounds()
width := bounds.Dx()
height := bounds.Dy()
if width == 0 || height == 0 {
return nil, errors.New("image has zero dimensions")
}
// Normalize to NRGBA
var nrgba *image.NRGBA
if n, ok := img.(*image.NRGBA); ok && n.Rect.Min.X == 0 && n.Rect.Min.Y == 0 && n.Stride == width*4 {
nrgba = n
} else {
nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
draw.Draw(nrgba, nrgba.Bounds(), img, bounds.Min, draw.Src)
}
// Create vips image from pixel data (copies data, safe for Go GC)
vipsImage := C.create_image_from_memory_copy(
unsafe.Pointer(&nrgba.Pix[0]),
C.size_t(len(nrgba.Pix)),
C.int(width),
C.int(height),
4,
C.VIPS_FORMAT_UCHAR,
)
runtime.KeepAlive(nrgba)
if vipsImage == nil {
return nil, errors.New("failed to create vips image from memory")
}
// Set interpretation to sRGB
vipsImage.Type = C.VIPS_INTERPRETATION_sRGB
return newImageRef(vipsImage, ImageTypeUnknown, ImageTypeUnknown, nil), nil
}
// setImage resets the image for this image and frees the previous one
func (r *ImageRef) setImage(image *C.VipsImage) {
r.lock.Lock()

View File

@@ -6,3 +6,7 @@
int has_alpha_channel(VipsImage *image);
void clear_image(VipsImage **image);
VipsImage *create_image_from_memory_copy(const void *data, size_t size,
int width, int height, int bands,
VipsBandFormat format);

View File

@@ -0,0 +1,20 @@
package vips
// #include <vips/vips.h>
import "C"
import "unsafe"
// NewInterpolate creates a VipsInterpolate from a name string.
// Common names: "nearest", "bilinear", "bicubic", "nohalo", "vsqbs", "lbb".
// The caller should call g_object_unref on the result when done, or pass it
// to a generated operation (which does not take ownership).
func NewInterpolate(name string) (*C.VipsInterpolate, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
interp := C.vips_interpolate_new(cName)
if interp == nil {
return nil, handleVipsError()
}
return interp, nil
}

View File

@@ -1,37 +0,0 @@
#include "label.h"
int text(VipsImage **out, const char *text, const char *font, int width,
int height, VipsAlign align, int dpi) {
return vips_text(out, text, "font", font, "width", width, "height", height,
"align", align, "dpi", dpi, NULL);
}
int label(VipsImage *in, VipsImage **out, LabelOptions *o) {
double ones[3] = {1, 1, 1};
VipsImage *base = vips_image_new();
VipsImage **t = (VipsImage **)vips_object_local_array(VIPS_OBJECT(base), 9);
if (vips_text(&t[0], o->Text, "font", o->Font, "width", o->Width, "height",
o->Height, "align", o->Align, NULL) ||
vips_linear1(t[0], &t[1], o->Opacity, 0.0, NULL) ||
vips_cast(t[1], &t[2], VIPS_FORMAT_UCHAR, NULL) ||
vips_embed(t[2], &t[3], o->OffsetX, o->OffsetY, t[2]->Xsize + o->OffsetX,
t[2]->Ysize + o->OffsetY, NULL)) {
g_object_unref(base);
return 1;
}
if (vips_black(&t[4], 1, 1, NULL) ||
vips_linear(t[4], &t[5], ones, o->Color, 3, NULL) ||
vips_cast(t[5], &t[6], VIPS_FORMAT_UCHAR, NULL) ||
vips_copy(t[6], &t[7], "interpretation", in->Type, NULL) ||
vips_embed(t[7], &t[8], 0, 0, in->Xsize, in->Ysize, "extend",
VIPS_EXTEND_COPY, NULL)) {
g_object_unref(base);
return 1;
}
if (vips_ifthenelse(t[3], t[8], in, out, "blend", TRUE, NULL)) {
g_object_unref(base);
return 1;
}
g_object_unref(base);
return 0;
}

View File

@@ -1,84 +0,0 @@
package vips
// #include "label.h"
import "C"
import "unsafe"
// Align represents VIPS_ALIGN
type Align int
// Direction enum
const (
AlignLow Align = C.VIPS_ALIGN_LOW
AlignCenter Align = C.VIPS_ALIGN_CENTRE
AlignHigh Align = C.VIPS_ALIGN_HIGH
)
// DefaultFont is the default font to be used for label texts created by govips
const DefaultFont = "sans 10"
// LabelParams represents a text-based label
type LabelParams struct {
Text string
Font string
Width Scalar
Height Scalar
OffsetX Scalar
OffsetY Scalar
Opacity float32
Color Color
Alignment Align
}
type vipsLabelOptions struct {
Text *C.char
Font *C.char
Width C.int
Height C.int
OffsetX C.int
OffsetY C.int
Alignment C.VipsAlign
DPI C.int
Margin C.int
Opacity C.float
Color [3]C.double
}
func labelImage(in *C.VipsImage, params *LabelParams) (*C.VipsImage, error) {
incOpCounter("label")
var out *C.VipsImage
text := C.CString(params.Text)
defer freeCString(text)
font := C.CString(params.Font)
defer freeCString(font)
// todo: release color?
color := [3]C.double{C.double(params.Color.R), C.double(params.Color.G), C.double(params.Color.B)}
w := params.Width.GetRounded(int(in.Xsize))
h := params.Height.GetRounded(int(in.Ysize))
offsetX := params.OffsetX.GetRounded(int(in.Xsize))
offsetY := params.OffsetY.GetRounded(int(in.Ysize))
opts := vipsLabelOptions{
Text: text,
Font: font,
Width: C.int(w),
Height: C.int(h),
OffsetX: C.int(offsetX),
OffsetY: C.int(offsetY),
Alignment: C.VipsAlign(params.Alignment),
Opacity: C.float(params.Opacity),
Color: color,
}
// todo: release inline pointer?
err := C.label(in, &out, (*C.LabelOptions)(unsafe.Pointer(&opts)))
if err != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,21 +0,0 @@
#include <stdlib.h>
#include <vips/vips.h>
typedef struct {
const char *Text;
const char *Font;
int Width;
int Height;
int OffsetX;
int OffsetY;
VipsAlign Align;
int DPI;
int Margin;
float Opacity;
double Color[3];
} LabelOptions;
int label(VipsImage *in, VipsImage **out, LabelOptions *o);
int text(VipsImage **out, const char *text, const char *font, int width,
int height, VipsAlign align, int dpi);

View File

@@ -47,3 +47,16 @@ func fromCArrayInt(out *C.int, n int) []int {
}
return result
}
func fromCArrayDouble(out *C.double, n int) []float64 {
if out == nil || n <= 0 {
return nil
}
data := make([]float64, n)
for i := 0; i < n; i++ {
data[i] = float64(*(*C.double)(unsafe.Pointer(uintptr(unsafe.Pointer(out)) + uintptr(i)*unsafe.Sizeof(C.double(0)))))
}
return data
}

View File

@@ -1,4 +1,2 @@
#include <stdlib.h>
#include <vips/vips.h>
#define INT_TO_GBOOLEAN(bool) (bool > 0 ? TRUE : FALSE)

View File

@@ -1,6 +0,0 @@
#include "morphology.h"
int rank(VipsImage *in, VipsImage **out, int width, int height, int index) {
return vips_rank(in, out, width, height, index, NULL);
}

View File

@@ -1,17 +0,0 @@
package vips
// #include "morphology.h"
import "C"
// https://libvips.github.io/libvips/API/current/libvips-morphology.html#vips-rank
func vipsRank(in *C.VipsImage, width int, height int, index int) (*C.VipsImage, error) {
incOpCounter("rank")
var out *C.VipsImage
err := C.rank(in, &out, C.int(width), C.int(height), C.int(index))
if int(err) != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,6 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-morphology.html
#include <stdlib.h>
#include <vips/vips.h>
int rank(VipsImage *in, VipsImage **out, int width, int height, int index);

View File

@@ -0,0 +1,503 @@
// operations.c - Hand-written C bridge functions for libvips operations
#include "lang.h"
#include "operations.h"
#include <unistd.h>
static int is_16bit(VipsInterpretation interpretation);
// Arithmetic
int find_trim(VipsImage *in, int *left, int *top, int *width, int *height,
double threshold, double r, double g, double b) {
if (in->Type == VIPS_INTERPRETATION_RGB16 || in->Type == VIPS_INTERPRETATION_GREY16) {
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);
int code = vips_find_trim(in, left, top, width, height, "threshold", threshold, "background", vipsBackground, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int getpoint(VipsImage *in, double **vector, int n, int x, int y) {
return vips_getpoint(in, vector, &n, x, y, NULL);
}
int minOp(VipsImage *in, double *out, int *x, int *y, int size) {
return vips_min(in, out, "x", x, "y", y, "size", size, NULL);
}
// Color
int is_colorspace_supported(VipsImage *in) {
return vips_colourspace_issupported(in) ? 1 : 0;
}
int to_colorspace(VipsImage *in, VipsImage **out, VipsInterpretation space) {
return vips_colourspace(in, out, space, NULL);
}
// https://libvips.github.io/libvips/API/8.6/libvips-colour.html#vips-icc-transform
int icc_transform(VipsImage *in, VipsImage **out, const char *output_profile, const char *input_profile, VipsIntent intent,
int depth, gboolean embedded) {
return vips_icc_transform(
in, out, output_profile,
"input_profile", input_profile ? input_profile : "none",
"intent", intent,
"depth", depth ? depth : 8,
"embedded", embedded,
NULL);
}
// Conversion
int embed_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend) {
return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
}
int embed_image_background(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, double r, double g, double b, double a) {
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
int code = vips_embed(in, out, left, top, width, height,
"extend", VIPS_EXTEND_BACKGROUND, "background", vipsBackground, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int embed_multi_page_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend) {
VipsObject *base = VIPS_OBJECT(vips_image_new());
int page_height = vips_image_get_page_height(in);
int in_width = in->Xsize;
int n_pages = in->Ysize / page_height;
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **embedded_page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_embed(page[i], &embedded_page[i], left, top, width, height, "extend", extend, NULL)
) {
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(embedded_page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
g_object_unref(base);
return 0;
}
int embed_multi_page_image_background(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, double r, double g, double b, double a) {
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
VipsObject *base = VIPS_OBJECT(vips_image_new());
int page_height = vips_image_get_page_height(in);
int in_width = in->Xsize;
int n_pages = in->Ysize / page_height;
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **embedded_page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_embed(page[i], &embedded_page[i], left, top, width, height,
"extend", VIPS_EXTEND_BACKGROUND, "background", vipsBackground, NULL)
) {
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(embedded_page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
vips_area_unref(VIPS_AREA(vipsBackground));
g_object_unref(base);
return 0;
}
int similarity(VipsImage *in, VipsImage **out, double scale, double angle,
double r, double g, double b, double a, double idx, double idy,
double odx, double ody) {
if (is_16bit(in->Type)) {
r = 65535 * r / 255;
g = 65535 * g / 255;
b = 65535 * b / 255;
a = 65535 * a / 255;
}
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
VipsArrayDouble *vipsBackground;
// Ignore the alpha channel if the image doesn't have one
if (in->Bands <= 3) {
vipsBackground = vips_array_double_new(background, 3);
} else {
vipsBackground = vips_array_double_new(backgroundRGBA, 4);
}
int code = vips_similarity(in, out, "scale", scale, "angle", angle,
"background", vipsBackground, "idx", idx, "idy",
idy, "odx", odx, "ody", ody, NULL);
vips_area_unref(VIPS_AREA(vipsBackground));
return code;
}
int crop(VipsImage *in, VipsImage **out, int left, int top,
int width, int height) {
// resolve image pages
int page_height = vips_image_get_page_height(in);
int n_pages = in->Ysize / page_height;
if (n_pages <= 1) {
return vips_crop(in, out, left, top, width, height, NULL);
}
int in_width = in->Xsize;
VipsObject *base = VIPS_OBJECT(vips_image_new());
VipsImage **page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **cropped_page = (VipsImage **) vips_object_local_array(base, n_pages);
VipsImage **copy = (VipsImage **) vips_object_local_array(base, 1);
// split image into cropped frames
for (int i = 0; i < n_pages; i++) {
if (
vips_extract_area(in, &page[i], 0, page_height * i, in_width, page_height, NULL) ||
vips_crop(page[i], &cropped_page[i], left, top, width, height, NULL)
) {
g_object_unref(base);
return -1;
}
}
// reassemble frames and set page height
// copy before modifying metadata
if(
vips_arrayjoin(cropped_page, &copy[0], n_pages, "across", 1, NULL) ||
vips_copy(copy[0], out, NULL)
) {
g_object_unref(base);
return -1;
}
vips_image_set_int(*out, VIPS_META_PAGE_HEIGHT, height);
g_object_unref(base);
return 0;
}
static int is_16bit(VipsInterpretation interpretation) {
return interpretation == VIPS_INTERPRETATION_RGB16 ||
interpretation == VIPS_INTERPRETATION_GREY16;
}
int composite_image(VipsImage **in, VipsImage **out, int n, int *mode, int *x,
int *y) {
VipsArrayInt *xs = vips_array_int_new(x, n - 1);
VipsArrayInt *ys = vips_array_int_new(y, n - 1);
int code = vips_composite(in, out, n, mode, "x", xs, "y", ys, NULL);
vips_area_unref(VIPS_AREA(xs));
vips_area_unref(VIPS_AREA(ys));
return code;
}
int join(VipsImage *in1, VipsImage *in2, VipsImage **out, int direction) {
return vips_join(in1, in2, out, direction, NULL);
}
int add_alpha(VipsImage *in, VipsImage **out) {
return vips_addalpha(in, out, NULL);
}
// Create
// https://libvips.github.io/libvips/API/current/libvips-create.html#vips-text
int text(VipsImage **out, TextOptions *o) {
return vips_text(out, o->Text, "font", o->Font, "width", o->Width, "height", o->Height, "align", o->Align,
"dpi", o->DPI, "rgba", o->RGBA, "justify", o->Justify, "spacing", o->Spacing, "wrap", o->Wrap, NULL);
}
// Draw
int draw_rect(VipsImage *in, double r, double g, double b, double a, int left,
int top, int width, int height, int fill) {
if (is_16bit(in->Type)) {
r = 65535 * r / 255;
g = 65535 * g / 255;
b = 65535 * b / 255;
a = 65535 * a / 255;
}
double background[3] = {r, g, b};
double backgroundRGBA[4] = {r, g, b, a};
if (in->Bands <= 3) {
return vips_draw_rect(in, background, 3, left, top, width, height, "fill",
fill, NULL);
} else {
return vips_draw_rect(in, backgroundRGBA, 4, left, top, width, height,
"fill", fill, NULL);
}
}
// Header
unsigned long has_icc_profile(VipsImage *in) {
return vips_image_get_typeof(in, VIPS_META_ICC_NAME);
}
unsigned long get_icc_profile(VipsImage *in, const void **data,
size_t *dataLength) {
return image_get_blob(in, VIPS_META_ICC_NAME, data, dataLength);
}
gboolean remove_icc_profile(VipsImage *in) {
return vips_image_remove(in, VIPS_META_ICC_NAME);
}
unsigned long has_iptc(VipsImage *in) {
return vips_image_get_typeof(in, VIPS_META_IPTC_NAME);
}
char **image_get_fields(VipsImage *in) { return vips_image_get_fields(in); }
void image_set_string(VipsImage *in, const char *name, const char *str) {
vips_image_set_string(in, name, str);
}
unsigned long image_get_string(VipsImage *in, const char *name,
const char **out) {
return vips_image_get_string(in, name, out);
}
unsigned long image_get_as_string(VipsImage *in, const char *name, char **out) {
return vips_image_get_as_string(in, name, out);
}
void remove_field(VipsImage *in, char *field) { vips_image_remove(in, field); }
int get_meta_orientation(VipsImage *in) {
int orientation = 0;
if (vips_image_get_typeof(in, VIPS_META_ORIENTATION) != 0) {
vips_image_get_int(in, VIPS_META_ORIENTATION, &orientation);
}
return orientation;
}
void remove_meta_orientation(VipsImage *in) {
vips_image_remove(in, VIPS_META_ORIENTATION);
}
void set_meta_orientation(VipsImage *in, int orientation) {
vips_image_set_int(in, VIPS_META_ORIENTATION, orientation);
}
// https://libvips.github.io/libvips/API/current/libvips-header.html#vips-image-get-n-pages
int get_image_n_pages(VipsImage *in) {
int n_pages = 0;
n_pages = vips_image_get_n_pages(in);
return n_pages;
}
void set_image_n_pages(VipsImage *in, int n_pages) {
vips_image_set_int(in, VIPS_META_N_PAGES, n_pages);
}
// https://www.libvips.org/API/current/libvips-header.html#vips-image-get-page-height
int get_page_height(VipsImage *in) {
int page_height = 0;
page_height = vips_image_get_page_height(in);
return page_height;
}
void set_page_height(VipsImage *in, int height) {
vips_image_set_int(in, VIPS_META_PAGE_HEIGHT, height);
}
int get_meta_loader(const VipsImage *in, const char **out) {
return vips_image_get_string(in, VIPS_META_LOADER, out);
}
int get_background(VipsImage *in, double **out, int *n) {
return vips_image_get_array_double(in, "background", out, n);
}
int get_image_delay(VipsImage *in, int **out) {
return vips_image_get_array_int(in, "delay", out, NULL);
}
void set_image_delay(VipsImage *in, const int *array, int n) {
return vips_image_set_array_int(in, "delay", array, n);
}
int get_image_loop(VipsImage *in) {
int loop = 0;
if (vips_image_get_typeof(in, "loop") != 0) {
vips_image_get_int(in, "loop", &loop);
}
return loop;
}
void set_image_loop(VipsImage *in, int loop) {
vips_image_set_int(in, "loop", loop);
}
void image_set_double(VipsImage *in, const char *name, double i) {
vips_image_set_double(in, name, i);
}
unsigned long image_get_double(VipsImage *in, const char *name, double *out) {
return vips_image_get_double(in, name, out);
}
void image_set_int(VipsImage *in, const char *name, int i) {
vips_image_set_int(in, name, i);
}
unsigned long image_get_int(VipsImage *in, const char *name, int *out) {
return vips_image_get_int(in, name, out);
}
void image_set_blob(VipsImage *in, const char *name, const void *data,
size_t dataLength) {
vips_image_set_blob_copy(in, name, data, dataLength);
}
unsigned long image_get_blob(VipsImage *in, const char *name, const void **data,
size_t *dataLength) {
if (vips_image_get_typeof(in, name) == 0) {
return 0;
}
if (vips_image_get_blob(in, name, data, dataLength)) {
return -1;
}
return 0;
}
// Label
int label(VipsImage *in, VipsImage **out, LabelOptions *o) {
double ones[3] = {1, 1, 1};
VipsImage *base = vips_image_new();
VipsImage **t = (VipsImage **)vips_object_local_array(VIPS_OBJECT(base), 9);
if (vips_text(&t[0], o->Text, "font", o->Font, "width", o->Width, "height",
o->Height, "align", o->Align, NULL) ||
vips_linear1(t[0], &t[1], o->Opacity, 0.0, NULL) ||
vips_cast(t[1], &t[2], VIPS_FORMAT_UCHAR, NULL) ||
vips_embed(t[2], &t[3], o->OffsetX, o->OffsetY, t[2]->Xsize + o->OffsetX,
t[2]->Ysize + o->OffsetY, NULL)) {
g_object_unref(base);
return 1;
}
if (vips_black(&t[4], 1, 1, NULL) ||
vips_linear(t[4], &t[5], ones, o->Color, 3, NULL) ||
vips_cast(t[5], &t[6], VIPS_FORMAT_UCHAR, NULL) ||
vips_copy(t[6], &t[7], "interpretation", in->Type, NULL) ||
vips_embed(t[7], &t[8], 0, 0, in->Xsize, in->Ysize, "extend",
VIPS_EXTEND_COPY, NULL)) {
g_object_unref(base);
return 1;
}
if (vips_ifthenelse(t[3], t[8], in, out, "blend", TRUE, NULL)) {
g_object_unref(base);
return 1;
}
g_object_unref(base);
return 0;
}
// Resample
int resize_image(VipsImage *in, VipsImage **out, double scale, gdouble vscale,
int kernel) {
if (vscale > 0) {
return vips_resize(in, out, scale, "vscale", vscale, "kernel", kernel,
NULL);
}
return vips_resize(in, out, scale, "kernel", kernel, NULL);
}
int thumbnail(const char *filename, VipsImage **out,
int width, int height, int crop, int size) {
return vips_thumbnail(filename, out, width, "height", height,
"crop", crop, "size", size, NULL);
}
int thumbnail_image(VipsImage *in, VipsImage **out, int width, int height,
int crop, int size) {
return vips_thumbnail_image(in, out, width, "height", height, "crop", crop,
"size", size, NULL);
}
int thumbnail_buffer_with_option(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size,
const char *option_string) {
return vips_thumbnail_buffer(buf, len, out, width, "height", height,
"crop", crop, "size", size,
"option_string", option_string, NULL);
}
int thumbnail_buffer(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size) {
return vips_thumbnail_buffer(buf, len, out, width, "height", height,
"crop", crop, "size", size, NULL);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
// operations.h - Hand-written C bridge functions for libvips operations
#ifndef OPERATIONS_H
#define OPERATIONS_H
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/foreign.h>
// Arithmetic
// https://libvips.github.io/libvips/API/current/libvips-arithmetic.html
int find_trim(VipsImage *in, int *left, int *top, int *width, int *height,
double threshold, double r, double g, double b);
int getpoint(VipsImage *in, double **vector, int n, int x, int y);
int minOp(VipsImage *in, double *out, int *x, int *y, int size);
// Color
// https://libvips.github.io/libvips/API/current/libvips-colour.html
int is_colorspace_supported(VipsImage *in);
int to_colorspace(VipsImage *in, VipsImage **out, VipsInterpretation space);
int icc_transform(VipsImage *in, VipsImage **out, const char *output_profile,
const char *input_profile, VipsIntent intent, int depth,
gboolean embedded);
// Conversion
// https://libvips.github.io/libvips/API/current/libvips-conversion.html
int embed_image(VipsImage *in, VipsImage **out, int left, int top, int width,
int height, int extend);
int embed_image_background(VipsImage *in, VipsImage **out, int left, int top,
int width, int height, double r, double g, double b, double a);
int embed_multi_page_image(VipsImage *in, VipsImage **out, int left, int top,
int width, int height, int extend);
int embed_multi_page_image_background(VipsImage *in, VipsImage **out, int left,
int top, int width, int height, double r, double g, double b,
double a);
int crop(VipsImage *in, VipsImage **out, int left, int top, int width,
int height);
int similarity(VipsImage *in, VipsImage **out, double scale, double angle,
double r, double g, double b, double a, double idx, double idy,
double odx, double ody);
int composite_image(VipsImage **in, VipsImage **out, int n, int *mode, int *x,
int *y);
int join(VipsImage *in1, VipsImage *in2, VipsImage **out, int direction);
int add_alpha(VipsImage *in, VipsImage **out);
// Create
// https://libvips.github.io/libvips/API/current/libvips-create.html
typedef struct {
const char *Text;
const char *Font;
int Width;
int Height;
int DPI;
gboolean RGBA;
gboolean Justify;
int Spacing;
VipsAlign Align;
VipsTextWrap Wrap;
} TextOptions;
int text(VipsImage **out, TextOptions *o);
// Draw
// https://libvips.github.io/libvips/API/current/libvips-draw.html
int draw_rect(VipsImage *in, double r, double g, double b, double a, int left,
int top, int width, int height, int fill);
// Header
// https://libvips.github.io/libvips/API/current/libvips-header.html
unsigned long has_icc_profile(VipsImage *in);
unsigned long get_icc_profile(VipsImage *in, const void **data,
size_t *dataLength);
int remove_icc_profile(VipsImage *in);
unsigned long has_iptc(VipsImage *in);
char **image_get_fields(VipsImage *in);
void image_set_string(VipsImage *in, const char *name, const char *str);
unsigned long image_get_string(VipsImage *in, const char *name,
const char **out);
unsigned long image_get_as_string(VipsImage *in, const char *name, char **out);
void remove_field(VipsImage *in, char *field);
int get_meta_orientation(VipsImage *in);
void remove_meta_orientation(VipsImage *in);
void set_meta_orientation(VipsImage *in, int orientation);
int get_image_n_pages(VipsImage *in);
void set_image_n_pages(VipsImage *in, int n_pages);
int get_page_height(VipsImage *in);
void set_page_height(VipsImage *in, int height);
int get_meta_loader(const VipsImage *in, const char **out);
int get_image_delay(VipsImage *in, int **out);
void set_image_delay(VipsImage *in, const int *array, int n);
int get_image_loop(VipsImage *in);
void set_image_loop(VipsImage *in, int loop);
int get_background(VipsImage *in, double **out, int *n);
void image_set_blob(VipsImage *in, const char *name, const void *data,
size_t dataLength);
unsigned long image_get_blob(VipsImage *in, const char *name, const void **data,
size_t *dataLength);
void image_set_double(VipsImage *in, const char *name, double i);
unsigned long image_get_double(VipsImage *in, const char *name, double *out);
void image_set_int(VipsImage *in, const char *name, int i);
unsigned long image_get_int(VipsImage *in, const char *name, int *out);
// Label
typedef struct {
const char *Text;
const char *Font;
int Width;
int Height;
int OffsetX;
int OffsetY;
VipsAlign Align;
int DPI;
int Margin;
float Opacity;
double Color[3];
} LabelOptions;
int label(VipsImage *in, VipsImage **out, LabelOptions *o);
// Resample
// https://libvips.github.io/libvips/API/current/libvips-resample.html
int resize_image(VipsImage *in, VipsImage **out, double scale, gdouble vscale,
int kernel);
int thumbnail(const char *filename, VipsImage **out, int width, int height,
int crop, int size);
int thumbnail_image(VipsImage *in, VipsImage **out, int width, int height,
int crop, int size);
int thumbnail_buffer(void *buf, size_t len, VipsImage **out, int width,
int height, int crop, int size);
int thumbnail_buffer_with_option(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size,
const char *option_string);
#endif // OPERATIONS_H

View File

@@ -1,61 +0,0 @@
#include "resample.h"
int shrink_image(VipsImage *in, VipsImage **out, double xshrink,
double yshrink) {
return vips_shrink(in, out, xshrink, yshrink, NULL);
}
int reduce_image(VipsImage *in, VipsImage **out, double xshrink,
double yshrink) {
return vips_reduce(in, out, xshrink, yshrink, NULL);
}
int affine_image(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 resize_image(VipsImage *in, VipsImage **out, double scale, gdouble vscale,
int kernel) {
if (vscale > 0) {
return vips_resize(in, out, scale, "vscale", vscale, "kernel", kernel,
NULL);
}
return vips_resize(in, out, scale, "kernel", kernel, NULL);
}
int thumbnail(const char *filename, VipsImage **out,
int width, int height, int crop, int size) {
return vips_thumbnail(filename, out, width, "height", height,
"crop", crop, "size", size, NULL);
}
int thumbnail_image(VipsImage *in, VipsImage **out, int width, int height,
int crop, int size) {
return vips_thumbnail_image(in, out, width, "height", height, "crop", crop,
"size", size, NULL);
}
int thumbnail_buffer_with_option(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size,
const char *option_string) {
return vips_thumbnail_buffer(buf, len, out, width, "height", height,
"crop", crop, "size", size,
"option_string", option_string, NULL);
}
int thumbnail_buffer(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size) {
return vips_thumbnail_buffer(buf, len, out, width, "height", height,
"crop", crop, "size", size, NULL);
}
int mapim(VipsImage *in, VipsImage **out, VipsImage *index) {
return vips_mapim(in, out, index, NULL);
}
int maplut(VipsImage *in, VipsImage **out, VipsImage *lut) {
return vips_maplut(in, out, lut, NULL);
}

View File

@@ -1,146 +0,0 @@
package vips
// #include "resample.h"
import "C"
import (
"os"
"runtime"
"unsafe"
)
// Kernel represents VipsKernel type
type Kernel int
// Kernel enum
const (
KernelAuto Kernel = -1
KernelNearest Kernel = C.VIPS_KERNEL_NEAREST
KernelLinear Kernel = C.VIPS_KERNEL_LINEAR
KernelCubic Kernel = C.VIPS_KERNEL_CUBIC
KernelLanczos2 Kernel = C.VIPS_KERNEL_LANCZOS2
KernelLanczos3 Kernel = C.VIPS_KERNEL_LANCZOS3
KernelMitchell Kernel = C.VIPS_KERNEL_MITCHELL
)
// Size represents VipsSize type
type Size int
const (
SizeBoth Size = C.VIPS_SIZE_BOTH
SizeUp Size = C.VIPS_SIZE_UP
SizeDown Size = C.VIPS_SIZE_DOWN
SizeForce Size = C.VIPS_SIZE_FORCE
SizeLast Size = C.VIPS_SIZE_LAST
)
// https://libvips.github.io/libvips/API/current/libvips-resample.html#vips-resize
func vipsResizeWithVScale(in *C.VipsImage, hscale, vscale float64, kernel Kernel) (*C.VipsImage, error) {
incOpCounter("resize")
var out *C.VipsImage
// libvips recommends Lanczos3 as the default kernel
if kernel == KernelAuto {
kernel = KernelLanczos3
}
if err := C.resize_image(in, &out, C.double(hscale), C.double(vscale), C.int(kernel)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
func vipsThumbnail(in *C.VipsImage, width, height int, crop Interesting, size Size) (*C.VipsImage, error) {
incOpCounter("thumbnail")
var out *C.VipsImage
if err := C.thumbnail_image(in, &out, C.int(width), C.int(height), C.int(crop), C.int(size)); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://www.libvips.org/API/current/libvips-resample.html#vips-thumbnail
func vipsThumbnailFromFile(filename string, width, height int, crop Interesting, size Size, params *ImportParams) (*C.VipsImage, ImageType, error) {
var out *C.VipsImage
filenameOption := filename
if params != nil {
filenameOption += "[" + params.OptionString() + "]"
}
cFileName := C.CString(filenameOption)
defer freeCString(cFileName)
if err := C.thumbnail(cFileName, &out, C.int(width), C.int(height), C.int(crop), C.int(size)); err != 0 {
err := handleImageError(out)
if src, err2 := os.ReadFile(filename); err2 == nil {
if isBMP(src) {
if src2, err3 := bmpToPNG(src); err3 == nil {
return vipsThumbnailFromBuffer(src2, width, height, crop, size, params)
}
}
}
return nil, ImageTypeUnknown, err
}
imageType := vipsDetermineImageTypeFromMetaLoader(out)
return out, imageType, nil
}
// https://www.libvips.org/API/current/libvips-resample.html#vips-thumbnail-buffer
func vipsThumbnailFromBuffer(buf []byte, width, height int, crop Interesting, size Size, params *ImportParams) (*C.VipsImage, ImageType, error) {
src := buf
// Reference src here so it's not garbage collected during image initialization.
defer runtime.KeepAlive(src)
var out *C.VipsImage
var err C.int
if params == nil {
err = C.thumbnail_buffer(unsafe.Pointer(&src[0]), C.size_t(len(src)), &out, C.int(width), C.int(height), C.int(crop), C.int(size))
} else {
cOptionString := C.CString(params.OptionString())
defer freeCString(cOptionString)
err = C.thumbnail_buffer_with_option(unsafe.Pointer(&src[0]), C.size_t(len(src)), &out, C.int(width), C.int(height), C.int(crop), C.int(size), cOptionString)
}
if err != 0 {
err := handleImageError(out)
if isBMP(src) {
if src2, err2 := bmpToPNG(src); err2 == nil {
return vipsThumbnailFromBuffer(src2, width, height, crop, size, params)
}
}
return nil, ImageTypeUnknown, err
}
imageType := vipsDetermineImageTypeFromMetaLoader(out)
return out, imageType, nil
}
// https://libvips.github.io/libvips/API/current/libvips-resample.html#vips-mapim
func vipsMapim(in *C.VipsImage, index *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("mapim")
var out *C.VipsImage
if err := C.mapim(in, &out, index); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}
// https://libvips.github.io/libvips/API/current/libvips-histogram.html#vips-maplut
func vipsMaplut(in *C.VipsImage, lut *C.VipsImage) (*C.VipsImage, error) {
incOpCounter("maplut")
var out *C.VipsImage
if err := C.maplut(in, &out, lut); err != 0 {
return nil, handleImageError(out)
}
return out, nil
}

View File

@@ -1,24 +0,0 @@
// https://libvips.github.io/libvips/API/current/libvips-resample.html
#include <stdlib.h>
#include <vips/vips.h>
int shrink_image(VipsImage *in, VipsImage **out, double xshrink,
double yshrink);
int reduce_image(VipsImage *in, VipsImage **out, double xshrink,
double yshrink);
int affine_image(VipsImage *in, VipsImage **out, double a, double b, double c,
double d, VipsInterpolate *interpolator);
int resize_image(VipsImage *in, VipsImage **out, double scale, gdouble vscale,
int kernel);
int thumbnail(const char *filename, VipsImage **out, int width, int height,
int crop, int size);
int thumbnail_image(VipsImage *in, VipsImage **out, int width, int height,
int crop, int size);
int thumbnail_buffer(void *buf, size_t len, VipsImage **out, int width, int height,
int crop, int size);
int thumbnail_buffer_with_option(void *buf, size_t len, VipsImage **out,
int width, int height, int crop, int size,
const char *option_string);
int mapim(VipsImage *in, VipsImage **out, VipsImage *index);
int maplut(VipsImage *in, VipsImage **out, VipsImage *lut);

4
vendor/modules.txt vendored
View File

@@ -358,8 +358,8 @@ github.com/cyphar/filepath-securejoin/pathrs-lite/procfs
# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
## explicit
github.com/davecgh/go-spew/spew
# github.com/davidbyttow/govips/v2 v2.16.0
## explicit; go 1.15
# github.com/davidbyttow/govips/v2 v2.17.0
## explicit; go 1.23.0
github.com/davidbyttow/govips/v2/vips
# github.com/deckarep/golang-set v1.8.0
## explicit; go 1.17