diff --git a/vips/foreign.c b/vips/foreign.c index 722a3b1c..e8d540c6 100644 --- a/vips/foreign.c +++ b/vips/foreign.c @@ -2,94 +2,118 @@ #include "foreign.h" int load_image_buffer(void *buf, size_t len, int imageType, VipsImage **out) { - int code = 1; + int code = 1; - if (imageType == JPEG) { - code = vips_jpegload_buffer(buf, len, out, NULL); - } else if (imageType == PNG) { - code = vips_pngload_buffer(buf, len, out, NULL); - } else if (imageType == WEBP) { - code = vips_webpload_buffer(buf, len, out, NULL); - } else if (imageType == TIFF) { - code = vips_tiffload_buffer(buf, len, out, NULL); - } else if (imageType == GIF) { - code = vips_gifload_buffer(buf, len, out, NULL); - } else if (imageType == PDF) { - code = vips_pdfload_buffer(buf, len, out, NULL); - } else if (imageType == SVG) { - code = vips_svgload_buffer(buf, len, out, NULL); - } else if (imageType == HEIF) { - // added autorotate on load as currently it addresses orientation issues - // https://github.com/libvips/libvips/pull/1680 - code = vips_heifload_buffer(buf, len, out, "autorotate", TRUE, NULL); - } else if (imageType == MAGICK) { - code = vips_magickload_buffer(buf, len, out, NULL); - } + if (imageType == JPEG) { + code = vips_jpegload_buffer(buf, len, out, NULL); + } else if (imageType == PNG) { + code = vips_pngload_buffer(buf, len, out, NULL); + } else if (imageType == WEBP) { + code = vips_webpload_buffer(buf, len, out, NULL); + } else if (imageType == TIFF) { + code = vips_tiffload_buffer(buf, len, out, NULL); + } else if (imageType == GIF) { + code = vips_gifload_buffer(buf, len, out, NULL); + } else if (imageType == PDF) { + code = vips_pdfload_buffer(buf, len, out, NULL); + } else if (imageType == SVG) { + code = vips_svgload_buffer(buf, len, out, NULL); + } else if (imageType == HEIF) { + // added autorotate on load as currently it addresses orientation issues + // https://github.com/libvips/libvips/pull/1680 + code = vips_heifload_buffer(buf, len, out, "autorotate", TRUE, NULL); + } else if (imageType == MAGICK) { + code = vips_magickload_buffer(buf, len, out, NULL); + } - return code; + return code; } // https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-jpegsave-buffer -int save_jpeg_buffer(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace) { - return vips_jpegsave_buffer(in, buf, len, - "strip", INT_TO_GBOOLEAN(strip), - "Q", quality, - "optimize_coding", TRUE, - "interlace", INT_TO_GBOOLEAN(interlace), - "subsample_mode", VIPS_FOREIGN_JPEG_SUBSAMPLE_ON, - NULL - ); +int save_jpeg_buffer(SaveParams *params) { + return vips_jpegsave_buffer(params->inputImage, + ¶ms->outputBuffer, + ¶ms->outputLen, + "strip", INT_TO_GBOOLEAN(params->stripMetadata), + "Q", params->quality, + "optimize_coding", TRUE, + "interlace", INT_TO_GBOOLEAN(params->interlace), + "subsample_mode", VIPS_FOREIGN_JPEG_SUBSAMPLE_ON, + NULL); } // https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-pngsave-buffer -int save_png_buffer(VipsImage *in, void **buf, size_t *len, int strip, int compression, int interlace) { - return vips_pngsave_buffer(in, buf, len, - "strip", INT_TO_GBOOLEAN(strip), - "compression", compression, - "interlace", INT_TO_GBOOLEAN(interlace), - "filter", VIPS_FOREIGN_PNG_FILTER_NONE, - NULL - ); +int save_png_buffer(SaveParams *params) { + return vips_pngsave_buffer(params->inputImage, + ¶ms->outputBuffer, + ¶ms->outputLen, + "strip", INT_TO_GBOOLEAN(params->stripMetadata), + "compression", params->pngCompression, + "interlace", INT_TO_GBOOLEAN(params->interlace), + "filter", VIPS_FOREIGN_PNG_FILTER_NONE, + NULL); } // todo: support additional params // https://github.com/libvips/libvips/blob/master/libvips/foreign/webpsave.c#L524 // https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-webpsave-buffer -int save_webp_buffer(VipsImage *in, void **buf, size_t *len, int strip, int quality, int lossless, int effort) { - return vips_webpsave_buffer(in, buf, len, - "strip", INT_TO_GBOOLEAN(strip), - "Q", quality, - "lossless", INT_TO_GBOOLEAN(lossless), - "reduction_effort", effort, - NULL - ); +int save_webp_buffer(SaveParams *params) { + return vips_webpsave_buffer(params->inputImage, + ¶ms->outputBuffer, + ¶ms->outputLen, + "strip", INT_TO_GBOOLEAN(params->stripMetadata), + "Q", params->quality, + "lossless", INT_TO_GBOOLEAN(params->webpLossless), + "reduction_effort", params->webpReductionEffort, + NULL); } // todo: support additional params // https://github.com/libvips/libvips/blob/master/libvips/foreign/heifsave.c#L653 -int save_heif_buffer(VipsImage *in, void **buf, size_t *len, int quality, int lossless) { - return vips_heifsave_buffer(in, buf, len, - "Q", quality, - "lossless", INT_TO_GBOOLEAN(lossless), - NULL - ); +int save_heif_buffer(SaveParams *params) { + return vips_heifsave_buffer(params->inputImage, + ¶ms->outputBuffer, + ¶ms->outputLen, + "Q", params->quality, + "lossless", INT_TO_GBOOLEAN(params->heifLossless), + NULL); } // https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-tiffsave-buffer -int save_tiff_buffer(VipsImage *in, void **buf, size_t *len, int strip, int quality, int lossless) { - // TODO: Allow various options to be passed in. - return vips_tiffsave_buffer(in, buf, len, - "strip", INT_TO_GBOOLEAN(strip), - "Q", quality, - "compression", lossless ? VIPS_FOREIGN_TIFF_COMPRESSION_NONE : VIPS_FOREIGN_TIFF_COMPRESSION_LZW, - "pyramid", FALSE, - "predictor", VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL, - "pyramid", FALSE, - "tile", FALSE, - "tile_height", 256, - "tile_width", 256, - "xres", 1.0, - "yres", 1.0, - NULL - ); +int save_tiff_buffer(SaveParams *params) { + return vips_tiffsave_buffer(params->inputImage, + ¶ms->outputBuffer, + ¶ms->outputLen, + "strip", INT_TO_GBOOLEAN(params->stripMetadata), + "Q", params->quality, + "compression", params->tiffCompression, + "pyramid", FALSE, + "predictor", VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL, + "pyramid", FALSE, + "tile", FALSE, + "tile_height", 256, + "tile_width", 256, + "xres", 1.0, + "yres", 1.0, + NULL); } + +int save_to_buffer(SaveParams *params) { + switch (params->outputFormat) + { + case JPEG: + return save_jpeg_buffer(params); + case PNG: + return save_png_buffer(params); + case WEBP: + return save_webp_buffer(params); + case HEIF: + return save_heif_buffer(params); + case TIFF: + return save_tiff_buffer(params); + default: + g_warning("Unsupported output type given: %d", params->outputFormat); + return -1; + } +} + diff --git a/vips/foreign.go b/vips/foreign.go index bc775b36..948d3d3f 100644 --- a/vips/foreign.go +++ b/vips/foreign.go @@ -61,6 +61,15 @@ var ImageTypes = map[ImageType]string{ ImageTypeBMP: "bmp", } +// TiffCompression represents method for compressing a tiff at export +type TiffCompression int + +// TiffCompression enum +const ( + TiffCompressionNone TiffCompression = C.VIPS_FOREIGN_TIFF_COMPRESSION_NONE + TiffCompressionLzw TiffCompression = C.VIPS_FOREIGN_TIFF_COMPRESSION_LZW +) + // FileExt returns the canonical extension for the ImageType func (i ImageType) FileExt() string { if ext, ok := imageTypeExtensionMap[i]; ok { @@ -227,89 +236,83 @@ func bmpToPNG(src []byte) ([]byte, error) { return w.Bytes(), nil } -func vipsSavePNGToBuffer(in *C.VipsImage, stripMetadata bool, compression int, interlaced bool) ([]byte, error) { +func vipsSavePNGToBuffer(in *C.VipsImage, params PngExportParams) ([]byte, error) { incOpCounter("save_png_buffer") - var ptr unsafe.Pointer - cLen := C.size_t(0) - - strip := C.int(boolToInt(stripMetadata)) - comp := C.int(compression) - inter := C.int(boolToInt(interlaced)) - if err := C.save_png_buffer(in, &ptr, &cLen, strip, comp, inter); err != 0 { - return nil, handleSaveBufferError(ptr) + p := C.struct_SaveParams{ + inputImage: in, + outputFormat: C.PNG, + stripMetadata: C.int(boolToInt(params.StripMetadata)), + interlace: C.int(boolToInt(params.Interlace)), + pngCompression: C.int(params.Compression), } - return toBuff(ptr, cLen), nil + return vipsSaveToBuffer(p) } -func vipsSaveWebPToBuffer(in *C.VipsImage, stripMetadata bool, quality int, lossless bool, effort int) ([]byte, error) { +func vipsSaveWebPToBuffer(in *C.VipsImage, params WebpExportParams) ([]byte, error) { incOpCounter("save_webp_buffer") - var ptr unsafe.Pointer - cLen := C.size_t(0) - - strip := C.int(boolToInt(stripMetadata)) - qual := C.int(quality) - loss := C.int(boolToInt(lossless)) - eff := C.int(effort) - if err := C.save_webp_buffer(in, &ptr, &cLen, strip, qual, loss, eff); err != 0 { - return nil, handleSaveBufferError(ptr) + p := C.struct_SaveParams{ + inputImage: in, + outputFormat: C.WEBP, + stripMetadata: C.int(boolToInt(params.StripMetadata)), + quality: C.int(params.Quality), + webpLossless: C.int(boolToInt(params.Lossless)), + webpReductionEffort: C.int(params.ReductionEffort), } - return toBuff(ptr, cLen), nil + return vipsSaveToBuffer(p) } -func vipsSaveTIFFToBuffer(in *C.VipsImage, stripMetadata bool, quality int, lossless bool) ([]byte, error) { +func vipsSaveTIFFToBuffer(in *C.VipsImage, params TiffExportParams) ([]byte, error) { incOpCounter("save_tiff_buffer") - var ptr unsafe.Pointer - cLen := C.size_t(0) - strip := C.int(boolToInt(stripMetadata)) - qual := C.int(quality) - loss := C.int(boolToInt(lossless)) - - if err := C.save_tiff_buffer(in, &ptr, &cLen, strip, qual, loss); err != 0 { - return nil, handleSaveBufferError(ptr) + p := C.struct_SaveParams{ + inputImage: in, + outputFormat: C.TIFF, + stripMetadata: C.int(boolToInt(params.StripMetadata)), + quality: C.int(params.Quality), + tiffCompression: C.VipsForeignTiffCompression(params.Compression), } - return toBuff(ptr, cLen), nil + return vipsSaveToBuffer(p) } -func vipsSaveHEIFToBuffer(in *C.VipsImage, quality int, lossless bool) ([]byte, error) { +func vipsSaveHEIFToBuffer(in *C.VipsImage, params HeifExportParams) ([]byte, error) { incOpCounter("save_heif_buffer") - var ptr unsafe.Pointer - cLen := C.size_t(0) - - qual := C.int(quality) - loss := C.int(boolToInt(lossless)) - if err := C.save_heif_buffer(in, &ptr, &cLen, qual, loss); err != 0 { - return nil, handleSaveBufferError(ptr) + p := C.struct_SaveParams{ + inputImage: in, + outputFormat: C.HEIF, + quality: C.int(params.Quality), + heifLossless: C.int(boolToInt(params.Lossless)), } - return toBuff(ptr, cLen), nil + return vipsSaveToBuffer(p) } -func vipsSaveJPEGToBuffer(in *C.VipsImage, quality int, stripMetadata, interlaced bool) ([]byte, error) { +func vipsSaveJPEGToBuffer(in *C.VipsImage, params JpegExportParams) ([]byte, error) { incOpCounter("save_jpeg_buffer") - var ptr unsafe.Pointer - cLen := C.size_t(0) - - strip := C.int(boolToInt(stripMetadata)) - qual := C.int(quality) - inter := C.int(boolToInt(interlaced)) - if err := C.save_jpeg_buffer(in, &ptr, &cLen, strip, qual, inter); err != 0 { - return nil, handleSaveBufferError(ptr) + p := C.struct_SaveParams{ + inputImage: in, + outputFormat: C.JPEG, + stripMetadata: C.int(boolToInt(params.StripMetadata)), + quality: C.int(params.Quality), + interlace: C.int(boolToInt(params.Interlace)), } - return toBuff(ptr, cLen), nil + return vipsSaveToBuffer(p) } -func toBuff(ptr unsafe.Pointer, cLen C.size_t) []byte { - buf := C.GoBytes(ptr, C.int(cLen)) - gFreePointer(ptr) +func vipsSaveToBuffer(params C.struct_SaveParams) ([]byte, error) { + if err := C.save_to_buffer(¶ms); err != 0 { + return nil, handleSaveBufferError(params.outputBuffer) + } + + buf := C.GoBytes(params.outputBuffer, C.int(params.outputLen)) + defer gFreePointer(params.outputBuffer) - return buf + return buf, nil } diff --git a/vips/foreign.h b/vips/foreign.h index 2da384fa..5e9337cc 100644 --- a/vips/foreign.h +++ b/vips/foreign.h @@ -4,8 +4,11 @@ #include #include +#ifndef BOOL +#define BOOL int +#endif -enum types { +typedef enum types { UNKNOWN = 0, JPEG, WEBP, @@ -17,13 +20,32 @@ enum types { MAGICK, HEIF, BMP -}; +} ImageType; int load_image_buffer(void *buf, size_t len, int imageType, VipsImage **out); -// TODO: Pass options as discrete params objects based on types rather than long function signatures -int save_jpeg_buffer(VipsImage* image, void **buf, size_t *len, int strip, int quality, int interlace); -int save_png_buffer(VipsImage *in, void **buf, size_t *len, int strip, int compression, int interlace); -int save_webp_buffer(VipsImage *in, void **buf, size_t *len, int strip, int quality, int lossless, int effort); -int save_heif_buffer(VipsImage *in, void **buf, size_t *len, int quality, int lossless); -int save_tiff_buffer(VipsImage *in, void **buf, size_t *len, int strip, int quality, int lossless); +typedef struct SaveParams { + VipsImage *inputImage; + void *outputBuffer; + ImageType outputFormat; + size_t outputLen; + + BOOL stripMetadata; + int quality; + BOOL interlace; + + // PNG + int pngCompression; + + // WEBP + BOOL webpLossless; + int webpReductionEffort; + + // HEIF + BOOL heifLossless; + + // TIFF + VipsForeignTiffCompression tiffCompression; +} SaveParams; + +int save_to_buffer(SaveParams *params); diff --git a/vips/image.go b/vips/image.go index 01403f98..083e3b96 100644 --- a/vips/image.go +++ b/vips/image.go @@ -44,6 +44,7 @@ type ImageMetadata struct { } // ExportParams are options when exporting an image to file or buffer. +// Deprecated: Use format-specific params type ExportParams struct { Format ImageType Quality int @@ -58,6 +59,7 @@ type ExportParams struct { // By default, govips creates interlaced, lossy images with a quality of 80/100 and compression of 6/10. // As these are default values for a wide variety of image formats, their application varies. // Some formats use the quality parameters, some compression, etc. +// Deprecated: Use format-specific params func NewDefaultExportParams() *ExportParams { return &ExportParams{ Format: ImageTypeUnknown, // defaults to the starting encoder @@ -71,6 +73,7 @@ func NewDefaultExportParams() *ExportParams { // NewDefaultJPEGExportParams creates default values for an export of a JPEG image. // By default, govips creates interlaced JPEGs with a quality of 80/100. +// Deprecated: Use NewJpegExportParams func NewDefaultJPEGExportParams() *ExportParams { return &ExportParams{ Format: ImageTypeJPEG, @@ -81,6 +84,7 @@ func NewDefaultJPEGExportParams() *ExportParams { // NewDefaultPNGExportParams creates default values for an export of a PNG image. // By default, govips creates non-interlaced PNGs with a compression of 6/10. +// Deprecated: Use NewPngExportParams func NewDefaultPNGExportParams() *ExportParams { return &ExportParams{ Format: ImageTypePNG, @@ -91,6 +95,7 @@ func NewDefaultPNGExportParams() *ExportParams { // NewDefaultWEBPExportParams creates default values for an export of a WEBP image. // By default, govips creates lossy images with a quality of 75/100. +// Deprecated: Use NewWebpExportParams func NewDefaultWEBPExportParams() *ExportParams { return &ExportParams{ Format: ImageTypeWEBP, @@ -100,6 +105,85 @@ func NewDefaultWEBPExportParams() *ExportParams { } } +// JpegExportParams are options when exporting a JPEG to file or buffer +type JpegExportParams struct { + StripMetadata bool + Quality int + Interlace bool +} + +// NewJpegExportParams creates default values for an export of a JPEG image. +// By default, govips creates interlaced JPEGs with a quality of 80/100. +func NewJpegExportParams() *JpegExportParams { + return &JpegExportParams{ + Quality: 80, + Interlace: true, + } +} + +// PngExportParams are options when exporting a PNG to file or buffer +type PngExportParams struct { + StripMetadata bool + Compression int + Interlace bool +} + +// NewPngExportParams creates default values for an export of a PNG image. +// By default, govips creates non-interlaced PNGs with a compression of 6/10. +func NewPngExportParams() *PngExportParams { + return &PngExportParams{ + Compression: 6, + Interlace: false, + } +} + +// WebpExportParams are options when exporting a WEBP to file or buffer +type WebpExportParams struct { + StripMetadata bool + Quality int + Lossless bool + ReductionEffort int +} + +// NewWebpExportParams creates default values for an export of a WEBP image. +// By default, govips creates lossy images with a quality of 75/100. +func NewWebpExportParams() *WebpExportParams { + return &WebpExportParams{ + Quality: 75, + Lossless: false, + ReductionEffort: 4, + } +} + +// HeifExportParams are options when exporting a HEIF to file or buffer +type HeifExportParams struct { + Quality int + Lossless bool +} + +// NewHeifExportParams creates default values for an export of a HEIF image. +func NewHeifExportParams() *HeifExportParams { + return &HeifExportParams{ + Quality: 80, + Lossless: false, + } +} + +// TiffExportParams are options when exporting a TIFF to file or buffer +type TiffExportParams struct { + StripMetadata bool + Quality int + Compression TiffCompression +} + +// NewTiffExportParams creates default values for an export of a TIFF image. +func NewTiffExportParams() *TiffExportParams { + return &TiffExportParams{ + Quality: 80, + Compression: TiffCompressionLzw, + } +} + // NewImageFromReader loads an ImageRef from the given reader func NewImageFromReader(r io.Reader) (*ImageRef, error) { buf, err := ioutil.ReadAll(r) @@ -320,44 +404,157 @@ func (r *ImageRef) IsColorSpaceSupported() bool { return vipsIsColorSpaceSupported(r.image) } +func (r *ImageRef) newMetadata(format ImageType) *ImageMetadata { + return &ImageMetadata{ + Format: format, + Width: r.Width(), + Height: r.Height(), + Colorspace: r.ColorSpace(), + Orientation: r.GetOrientation(), + } +} + // 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 ioutil.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) { - p := params - if p == nil { - switch r.format { - case ImageTypeJPEG: - p = NewDefaultJPEGExportParams() - case ImageTypePNG: - p = NewDefaultPNGExportParams() - case ImageTypeWEBP: - p = NewDefaultWEBPExportParams() - default: - p = NewDefaultExportParams() + 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 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, + }) + default: + format = ImageTypeJPEG + return r.ExportJpeg(&JpegExportParams{ + Quality: params.Quality, + StripMetadata: params.StripMetadata, + Interlace: params.Interlaced, + }) + } +} + +// 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()) + default: + return r.ExportJpeg(NewJpegExportParams()) } +} - if p.Format == ImageTypeUnknown { - p.Format = r.format +// ExportJpeg exports the image as JPEG to a buffer. +func (r *ImageRef) ExportJpeg(params *JpegExportParams) ([]byte, *ImageMetadata, error) { + if params == nil { + params = NewJpegExportParams() } - // the exported buf is not necessarily in same format as the original buf, might default to JPEG as well. - buf, format, err := r.exportBuffer(p) + buf, err := vipsSaveJPEGToBuffer(r.image, *params) if err != nil { return nil, nil, err } - metadata := &ImageMetadata{ - Format: format, - Width: r.Width(), - Height: r.Height(), - Colorspace: r.ColorSpace(), - Orientation: r.GetOrientation(), + return buf, r.newMetadata(ImageTypeJPEG), nil +} + +// ExportPng exports the image as PNG to a buffer. +func (r *ImageRef) ExportPng(params *PngExportParams) ([]byte, *ImageMetadata, error) { + 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) { + if params == nil { + params = NewWebpExportParams() + } + + buf, err := vipsSaveWebPToBuffer(r.image, *params) + 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) { + 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) { + if params == nil { + params = NewTiffExportParams() + } + + buf, err := vipsSaveTIFFToBuffer(r.image, *params) + if err != nil { + return nil, nil, err } - return buf, metadata, nil + return buf, r.newMetadata(ImageTypeTIFF), nil } // CompositeMulti composites the given overlay image on top of the associated image with provided blending mode. @@ -857,6 +1054,7 @@ func (r *ImageRef) Similarity(scale float64, angle float64, backgroundColor *Col return nil } +// SmartCrop will crop the image based on interestingness factor func (r *ImageRef) SmartCrop(width int, height int, interesting Interesting) error { out, err := vipsSmartCrop(r.image, width, height, interesting) if err != nil { @@ -921,44 +1119,10 @@ func (r *ImageRef) setImage(image *C.VipsImage) { r.image = image } -func (r *ImageRef) exportBuffer(params *ExportParams) ([]byte, ImageType, error) { - var buf []byte - var err error - - format := params.Format - if format != ImageTypeUnknown && !IsTypeSupported(format) { - return nil, ImageTypeUnknown, fmt.Errorf("cannot save to %#v", ImageTypes[format]) - } - - switch format { - case ImageTypeWEBP: - buf, err = vipsSaveWebPToBuffer(r.image, params.StripMetadata, params.Quality, params.Lossless, params.Effort) - case ImageTypePNG: - buf, err = vipsSavePNGToBuffer(r.image, params.StripMetadata, params.Compression, params.Interlaced) - case ImageTypeTIFF: - buf, err = vipsSaveTIFFToBuffer(r.image, params.StripMetadata, params.Quality, params.Lossless) - case ImageTypeHEIF: - buf, err = vipsSaveHEIFToBuffer(r.image, params.Quality, params.Lossless) - default: - format = ImageTypeJPEG - buf, err = vipsSaveJPEGToBuffer(r.image, params.Quality, params.StripMetadata, params.Interlaced) - } - - if err != nil { - return nil, ImageTypeUnknown, err - } - - return buf, format, nil -} - -/////////////// - func vipsHasAlpha(in *C.VipsImage) bool { return int(C.has_alpha_channel(in)) > 0 } -////////////// - func clearImage(ref *C.VipsImage) { C.clear_image(&ref) } diff --git a/vips/image_golden_test.go b/vips/image_golden_test.go index 57bb3b80..77403758 100644 --- a/vips/image_golden_test.go +++ b/vips/image_golden_test.go @@ -2,7 +2,6 @@ package vips import ( "bytes" - "golang.org/x/image/bmp" "image" jpeg2 "image/jpeg" "image/png" @@ -12,6 +11,8 @@ import ( "strings" "testing" + "golang.org/x/image/bmp" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/vips/image_test.go b/vips/image_test.go index dfaf2cda..a47dcb42 100644 --- a/vips/image_test.go +++ b/vips/image_test.go @@ -123,9 +123,10 @@ func TestImageRef_BMP(t *testing.T) { require.NoError(t, err) require.NotNil(t, img) - _, metadata, err := img.Export(nil) + exported, metadata, err := img.Export(nil) assert.NoError(t, err) assert.Equal(t, ImageTypePNG, metadata.Format) + assert.NotNil(t, exported) } func TestImageRef_SVG(t *testing.T) {