mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-01 20:53:05 -04:00
build(deps): bump github.com/davidbyttow/govips/v2 from 2.17.0 to 2.18.0
Bumps [github.com/davidbyttow/govips/v2](https://github.com/davidbyttow/govips) from 2.17.0 to 2.18.0. - [Release notes](https://github.com/davidbyttow/govips/releases) - [Commits](https://github.com/davidbyttow/govips/compare/v2.17.0...v2.18.0) --- updated-dependencies: - dependency-name: github.com/davidbyttow/govips/v2 dependency-version: 2.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
e2f322791a
commit
8f26149743
2
vendor/github.com/davidbyttow/govips/v2/vips/foreign.c
generated
vendored
2
vendor/github.com/davidbyttow/govips/v2/vips/foreign.c
generated
vendored
@@ -114,6 +114,7 @@ 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");
|
||||
MAYBE_SET_DOUBLE(operation, params->webpScale, "scale");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -527,6 +528,7 @@ LoadParams create_load_params(ImageType inputFormat) {
|
||||
.n = defaultParam,
|
||||
.dpi = defaultParam,
|
||||
.jpegShrink = defaultParam,
|
||||
.webpScale = defaultParam,
|
||||
.heifThumbnail = defaultParam,
|
||||
.svgUnlimited = defaultParam,
|
||||
.access = defaultParam,
|
||||
|
||||
16
vendor/github.com/davidbyttow/govips/v2/vips/foreign.go
generated
vendored
16
vendor/github.com/davidbyttow/govips/v2/vips/foreign.go
generated
vendored
@@ -146,7 +146,10 @@ func (i ImageType) FileExt() string {
|
||||
|
||||
// IsTypeSupported checks whether given image type is supported by govips
|
||||
func IsTypeSupported(imageType ImageType) bool {
|
||||
startupIfNeeded()
|
||||
if err := startupIfNeeded(); err != nil {
|
||||
govipsLog("govips", LogLevelError, fmt.Sprintf("failed to start vips: %v", err))
|
||||
return false
|
||||
}
|
||||
|
||||
// BMP is supported via the magick loader
|
||||
if imageType == ImageTypeBMP {
|
||||
@@ -233,6 +236,7 @@ var heis = []byte("heis")
|
||||
var mif1 = []byte("mif1")
|
||||
var msf1 = []byte("msf1")
|
||||
var avif = []byte("avif")
|
||||
var avis = []byte("avis")
|
||||
|
||||
func isHEIF(buf []byte) bool {
|
||||
return bytes.Equal(buf[4:8], ftyp) && (bytes.Equal(buf[8:12], heic) ||
|
||||
@@ -245,7 +249,8 @@ func isHEIF(buf []byte) bool {
|
||||
}
|
||||
|
||||
func isAVIF(buf []byte) bool {
|
||||
return bytes.Equal(buf[4:8], ftyp) && bytes.Equal(buf[8:12], avif)
|
||||
return bytes.Equal(buf[4:8], ftyp) &&
|
||||
(bytes.Equal(buf[8:12], avif) || bytes.Equal(buf[8:12], avis))
|
||||
}
|
||||
|
||||
var svg = []byte("<svg")
|
||||
@@ -363,6 +368,12 @@ func maybeSetIntParam(p IntParameter, cp *C.Param) {
|
||||
}
|
||||
}
|
||||
|
||||
func maybeSetDoubleParam(p Float64Parameter, cp *C.Param) {
|
||||
if p.IsSet() {
|
||||
C.set_double_param(cp, C.gdouble(p.Get()))
|
||||
}
|
||||
}
|
||||
|
||||
func createImportParams(format ImageType, params *ImportParams) C.LoadParams {
|
||||
p := C.create_load_params(C.ImageType(format))
|
||||
|
||||
@@ -371,6 +382,7 @@ func createImportParams(format ImageType, params *ImportParams) C.LoadParams {
|
||||
maybeSetIntParam(params.Page, &p.page)
|
||||
maybeSetIntParam(params.NumPages, &p.n)
|
||||
maybeSetIntParam(params.JpegShrinkFactor, &p.jpegShrink)
|
||||
maybeSetDoubleParam(params.WebpScaleFactor, &p.webpScale)
|
||||
maybeSetBoolParam(params.HeifThumbnail, &p.heifThumbnail)
|
||||
maybeSetBoolParam(params.SvgUnlimited, &p.svgUnlimited)
|
||||
maybeSetIntParam(params.Access, &p.access)
|
||||
|
||||
1
vendor/github.com/davidbyttow/govips/v2/vips/foreign.h
generated
vendored
1
vendor/github.com/davidbyttow/govips/v2/vips/foreign.h
generated
vendored
@@ -65,6 +65,7 @@ typedef struct LoadParams {
|
||||
Param n;
|
||||
Param dpi;
|
||||
Param jpegShrink;
|
||||
Param webpScale;
|
||||
Param heifThumbnail;
|
||||
Param svgUnlimited;
|
||||
Param access;
|
||||
|
||||
29
vendor/github.com/davidbyttow/govips/v2/vips/govips.go
generated
vendored
29
vendor/github.com/davidbyttow/govips/v2/vips/govips.go
generated
vendored
@@ -12,6 +12,8 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -130,14 +132,13 @@ func Startup(config *Config) error {
|
||||
C.vips_cache_set_max(defaultMaxCacheSize)
|
||||
}
|
||||
|
||||
if config.CacheTrace {
|
||||
C.vips_cache_set_trace(toGboolean(true))
|
||||
}
|
||||
C.vips_cache_set_trace(toGboolean(config.CacheTrace))
|
||||
} else {
|
||||
C.vips_concurrency_set(defaultConcurrencyLevel)
|
||||
C.vips_cache_set_max(defaultMaxCacheSize)
|
||||
C.vips_cache_set_max_mem(defaultMaxCacheMem)
|
||||
C.vips_cache_set_max_files(defaultMaxCacheFiles)
|
||||
C.vips_cache_set_trace(toGboolean(false))
|
||||
}
|
||||
|
||||
govipsLog("govips", LogLevelInfo, fmt.Sprintf("vips %s started with concurrency=%d cache_max_files=%d cache_max_mem=%d cache_max=%d",
|
||||
@@ -225,6 +226,23 @@ type MemoryStats struct {
|
||||
Allocs int64
|
||||
}
|
||||
|
||||
var openImageRefs atomic.Int64
|
||||
|
||||
// OpenImageRefs returns the number of ImageRef instances that haven't been closed.
|
||||
func OpenImageRefs() int64 {
|
||||
return openImageRefs.Load()
|
||||
}
|
||||
|
||||
// AssertNoLeaks fails the test if any ImageRef instances remain open.
|
||||
// Call this at the end of tests to catch leaked images.
|
||||
func AssertNoLeaks(t testing.TB) {
|
||||
t.Helper()
|
||||
n := openImageRefs.Load()
|
||||
if n != 0 {
|
||||
t.Errorf("govips: %d ImageRef(s) not closed (leaked)", n)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadVipsMemStats returns various memory statistics such as allocated memory and open files.
|
||||
func ReadVipsMemStats(stats *MemoryStats) {
|
||||
stats.Mem = int64(C.vips_tracked_get_mem())
|
||||
@@ -233,13 +251,14 @@ func ReadVipsMemStats(stats *MemoryStats) {
|
||||
stats.Files = int64(C.vips_tracked_get_files())
|
||||
}
|
||||
|
||||
func startupIfNeeded() {
|
||||
func startupIfNeeded() error {
|
||||
if !running {
|
||||
govipsLog("govips", LogLevelInfo, "libvips was forcibly started automatically, consider calling Startup/Shutdown yourself")
|
||||
if err := Startup(nil); err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitTypes initializes caches and figures out which image types are supported
|
||||
|
||||
1839
vendor/github.com/davidbyttow/govips/v2/vips/image.go
generated
vendored
1839
vendor/github.com/davidbyttow/govips/v2/vips/image.go
generated
vendored
File diff suppressed because it is too large
Load Diff
173
vendor/github.com/davidbyttow/govips/v2/vips/image_color.go
generated
vendored
Normal file
173
vendor/github.com/davidbyttow/govips/v2/vips/image_color.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// ToColorSpace changes the color space of the image to the interpretation supplied as the parameter.
|
||||
func (r *ImageRef) ToColorSpace(interpretation Interpretation) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsToColorSpace(r.image, interpretation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flatten removes the alpha channel from the image and replaces it with the background color
|
||||
func (r *ImageRef) Flatten(backgroundColor *Color) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
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
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Modulate the colors
|
||||
func (r *ImageRef) Modulate(brightness, saturation, hue float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
var err error
|
||||
var multiplications []float64
|
||||
var additions []float64
|
||||
|
||||
colorspace := r.ColorSpace()
|
||||
if colorspace == InterpretationRGB {
|
||||
colorspace = InterpretationSRGB
|
||||
}
|
||||
|
||||
multiplications = []float64{brightness, saturation, 1}
|
||||
additions = []float64{0, 0, hue}
|
||||
|
||||
if r.HasAlpha() {
|
||||
multiplications = append(multiplications, 1)
|
||||
additions = append(additions, 0)
|
||||
}
|
||||
|
||||
err = r.ToColorSpace(InterpretationLCH)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Linear(multiplications, additions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.ToColorSpace(colorspace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ModulateHSV modulates the image HSV values based on the supplier parameters.
|
||||
func (r *ImageRef) ModulateHSV(brightness, saturation float64, hue int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
var err error
|
||||
var multiplications []float64
|
||||
var additions []float64
|
||||
|
||||
colorspace := r.ColorSpace()
|
||||
if colorspace == InterpretationRGB {
|
||||
colorspace = InterpretationSRGB
|
||||
}
|
||||
|
||||
if r.HasAlpha() {
|
||||
multiplications = []float64{1, saturation, brightness, 1}
|
||||
additions = []float64{float64(hue), 0, 0, 0}
|
||||
} else {
|
||||
multiplications = []float64{1, saturation, brightness}
|
||||
additions = []float64{float64(hue), 0, 0}
|
||||
}
|
||||
|
||||
err = r.ToColorSpace(InterpretationHSV)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Linear(multiplications, additions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.ToColorSpace(colorspace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Invert inverts the image
|
||||
func (r *ImageRef) Invert() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenInvert(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenGamma(r.image, &GammaOptions{Exponent: &gamma})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Linear passes an image through a linear transformation (i.e. output = input * a + b).
|
||||
// See https://libvips.github.io/libvips/API/current/libvips-arithmetic.html#vips-linear
|
||||
func (r *ImageRef) Linear(a, b []float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if len(a) != len(b) {
|
||||
return errors.New("a and b must be of same length")
|
||||
}
|
||||
|
||||
out, err := vipsGenLinear(r.image, a, b, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenLinear(r.image, []float64{a}, []float64{b}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cast converts the image to a target band format
|
||||
func (r *ImageRef) Cast(format BandFormat) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCast(r.image, format, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
70
vendor/github.com/davidbyttow/govips/v2/vips/image_composite.go
generated
vendored
Normal file
70
vendor/github.com/davidbyttow/govips/v2/vips/image_composite.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import "runtime"
|
||||
|
||||
// CompositeMulti composites the given overlay image on top of the associated image with provided blending mode.
|
||||
func (r *ImageRef) CompositeMulti(ins []*ImageComposite) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsComposite(toVipsCompositeStructs(r, ins))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenComposite2(r.image, overlay.image, mode, &Composite2Options{X: &x, Y: &y})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
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
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Join joins this image with another in the direction specified
|
||||
func (r *ImageRef) Join(in *ImageRef, dir Direction) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsJoin(r.image, in.image, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ArrayJoin joins an array of images together wrapping at each n images
|
||||
func (r *ImageRef) ArrayJoin(images []*ImageRef, across int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
allImages := append([]*ImageRef{r}, images...)
|
||||
inputs := make([]*C.VipsImage, len(allImages))
|
||||
for i := range inputs {
|
||||
inputs[i] = allImages[i].image
|
||||
}
|
||||
out, err := vipsGenArrayjoin(inputs, &ArrayjoinOptions{Across: &across})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
392
vendor/github.com/davidbyttow/govips/v2/vips/image_export.go
generated
vendored
Normal file
392
vendor/github.com/davidbyttow/govips/v2/vips/image_export.go
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// The function also returns a copy of the image metadata as well as an error.
|
||||
// Deprecated: Use ExportNative or format-specific Export methods
|
||||
func (r *ImageRef) Export(params *ExportParams) ([]byte, *ImageMetadata, error) {
|
||||
if params == nil || params.Format == ImageTypeUnknown {
|
||||
return r.ExportNative()
|
||||
}
|
||||
|
||||
format := params.Format
|
||||
|
||||
if !IsTypeSupported(format) {
|
||||
return nil, r.newMetadata(ImageTypeUnknown), fmt.Errorf("cannot save to %#v", ImageTypes[format])
|
||||
}
|
||||
|
||||
switch format {
|
||||
case ImageTypeGIF:
|
||||
return r.ExportGIF(&GifExportParams{
|
||||
Quality: params.Quality,
|
||||
})
|
||||
case ImageTypeWEBP:
|
||||
return r.ExportWebp(&WebpExportParams{
|
||||
StripMetadata: params.StripMetadata,
|
||||
Quality: params.Quality,
|
||||
Lossless: params.Lossless,
|
||||
ReductionEffort: params.Effort,
|
||||
})
|
||||
case ImageTypePNG:
|
||||
return r.ExportPng(&PngExportParams{
|
||||
StripMetadata: params.StripMetadata,
|
||||
Compression: params.Compression,
|
||||
Interlace: params.Interlaced,
|
||||
})
|
||||
case ImageTypeTIFF:
|
||||
compression := TiffCompressionLzw
|
||||
if params.Lossless {
|
||||
compression = TiffCompressionNone
|
||||
}
|
||||
return r.ExportTiff(&TiffExportParams{
|
||||
StripMetadata: params.StripMetadata,
|
||||
Quality: params.Quality,
|
||||
Compression: compression,
|
||||
})
|
||||
case ImageTypeHEIF:
|
||||
return r.ExportHeif(&HeifExportParams{
|
||||
Quality: params.Quality,
|
||||
Lossless: params.Lossless,
|
||||
})
|
||||
case ImageTypeAVIF:
|
||||
return r.ExportAvif(&AvifExportParams{
|
||||
StripMetadata: params.StripMetadata,
|
||||
Quality: params.Quality,
|
||||
Lossless: params.Lossless,
|
||||
Speed: params.Speed,
|
||||
})
|
||||
case ImageTypeJXL:
|
||||
return r.ExportJxl(&JxlExportParams{
|
||||
Quality: params.Quality,
|
||||
Lossless: params.Lossless,
|
||||
Effort: params.Effort,
|
||||
})
|
||||
default:
|
||||
format = ImageTypeJPEG
|
||||
return r.ExportJpeg(&JpegExportParams{
|
||||
Quality: params.Quality,
|
||||
StripMetadata: params.StripMetadata,
|
||||
Interlace: params.Interlaced,
|
||||
OptimizeCoding: params.OptimizeCoding,
|
||||
SubsampleMode: params.SubsampleMode,
|
||||
TrellisQuant: params.TrellisQuant,
|
||||
OvershootDeringing: params.OvershootDeringing,
|
||||
OptimizeScans: params.OptimizeScans,
|
||||
QuantTable: params.QuantTable,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ExportNative exports the image to a buffer based on its native format with default parameters.
|
||||
func (r *ImageRef) ExportNative() ([]byte, *ImageMetadata, error) {
|
||||
switch r.format {
|
||||
case ImageTypeJPEG:
|
||||
return r.ExportJpeg(NewJpegExportParams())
|
||||
case ImageTypePNG:
|
||||
return r.ExportPng(NewPngExportParams())
|
||||
case ImageTypeWEBP:
|
||||
return r.ExportWebp(NewWebpExportParams())
|
||||
case ImageTypeHEIF:
|
||||
return r.ExportHeif(NewHeifExportParams())
|
||||
case ImageTypeTIFF:
|
||||
return r.ExportTiff(NewTiffExportParams())
|
||||
case ImageTypeAVIF:
|
||||
return r.ExportAvif(NewAvifExportParams())
|
||||
case ImageTypeJP2K:
|
||||
return r.ExportJp2k(NewJp2kExportParams())
|
||||
case ImageTypeGIF:
|
||||
return r.ExportGIF(NewGifExportParams())
|
||||
case ImageTypeJXL:
|
||||
return r.ExportJxl(NewJxlExportParams())
|
||||
default:
|
||||
return r.ExportJpeg(NewJpegExportParams())
|
||||
}
|
||||
}
|
||||
|
||||
// ExportJpeg exports the image as JPEG to a buffer.
|
||||
func (r *ImageRef) ExportJpeg(params *JpegExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewJpegExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveJPEGToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeJPEG), nil
|
||||
}
|
||||
|
||||
// ExportPng exports the image as PNG to a buffer.
|
||||
func (r *ImageRef) ExportPng(params *PngExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewPngExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSavePNGToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypePNG), nil
|
||||
}
|
||||
|
||||
// ExportWebp exports the image as WEBP to a buffer.
|
||||
func (r *ImageRef) ExportWebp(params *WebpExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewWebpExportParams()
|
||||
}
|
||||
|
||||
paramsWithIccProfile := *params
|
||||
paramsWithIccProfile.IccProfile = r.optimizedIccProfile
|
||||
|
||||
buf, err := vipsSaveWebPToBuffer(r.image, paramsWithIccProfile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeWEBP), nil
|
||||
}
|
||||
|
||||
// ExportHeif exports the image as HEIF to a buffer.
|
||||
func (r *ImageRef) ExportHeif(params *HeifExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewHeifExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveHEIFToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeHEIF), nil
|
||||
}
|
||||
|
||||
// ExportTiff exports the image as TIFF to a buffer.
|
||||
func (r *ImageRef) ExportTiff(params *TiffExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewTiffExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveTIFFToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeTIFF), nil
|
||||
}
|
||||
|
||||
// ExportGIF exports the image as GIF to a buffer.
|
||||
func (r *ImageRef) ExportGIF(params *GifExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewGifExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveGIFToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeGIF), nil
|
||||
}
|
||||
|
||||
// ExportAvif exports the image as AVIF to a buffer.
|
||||
func (r *ImageRef) ExportAvif(params *AvifExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewAvifExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveAVIFToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeAVIF), nil
|
||||
}
|
||||
|
||||
// ExportJp2k exports the image as JPEG2000 to a buffer.
|
||||
func (r *ImageRef) ExportJp2k(params *Jp2kExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewJp2kExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveJP2KToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buf, r.newMetadata(ImageTypeJP2K), nil
|
||||
}
|
||||
|
||||
// ExportJxl exports the image as JPEG XL to a buffer.
|
||||
func (r *ImageRef) ExportJxl(params *JxlExportParams) ([]byte, *ImageMetadata, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
if params == nil {
|
||||
params = NewJxlExportParams()
|
||||
}
|
||||
|
||||
buf, err := vipsSaveJxlToBuffer(r.image, *params)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
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) {
|
||||
defer runtime.KeepAlive(r)
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, errors.New("failed to write image to memory")
|
||||
}
|
||||
defer C.free(cData)
|
||||
|
||||
data := C.GoBytes(unsafe.Pointer(cData), C.int(cSize))
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ToImage converts a VIPs image to a golang image.Image object, useful for interoperability with other golang libraries.
|
||||
// Deprecated: Use ToGoImage for a faster, direct conversion without encoding round-trip.
|
||||
func (r *ImageRef) ToImage(params *ExportParams) (image.Image, error) {
|
||||
imageBytes, _, err := r.ExportNative()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(imageBytes)
|
||||
img, _, err := image.Decode(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
108
vendor/github.com/davidbyttow/govips/v2/vips/image_icc.go
generated
vendored
Normal file
108
vendor/github.com/davidbyttow/govips/v2/vips/image_icc.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsRemoveICCProfile(out)
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransformICCProfileWithFallback transforms from the embedded ICC profile of the image to the ICC profile at the given path.
|
||||
// The fallback ICC profile is used if the image does not have an embedded ICC profile.
|
||||
func (r *ImageRef) TransformICCProfileWithFallback(targetProfilePath, fallbackProfilePath string) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if err := ensureLoadICCPath(&targetProfilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureLoadICCPath(&fallbackProfilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
depth := 16
|
||||
if r.BandFormat() == BandFormatUchar || r.BandFormat() == BandFormatChar || r.BandFormat() == BandFormatNotSet {
|
||||
depth = 8
|
||||
}
|
||||
|
||||
out, err := vipsICCTransform(r.image, targetProfilePath, fallbackProfilePath, IntentPerceptual, depth, true)
|
||||
if err != nil {
|
||||
govipsLog("govips", LogLevelError, fmt.Sprintf("failed to do icc transform: %v", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransformICCProfile transforms from the embedded ICC profile of the image to the icc profile at the given path.
|
||||
func (r *ImageRef) TransformICCProfile(outputProfilePath string) error {
|
||||
return r.TransformICCProfileWithFallback(outputProfilePath, SRGBIEC6196621ICCProfilePath)
|
||||
}
|
||||
|
||||
// OptimizeICCProfile optimizes the ICC color profile of the image.
|
||||
// For two color channel images, it sets a grayscale profile.
|
||||
// For color images, it sets a CMYK or non-CMYK profile based on the image metadata.
|
||||
func (r *ImageRef) OptimizeICCProfile() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
inputProfile := r.determineInputICCProfile()
|
||||
if !r.HasICCProfile() && (inputProfile == "") {
|
||||
// No embedded ICC profile in the input image and no input profile determined, nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
r.optimizedIccProfile = SRGBV2MicroICCProfilePath
|
||||
if r.Bands() <= 2 {
|
||||
r.optimizedIccProfile = SGrayV2MicroICCProfilePath
|
||||
}
|
||||
|
||||
if err := ensureLoadICCPath(&r.optimizedIccProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
embedded := r.HasICCProfile() && (inputProfile == "")
|
||||
|
||||
depth := 16
|
||||
if r.BandFormat() == BandFormatUchar || r.BandFormat() == BandFormatChar || r.BandFormat() == BandFormatNotSet {
|
||||
depth = 8
|
||||
}
|
||||
|
||||
out, err := vipsICCTransform(r.image, r.optimizedIccProfile, inputProfile, IntentPerceptual, depth, embedded)
|
||||
if err != nil {
|
||||
govipsLog("govips", LogLevelError, fmt.Sprintf("failed to do icc transform: %v", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ImageRef) determineInputICCProfile() (inputProfile string) {
|
||||
if r.Interpretation() == InterpretationCMYK {
|
||||
if !r.HasICCProfile() {
|
||||
inputProfile = "cmyk"
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
338
vendor/github.com/davidbyttow/govips/v2/vips/image_metadata.go
generated
vendored
Normal file
338
vendor/github.com/davidbyttow/govips/v2/vips/image_metadata.go
generated
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Format returns the current format of the vips image.
|
||||
func (r *ImageRef) Format() ImageType {
|
||||
return r.format
|
||||
}
|
||||
|
||||
// OriginalFormat returns the original format of the image when loaded.
|
||||
// In some cases the loaded image is converted on load, for example, a BMP is automatically converted to PNG
|
||||
// This method returns the format of the original buffer, as opposed to Format() with will return the format of the
|
||||
// currently held buffer content.
|
||||
func (r *ImageRef) OriginalFormat() ImageType {
|
||||
return r.originalFormat
|
||||
}
|
||||
|
||||
// Width returns the width of this image.
|
||||
func (r *ImageRef) Width() int {
|
||||
return int(r.image.Xsize)
|
||||
}
|
||||
|
||||
// Height returns the height of this image.
|
||||
func (r *ImageRef) Height() int {
|
||||
return int(r.image.Ysize)
|
||||
}
|
||||
|
||||
// Bands returns the number of bands for this image.
|
||||
func (r *ImageRef) Bands() int {
|
||||
return int(r.image.Bands)
|
||||
}
|
||||
|
||||
// HasProfile returns if the image has an ICC profile embedded.
|
||||
func (r *ImageRef) HasProfile() bool {
|
||||
defer runtime.KeepAlive(r)
|
||||
return vipsHasICCProfile(r.image)
|
||||
}
|
||||
|
||||
// HasICCProfile checks whether the image has an ICC profile embedded. Alias to HasProfile
|
||||
func (r *ImageRef) HasICCProfile() bool {
|
||||
return r.HasProfile()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Deprecated: use Orientation() instead
|
||||
func (r *ImageRef) GetOrientation() int {
|
||||
return r.Orientation()
|
||||
}
|
||||
|
||||
// SetOrientation sets the orientation in the EXIF header of the associated image.
|
||||
func (r *ImageRef) SetOrientation(orientation int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsSetMetaOrientation(out, orientation)
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveOrientation removes the EXIF orientation information of the image.
|
||||
func (r *ImageRef) RemoveOrientation() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsRemoveMetaOrientation(out)
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResX returns the X resolution
|
||||
func (r *ImageRef) ResX() float64 {
|
||||
return float64(r.image.Xres)
|
||||
}
|
||||
|
||||
// ResY returns the Y resolution
|
||||
func (r *ImageRef) ResY() float64 {
|
||||
return float64(r.image.Yres)
|
||||
}
|
||||
|
||||
// OffsetX returns the X offset
|
||||
func (r *ImageRef) OffsetX() int {
|
||||
return int(r.image.Xoffset)
|
||||
}
|
||||
|
||||
// OffsetY returns the Y offset
|
||||
func (r *ImageRef) OffsetY() int {
|
||||
return int(r.image.Yoffset)
|
||||
}
|
||||
|
||||
// BandFormat returns the current band format
|
||||
func (r *ImageRef) BandFormat() BandFormat {
|
||||
return BandFormat(int(r.image.BandFmt))
|
||||
}
|
||||
|
||||
// Coding returns the image coding
|
||||
func (r *ImageRef) Coding() Coding {
|
||||
return Coding(int(r.image.Coding))
|
||||
}
|
||||
|
||||
// Interpretation returns the current interpretation of the color space of the image.
|
||||
func (r *ImageRef) Interpretation() Interpretation {
|
||||
return Interpretation(int(r.image.Type))
|
||||
}
|
||||
|
||||
// ColorSpace returns the interpretation of the current color space. Alias to Interpretation().
|
||||
func (r *ImageRef) ColorSpace() Interpretation {
|
||||
return r.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)
|
||||
}
|
||||
|
||||
// Pages returns the number of pages in the Image
|
||||
// For animated images this corresponds to the number of frames
|
||||
func (r *ImageRef) Pages() int {
|
||||
// libvips uses the same attribute (n_pages) to represent the number of pyramid layers in JP2K
|
||||
// as we interpret the attribute as frames and JP2K does not support animation we override this with 1
|
||||
if r.format == ImageTypeJP2K {
|
||||
return 1
|
||||
}
|
||||
|
||||
defer runtime.KeepAlive(r)
|
||||
return vipsGetImageNPages(r.image)
|
||||
}
|
||||
|
||||
// Deprecated: use Pages() instead
|
||||
func (r *ImageRef) GetPages() int {
|
||||
return r.Pages()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsSetImageNPages(out, pages)
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsSetPageHeight(out, height)
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
return nil, nil
|
||||
}
|
||||
return vipsImageGetDelay(r.image, n)
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (r *ImageRef) ImageFields() []string {
|
||||
return r.GetFields()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (r *ImageRef) HasExif() bool {
|
||||
for _, field := range r.ImageFields() {
|
||||
if strings.HasPrefix(field, "exif-") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *ImageRef) GetExif() map[string]string {
|
||||
defer runtime.KeepAlive(r)
|
||||
return vipsImageGetExifData(r.image)
|
||||
}
|
||||
|
||||
// RemoveMetadata removes the EXIF metadata from the image.
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenCopy(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vipsRemoveMetadata(out, keep...)
|
||||
|
||||
r.setImage(out)
|
||||
|
||||
return nil
|
||||
}
|
||||
390
vendor/github.com/davidbyttow/govips/v2/vips/image_pixel.go
generated
vendored
Normal file
390
vendor/github.com/davidbyttow/govips/v2/vips/image_pixel.go
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// GaussianBlur blurs the image
|
||||
// add support minAmpl
|
||||
func (r *ImageRef) GaussianBlur(sigmas ...float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
var (
|
||||
sigma = sigmas[0]
|
||||
minAmpl = GaussBlurDefaultMinAMpl
|
||||
)
|
||||
if len(sigmas) >= 2 {
|
||||
minAmpl = sigmas[1]
|
||||
}
|
||||
out, err := vipsGenGaussblur(r.image, sigma, &GaussblurOptions{MinAmpl: &minAmpl})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sharpen sharpens the image
|
||||
// sigma: sigma of the gaussian
|
||||
// x1: flat/jaggy threshold
|
||||
// m2: slope for jaggy areas
|
||||
func (r *ImageRef) Sharpen(sigma float64, x1 float64, m2 float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenSharpen(r.image, &SharpenOptions{Sigma: &sigma, X1: &x1, M2: &m2})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply Sobel edge detector to the image.
|
||||
func (r *ImageRef) Sobel() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenSobel(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenRank(r.image, width, height, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mapim resamples an image using index to look up pixels
|
||||
func (r *ImageRef) Mapim(index *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenMapim(r.image, index.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Maplut maps an image through another image acting as a LUT (Look Up Table)
|
||||
func (r *ImageRef) Maplut(lut *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenMaplut(r.image, lut.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractBand extracts one or more bands out of the image (replacing the associated ImageRef)
|
||||
func (r *ImageRef) ExtractBand(band int, num int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenExtractBand(r.image, band, &ExtractBandOptions{N: &num})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractBandToImage extracts one or more bands out of the image to a new image
|
||||
func (r *ImageRef) ExtractBandToImage(band int, num int) (*ImageRef, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenExtractBand(r.image, band, &ExtractBandOptions{N: &num})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newImageRef(out, ImageTypeUnknown, ImageTypeUnknown, nil), nil
|
||||
}
|
||||
|
||||
// BandJoin joins a set of images together, bandwise.
|
||||
func (r *ImageRef) BandJoin(images ...*ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
vipsImages := []*C.VipsImage{r.image}
|
||||
for _, vipsImage := range images {
|
||||
vipsImages = append(vipsImages, vipsImage.image)
|
||||
}
|
||||
|
||||
out, err := vipsGenBandjoin(vipsImages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 := vipsGenExtractBand(r.image, i, &ExtractBandOptions{N: &n})
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out = append(out, &ImageRef{image: img})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BandJoinConst appends a set of constant bands to an image.
|
||||
func (r *ImageRef) BandJoinConst(constants []float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if len(constants) == 0 {
|
||||
return errors.New("BandJoinConst: empty constants slice")
|
||||
}
|
||||
out, err := vipsGenBandjoinConst(r.image, constants)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddAlpha adds an alpha channel to the associated image.
|
||||
func (r *ImageRef) AddAlpha() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if vipsHasAlpha(r.image) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out, err := vipsAddAlpha(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PremultiplyAlpha premultiplies the alpha channel.
|
||||
// See https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-premultiply
|
||||
func (r *ImageRef) PremultiplyAlpha() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if r.preMultiplication != nil || !vipsHasAlpha(r.image) {
|
||||
return nil
|
||||
}
|
||||
|
||||
band := r.BandFormat()
|
||||
|
||||
out, err := vipsGenPremultiply(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.preMultiplication = &PreMultiplicationState{
|
||||
bandFormat: band,
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnpremultiplyAlpha unpremultiplies any alpha channel.
|
||||
// See https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-unpremultiply
|
||||
func (r *ImageRef) UnpremultiplyAlpha() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if r.preMultiplication == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
unpremultiplied, err := vipsGenUnpremultiply(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clearImage(unpremultiplied)
|
||||
|
||||
out, err := vipsGenCast(unpremultiplied, r.preMultiplication.bandFormat, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.preMultiplication = nil
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add calculates a sum of the image + addend and stores it back in the image
|
||||
func (r *ImageRef) Add(addend *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenAdd(r.image, addend.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Multiply calculates the product of the image * multiplier and stores it back in the image
|
||||
func (r *ImageRef) Multiply(multiplier *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenMultiply(r.image, multiplier.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Divide calculates the product of the image / denominator and stores it back in the image
|
||||
func (r *ImageRef) Divide(denominator *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenDivide(r.image, denominator.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Average finds the average value in an image
|
||||
func (r *ImageRef) Average() (float64, error) {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenAvg(r.image)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
return vipsGetPoint(r.image, n, x, y)
|
||||
}
|
||||
|
||||
// Stats find many image statistics in a single pass through the data. Image is changed into a one-band
|
||||
// `BandFormatDouble` image of at least 10 columns by n + 1 (where n is number of bands in image in)
|
||||
// rows. Columns are statistics, and are, in order: minimum, maximum, sum, sum of squares, mean,
|
||||
// standard deviation, x coordinate of minimum, y coordinate of minimum, x coordinate of maximum,
|
||||
// y coordinate of maximum.
|
||||
//
|
||||
// Row 0 has statistics for all bands together, row 1 has stats for band 1, and so on.
|
||||
//
|
||||
// If there is more than one maxima or minima, one of them will be chosen at random.
|
||||
func (r *ImageRef) Stats() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenStats(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HistogramFind find the histogram the image.
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenHistFind(r.image, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HistogramCumulative form cumulative histogram.
|
||||
func (r *ImageRef) HistogramCumulative() error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenHistCum(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HistogramNormalise
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenHistNorm(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HistogramEntropy estimate image entropy from a histogram. Entropy is calculated as:
|
||||
// `-sum(p * log2(p))`
|
||||
// where p is histogram-value / sum-of-histogram-values.
|
||||
func (r *ImageRef) HistogramEntropy() (float64, error) {
|
||||
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
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Subtract calculate subtract operation between two images.
|
||||
func (r *ImageRef) Subtract(in2 *ImageRef) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
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)
|
||||
}
|
||||
402
vendor/github.com/davidbyttow/govips/v2/vips/image_transform.go
generated
vendored
Normal file
402
vendor/github.com/davidbyttow/govips/v2/vips/image_transform.go
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
package vips
|
||||
|
||||
// #include "image.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// GetRotationAngleFromExif returns the angle which the image is currently rotated in.
|
||||
// First returned value is the angle and second is a boolean indicating whether image is flipped.
|
||||
// This is based on the EXIF orientation tag standard.
|
||||
// If no proper orientation number is provided, the picture will be assumed to be upright.
|
||||
func GetRotationAngleFromExif(orientation int) (Angle, bool) {
|
||||
switch orientation {
|
||||
case 0, 1, 2:
|
||||
return Angle0, orientation == 2
|
||||
case 3, 4:
|
||||
return Angle180, orientation == 4
|
||||
case 5, 8:
|
||||
return Angle90, orientation == 5
|
||||
case 6, 7:
|
||||
return Angle270, orientation == 7
|
||||
}
|
||||
|
||||
return Angle0, false
|
||||
}
|
||||
|
||||
// AutoRotate rotates the image upright based on the EXIF Orientation tag.
|
||||
// It also resets the orientation information in the EXIF tag to be 1 (i.e. upright).
|
||||
// N.B. libvips does not flip images currently (i.e. no support for orientations 2, 4, 5 and 7).
|
||||
// N.B. due to the HEIF image standard, HEIF images are always autorotated by default on load.
|
||||
// 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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, _, _, err := vipsGenAutorot(r.image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractArea crops the image to a specified area
|
||||
func (r *ImageRef) ExtractArea(left, top, width, height int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if r.Height() > r.PageHeight() {
|
||||
// use animated extract area if more than 1 pages loaded
|
||||
out, err := vipsExtractAreaMultiPage(r.image, left, top, width, height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
} else {
|
||||
out, err := vipsExtractArea(r.image, left, top, width, height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resize resizes the image based on the scale, maintaining aspect ratio
|
||||
func (r *ImageRef) Resize(scale float64, kernel Kernel) error {
|
||||
return r.ResizeWithVScale(scale, -1, kernel)
|
||||
}
|
||||
|
||||
// ResizeWithVScale resizes the image with both horizontal and vertical scaling.
|
||||
// The parameters are the scaling factors.
|
||||
func (r *ImageRef) ResizeWithVScale(hScale, vScale float64, kernel Kernel) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if err := r.PremultiplyAlpha(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pages := r.Pages()
|
||||
pageHeight := r.PageHeight()
|
||||
|
||||
out, err := vipsResizeWithVScale(r.image, hScale, vScale, kernel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
|
||||
if pages > 1 {
|
||||
scale := hScale
|
||||
if vScale != -1 {
|
||||
scale = vScale
|
||||
}
|
||||
newPageHeight := int(math.Round(float64(pageHeight) * scale))
|
||||
if err := r.SetPageHeight(newPageHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return r.UnpremultiplyAlpha()
|
||||
}
|
||||
|
||||
// Thumbnail resizes the image to the given width and height.
|
||||
// crop decides algorithm vips uses to shrink and crop to fill target,
|
||||
func (r *ImageRef) Thumbnail(width, height int, crop Interesting) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsThumbnail(r.image, width, height, crop, SizeBoth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ThumbnailWithSize resizes the image to the given width and height.
|
||||
// crop decides algorithm vips uses to shrink and crop to fill target,
|
||||
// size controls upsize, downsize, both or force
|
||||
func (r *ImageRef) ThumbnailWithSize(width, height int, crop Interesting, size Size) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsThumbnail(r.image, width, height, crop, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Embed embeds the given picture in a new one, i.e. the opposite of ExtractArea
|
||||
func (r *ImageRef) Embed(left, top, width, height int, extend ExtendStrategy) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if r.Height() > r.PageHeight() {
|
||||
out, err := vipsEmbedMultiPage(r.image, left, top, width, height, extend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
} else {
|
||||
out, err := vipsEmbed(r.image, left, top, width, height, extend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmbedBackground embeds the given picture with a background color
|
||||
func (r *ImageRef) EmbedBackground(left, top, width, height int, backgroundColor *Color) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
c := &ColorRGBA{
|
||||
R: backgroundColor.R,
|
||||
G: backgroundColor.G,
|
||||
B: backgroundColor.B,
|
||||
A: 255,
|
||||
}
|
||||
if r.Height() > r.PageHeight() {
|
||||
out, err := vipsEmbedMultiPageBackground(r.image, left, top, width, height, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
} else {
|
||||
out, err := vipsEmbedBackground(r.image, left, top, width, height, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmbedBackgroundRGBA embeds the given picture with a background rgba color
|
||||
func (r *ImageRef) EmbedBackgroundRGBA(left, top, width, height int, backgroundColor *ColorRGBA) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
if r.Height() > r.PageHeight() {
|
||||
out, err := vipsEmbedMultiPageBackground(r.image, left, top, width, height, backgroundColor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
} else {
|
||||
out, err := vipsEmbedBackground(r.image, left, top, width, height, backgroundColor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Zoom zooms the image by repeating pixels (fast nearest-neighbour)
|
||||
func (r *ImageRef) Zoom(xFactor int, yFactor int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenZoom(r.image, xFactor, yFactor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ImageRef) Gravity(gravity Gravity, width int, height int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
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 {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsFlip(r.image, direction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Recomb recombines the image bands using the matrix provided
|
||||
func (r *ImageRef) Recomb(matrix [][]float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
numBands := r.Bands()
|
||||
// Ensure the provided matrix is 3x3
|
||||
if len(matrix) != 3 || len(matrix[0]) != 3 || len(matrix[1]) != 3 || len(matrix[2]) != 3 {
|
||||
return errors.New("Invalid recombination matrix")
|
||||
}
|
||||
// If the image is RGBA, expand the matrix to 4x4
|
||||
if numBands == 4 {
|
||||
matrix = append(matrix, []float64{0, 0, 0, 1})
|
||||
for i := 0; i < 3; i++ {
|
||||
matrix[i] = append(matrix[i], 0)
|
||||
}
|
||||
} else if numBands != 3 {
|
||||
return errors.New("Unsupported number of bands")
|
||||
}
|
||||
|
||||
// Flatten the matrix
|
||||
matrixValues := make([]float64, 0, numBands*numBands)
|
||||
for _, row := range matrix {
|
||||
for _, value := range row {
|
||||
matrixValues = append(matrixValues, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the Go slice to a C array and get its size
|
||||
matrixPtr := unsafe.Pointer(&matrixValues[0])
|
||||
matrixSize := C.size_t(len(matrixValues) * 8) // 8 bytes for each float64
|
||||
|
||||
// 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)
|
||||
|
||||
if matrixImage == nil {
|
||||
return handleVipsError()
|
||||
}
|
||||
|
||||
// Recombine the image using the matrix
|
||||
out, err := vipsGenRecomb(r.image, matrixImage)
|
||||
runtime.KeepAlive(matrixValues)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rotate rotates the image by multiples of 90 degrees. To rotate by arbitrary angles use Similarity.
|
||||
func (r *ImageRef) Rotate(angle Angle) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
width := r.Width()
|
||||
|
||||
if r.Pages() > 1 && (angle == Angle90 || angle == Angle270) {
|
||||
if angle == Angle270 {
|
||||
if err := r.Flip(DirectionHorizontal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.Grid(r.PageHeight(), r.Pages(), 1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if angle == Angle270 {
|
||||
if err := r.Flip(DirectionHorizontal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out, err := vipsGenRot(r.image, angle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
|
||||
if r.Pages() > 1 && (angle == Angle90 || angle == Angle270) {
|
||||
if err := r.SetPageHeight(width); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Similarity lets you scale, offset and rotate images by arbitrary angles in a single operation while defining the
|
||||
// color of new background pixels. If the input image has no alpha channel, the alpha on `backgroundColor` will be
|
||||
// ignored. You can add an alpha channel to an image with `BandJoinConst` (e.g. `img.BandJoinConst([]float64{255})`) or
|
||||
// AddAlpha.
|
||||
func (r *ImageRef) Similarity(scale float64, angle float64, backgroundColor *ColorRGBA,
|
||||
idx float64, idy float64, odx float64, ody float64) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsSimilarity(r.image, scale, angle, backgroundColor, idx, idy, odx, ody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Grid tiles the image pages into a matrix across*down
|
||||
func (r *ImageRef) Grid(tileHeight, across, down int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenGrid(r.image, tileHeight, across, down)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SmartCrop will crop the image based on interesting factor
|
||||
func (r *ImageRef) SmartCrop(width int, height int, interesting Interesting) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsSmartCrop(r.image, width, height, interesting)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Crop will crop the image based on coordinate and box size
|
||||
func (r *ImageRef) Crop(left int, top int, width int, height int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsCrop(r.image, left, top, width, height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Label overlays a label on top of the image
|
||||
func (r *ImageRef) Label(labelParams *LabelParams) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := labelImage(r.image, labelParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replicate repeats an image many times across and down
|
||||
func (r *ImageRef) Replicate(across int, down int) error {
|
||||
defer runtime.KeepAlive(r)
|
||||
out, err := vipsGenReplicate(r.image, across, down)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.setImage(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pixelate applies a simple pixelate filter to the image
|
||||
func Pixelate(imageRef *ImageRef, factor float64) (err error) {
|
||||
if factor < 1 {
|
||||
return errors.New("factor must be greater then 1")
|
||||
}
|
||||
|
||||
width := imageRef.Width()
|
||||
height := imageRef.Height()
|
||||
|
||||
if err = imageRef.Resize(1/factor, KernelAuto); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hScale := float64(width) / float64(imageRef.Width())
|
||||
vScale := float64(height) / float64(imageRef.Height())
|
||||
if err = imageRef.ResizeWithVScale(hScale, vScale, KernelNearest); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
2
vendor/github.com/davidbyttow/govips/v2/vips/math.go
generated
vendored
2
vendor/github.com/davidbyttow/govips/v2/vips/math.go
generated
vendored
@@ -13,7 +13,7 @@ func ValueOf(value float64) Scalar {
|
||||
return Scalar{value, false}
|
||||
}
|
||||
|
||||
// IsZero checkes whether the associated Scalar's value is zero.
|
||||
// IsZero checks whether the associated Scalar's value is zero.
|
||||
func (s *Scalar) IsZero() bool {
|
||||
return s.Value == 0 && !s.Relative
|
||||
}
|
||||
|
||||
8
vendor/github.com/davidbyttow/govips/v2/vips/operations.c
generated
vendored
8
vendor/github.com/davidbyttow/govips/v2/vips/operations.c
generated
vendored
@@ -383,7 +383,7 @@ int get_image_delay(VipsImage *in, int **out) {
|
||||
}
|
||||
|
||||
void set_image_delay(VipsImage *in, const int *array, int n) {
|
||||
return vips_image_set_array_int(in, "delay", array, n);
|
||||
vips_image_set_array_int(in, "delay", array, n);
|
||||
}
|
||||
|
||||
int get_image_loop(VipsImage *in) {
|
||||
@@ -445,7 +445,7 @@ int label(VipsImage *in, VipsImage **out, LabelOptions *o) {
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
if (vips_black(&t[4], 1, 1, NULL) ||
|
||||
vips_linear(t[4], &t[5], ones, o->Color, 3, NULL) ||
|
||||
@@ -454,11 +454,11 @@ int label(VipsImage *in, VipsImage **out, LabelOptions *o) {
|
||||
vips_embed(t[7], &t[8], 0, 0, in->Xsize, in->Ysize, "extend",
|
||||
VIPS_EXTEND_COPY, NULL)) {
|
||||
g_object_unref(base);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if (vips_ifthenelse(t[3], t[8], in, out, "blend", TRUE, NULL)) {
|
||||
g_object_unref(base);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
g_object_unref(base);
|
||||
return 0;
|
||||
|
||||
14
vendor/github.com/davidbyttow/govips/v2/vips/operations.go
generated
vendored
14
vendor/github.com/davidbyttow/govips/v2/vips/operations.go
generated
vendored
@@ -30,14 +30,16 @@ func vipsFindTrim(in *C.VipsImage, threshold float64, backgroundColor *Color) (i
|
||||
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
|
||||
// Copy from C memory into a Go slice, then free the C allocation.
|
||||
result := make([]float64, n)
|
||||
copy(result, (*[4]float64)(unsafe.Pointer(out))[:n:n])
|
||||
gFreePointer(unsafe.Pointer(out))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// https://www.libvips.org/API/current/libvips-arithmetic.html#vips-min
|
||||
@@ -691,7 +693,6 @@ func vipsSetPageHeight(in *C.VipsImage, height int) {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -699,7 +700,6 @@ func vipsImageGetMetaLoader(in *C.VipsImage) (string, bool) {
|
||||
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()
|
||||
@@ -727,7 +727,6 @@ func vipsImageGetBackground(in *C.VipsImage) ([]float64, error) {
|
||||
incOpCounter("imageGetBackground")
|
||||
var out *C.double
|
||||
var n C.int
|
||||
defer gFreePointer(unsafe.Pointer(out))
|
||||
|
||||
if err := C.get_background(in, &out, &n); err != 0 {
|
||||
return nil, handleVipsError()
|
||||
@@ -854,7 +853,6 @@ 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)
|
||||
}
|
||||
@@ -866,7 +864,7 @@ func vipsImageGetAsString(in *C.VipsImage, name string) string {
|
||||
cField := C.CString(name)
|
||||
defer freeCString(cField)
|
||||
var cFieldValue *C.char
|
||||
defer freeCString(cFieldValue)
|
||||
defer func() { freeCString(cFieldValue) }()
|
||||
if int(C.image_get_as_string(in, cField, &cFieldValue)) == 0 {
|
||||
return C.GoString(cFieldValue)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user