Skip to content

Commit

Permalink
Merge pull request #151 from davidbyttow/export_params
Browse files Browse the repository at this point in the history
Adds format-specific export params
  • Loading branch information
tonimelisma committed Jan 6, 2021
2 parents f87489b + b2f6b21 commit feb2425
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 190 deletions.
164 changes: 94 additions & 70 deletions vips/foreign.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
&params->outputBuffer,
&params->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,
&params->outputBuffer,
&params->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,
&params->outputBuffer,
&params->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,
&params->outputBuffer,
&params->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,
&params->outputBuffer,
&params->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;
}
}

111 changes: 57 additions & 54 deletions vips/foreign.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(&params); 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
}
38 changes: 30 additions & 8 deletions vips/foreign.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#include <vips/vips.h>
#include <vips/foreign.h>

#ifndef BOOL
#define BOOL int
#endif

enum types {
typedef enum types {
UNKNOWN = 0,
JPEG,
WEBP,
Expand All @@ -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);

0 comments on commit feb2425

Please sign in to comment.