mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-09-23 00:57:50 +02:00
IMG-28: Save bmp via target (#1452)
* RLE fixes * disk_sink + fixes * Always 4 bands for v3+ bmp on save * bmpsave fixed (w/o orientation) * fixed ico for target save * cancel() comment * No orientation anymore * No orientation * Fixed non-alpha save bug * Fixed rebase artifact * Fixed condition
This commit is contained in:
@@ -144,7 +144,7 @@ func (it Type) IsVector() bool {
|
||||
}
|
||||
|
||||
func (it Type) SupportsAlpha() bool {
|
||||
return it != JPEG && it != BMP
|
||||
return it != JPEG
|
||||
}
|
||||
|
||||
func (it Type) SupportsAnimationLoad() bool {
|
||||
|
@@ -27,4 +27,7 @@ int vips_bmpload_source(VipsSource *source, VipsImage **out, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
int vips_bmpload_source_go(VipsImgproxySource *source, VipsImage **out);
|
||||
|
||||
// defined in bmpsave.c
|
||||
int vips_bmpsave_target_go(VipsImage *in, VipsTarget *target);
|
||||
|
||||
#endif
|
||||
|
309
vips/bmpsave.c
Normal file
309
vips/bmpsave.c
Normal file
@@ -0,0 +1,309 @@
|
||||
// BMP saver
|
||||
|
||||
#include "vips.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Save a bit of typing.
|
||||
*/
|
||||
#define UC VIPS_FORMAT_UCHAR
|
||||
|
||||
static VipsBandFormat bandfmt_bmp[10] = {
|
||||
/* Band format: UC C US S UI I F X D DX */
|
||||
/* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC
|
||||
};
|
||||
|
||||
// BMP BITMAPINFOHEADERV5 file header struct, ((packed)) since we
|
||||
// do not want any compiler-induced padding
|
||||
typedef struct __attribute__((packed)) _BmpHeader {
|
||||
uint8_t sig[2]; // Signature 'BM'
|
||||
uint32_t file_size; // File size in bytes
|
||||
uint16_t reserved[2]; // Reserved fields
|
||||
uint32_t pix_offset; // Offset to pixel data
|
||||
uint32_t dib_header_size; // DIB header size
|
||||
int32_t width; // Image width
|
||||
int32_t height; // Image height
|
||||
uint16_t color_plane; // Number of color planes
|
||||
uint16_t bpp; // Bits per pixel
|
||||
uint32_t compression; // Compression method
|
||||
uint32_t image_size; // Image size
|
||||
uint32_t x_pixels_per_meter; // Horizontal resolution
|
||||
uint32_t y_pixels_per_meter; // Vertical resolution
|
||||
uint32_t color_use; // Number of colors in palette
|
||||
uint32_t color_important; // Number of important colors
|
||||
uint32_t rmask; // Red mask
|
||||
uint32_t gmask; // Green mask
|
||||
uint32_t bmask; // Blue mask
|
||||
uint32_t amask; // Alpha mask (optional, only for 32 bpp BMP files)
|
||||
uint8_t cs_type[4]; // Color space type (B G R s)
|
||||
uint8_t cs[36]; // CIEXYZTRIPLE Color Space
|
||||
uint32_t red_gamma; // Red gamma
|
||||
uint32_t green_gamma; // Green gamma
|
||||
uint32_t blue_gamma; // Blue gamma
|
||||
uint32_t intent;
|
||||
uint32_t profile_data; // Profile data (optional, only for 32 bpp BMP files)
|
||||
uint32_t profile_size;
|
||||
uint32_t reserved_5;
|
||||
} BmpHeader;
|
||||
|
||||
typedef struct _VipsForeignSaveBmp {
|
||||
VipsForeignSave parent_object;
|
||||
|
||||
VipsTarget *target;
|
||||
VipsPel *line_buffer;
|
||||
|
||||
uint16_t bands;
|
||||
uint32_t line_size;
|
||||
} VipsForeignSaveBmp;
|
||||
|
||||
typedef VipsForeignSaveClass VipsForeignSaveBmpClass;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveBmp, vips_foreign_save_bmp,
|
||||
VIPS_TYPE_FOREIGN_SAVE);
|
||||
|
||||
static void
|
||||
vips_foreign_save_bmp_dispose(GObject *gobject)
|
||||
{
|
||||
VipsForeignSaveBmp *bmp = (VipsForeignSaveBmp *) gobject;
|
||||
|
||||
VIPS_UNREF(bmp->target);
|
||||
|
||||
G_OBJECT_CLASS(vips_foreign_save_bmp_parent_class)->dispose(gobject);
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_save_bmp_block(VipsRegion *region, VipsRect *area, void *a)
|
||||
{
|
||||
VipsForeignSaveBmp *bmp = (VipsForeignSaveBmp *) a;
|
||||
VipsImage *image = region->im;
|
||||
|
||||
// This is the position in the source image
|
||||
uint32_t source_row_size = region->im->Xsize * bmp->bands;
|
||||
|
||||
for (int y = 0; y < area->height; y++) {
|
||||
VipsPel *src = VIPS_REGION_ADDR(region, 0, area->top + y);
|
||||
VipsPel *dst = bmp->line_buffer;
|
||||
|
||||
for (int x = 0; x < source_row_size; x += bmp->bands) {
|
||||
dst[0] = src[2]; // B
|
||||
dst[1] = src[1]; // G
|
||||
dst[2] = src[0]; // R
|
||||
|
||||
if (bmp->bands == 4) {
|
||||
dst[3] = src[3]; // A
|
||||
}
|
||||
|
||||
dst += bmp->bands;
|
||||
src += bmp->bands;
|
||||
}
|
||||
|
||||
if (vips_target_write(bmp->target, bmp->line_buffer, bmp->line_size) < 0) {
|
||||
vips_error("vips_foreign_save_bmp_build", "unable to write BMP pixel data to target");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_save_bmp_build(VipsObject *object)
|
||||
{
|
||||
VipsForeignSave *save = (VipsForeignSave *) object;
|
||||
VipsForeignSaveBmp *bmp = (VipsForeignSaveBmp *) object;
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
if (VIPS_OBJECT_CLASS(vips_foreign_save_bmp_parent_class)->build(object))
|
||||
return -1;
|
||||
|
||||
in = save->ready; // shortcut
|
||||
|
||||
// bands (3 or 4) * 8 bits
|
||||
int bands = vips_image_get_bands(in);
|
||||
|
||||
if ((bands > 3) || (bands > 4)) {
|
||||
vips_error("vips_foreign_save_bmp_build", "BMP source file must have 3 or 4 bands (RGB or RGBA)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bpp = bands * 8;
|
||||
|
||||
// Target image line size trimmed to 4 bytes.
|
||||
uint32_t line_size = (in->Xsize * bands + 3) & (~3);
|
||||
uint32_t image_size = in->Ysize * line_size;
|
||||
|
||||
// pix_offset = header size + file size
|
||||
uint32_t pix_offset = BMP_FILE_HEADER_LEN + BMP_V5_INFO_HEADER_LEN;
|
||||
|
||||
// Format BMP file header. We write 24/32 bpp BMP files only with no compression.
|
||||
BmpHeader header;
|
||||
|
||||
header.sig[0] = 'B';
|
||||
header.sig[1] = 'M';
|
||||
header.file_size = GUINT32_TO_LE(pix_offset + image_size);
|
||||
header.reserved[0] = 0;
|
||||
header.reserved[1] = 0;
|
||||
header.pix_offset = GUINT32_TO_LE(pix_offset);
|
||||
header.dib_header_size = GUINT32_TO_LE(BMP_V5_INFO_HEADER_LEN);
|
||||
header.width = GINT32_TO_LE(in->Xsize);
|
||||
header.height = GINT32_TO_LE(-in->Ysize);
|
||||
header.color_plane = GUINT16_TO_LE(1);
|
||||
header.bpp = GUINT16_TO_LE(bpp);
|
||||
header.compression = COMPRESSION_BI_RGB;
|
||||
header.image_size = GUINT32_TO_LE(image_size);
|
||||
header.x_pixels_per_meter = 0; // GUINT32_TO_LE(2835);
|
||||
header.y_pixels_per_meter = 0; // GUINT32_TO_LE(2835);
|
||||
header.color_use = 0;
|
||||
header.color_important = 0;
|
||||
header.rmask = GUINT32_TO_LE(0x00FF0000); // Standard says that masks are in BE order
|
||||
header.gmask = GUINT32_TO_LE(0x0000FF00);
|
||||
header.bmask = GUINT32_TO_LE(0x000000FF);
|
||||
header.amask = GUINT32_TO_LE(0xFF000000);
|
||||
header.cs_type[0] = 'B'; // Image color profile
|
||||
header.cs_type[1] = 'G';
|
||||
header.cs_type[2] = 'R';
|
||||
header.cs_type[3] = 's';
|
||||
memset(header.cs, 0, sizeof(header.cs)); // CIEXYZTRIPLE Color Space
|
||||
header.red_gamma = 0;
|
||||
header.green_gamma = 0;
|
||||
header.blue_gamma = 0;
|
||||
header.intent = GUINT32_TO_LE(4); // IMAGES intent, must be 4
|
||||
header.profile_data = 0;
|
||||
header.profile_size = 0;
|
||||
header.reserved_5 = 0;
|
||||
|
||||
if (vips_target_write(bmp->target, &header, sizeof(header)) < 0) {
|
||||
vips_error("vips_foreign_save_bmp_build", "unable to write BMP header to target");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate a line buffer for the target image
|
||||
bmp->line_buffer = VIPS_MALLOC(save, line_size);
|
||||
bmp->bands = bands;
|
||||
bmp->line_size = line_size;
|
||||
|
||||
// save image async
|
||||
if (vips_sink_disc(in, vips_foreign_save_bmp_block, bmp))
|
||||
return -1;
|
||||
|
||||
if (vips_target_end(bmp->target))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_bmp_class_init(VipsForeignSaveBmpClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
|
||||
|
||||
gobject_class->dispose = vips_foreign_save_bmp_dispose;
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "bmpsave_base";
|
||||
object_class->description = "save bmp";
|
||||
object_class->build = vips_foreign_save_bmp_build;
|
||||
|
||||
// We do not support saving monochrome images yet (VIPS_FOREIGN_SAVEABLE_MONO)
|
||||
// In v4 we will support it, so we leave it here commented out
|
||||
save_class->saveable =
|
||||
VIPS_SAVEABLE_RGB | // latest vips: VIPS_FOREIGN_SAVEABLE_RGB
|
||||
VIPS_SAVEABLE_RGBA; // latest vips: VIPS_FOREIGN_SAVEABLE_ALPHA
|
||||
|
||||
save_class->format_table = bandfmt_bmp;
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_bmp_init(VipsForeignSaveBmp *bmp)
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignSaveBmpTarget {
|
||||
VipsForeignSaveBmp parent_object;
|
||||
|
||||
VipsTarget *target;
|
||||
} VipsForeignSaveBmpTarget;
|
||||
|
||||
typedef VipsForeignSaveBmpClass VipsForeignSaveBmpTargetClass;
|
||||
|
||||
G_DEFINE_TYPE(VipsForeignSaveBmpTarget, vips_foreign_save_bmp_target,
|
||||
vips_foreign_save_bmp_get_type());
|
||||
|
||||
static int
|
||||
vips_foreign_save_bmp_target_build(VipsObject *object)
|
||||
{
|
||||
VipsForeignSaveBmp *bmp = (VipsForeignSaveBmp *) object;
|
||||
VipsForeignSaveBmpTarget *target = (VipsForeignSaveBmpTarget *) object;
|
||||
|
||||
bmp->target = target->target;
|
||||
g_object_ref(bmp->target);
|
||||
|
||||
return VIPS_OBJECT_CLASS(vips_foreign_save_bmp_target_parent_class)
|
||||
->build(object);
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_bmp_target_class_init(VipsForeignSaveBmpTargetClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "bmpsave_target";
|
||||
object_class->description = "save image to target as PNG";
|
||||
object_class->build = vips_foreign_save_bmp_target_build;
|
||||
|
||||
VIPS_ARG_OBJECT(class, "target", 1,
|
||||
"Target",
|
||||
"Target to save to",
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET(VipsForeignSaveBmpTarget, target),
|
||||
VIPS_TYPE_TARGET);
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_bmp_target_init(VipsForeignSaveBmpTarget *target)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_bmpsave_target: (method)
|
||||
* @in: image to save
|
||||
* @target: save image to this target
|
||||
* @...: `NULL`-terminated list of optional named arguments
|
||||
*
|
||||
* As [method@Image.bmpsave], but save to a target.
|
||||
*
|
||||
* ::: seealso
|
||||
* [method@Image.bmpsave], [method@Image.write_to_target].
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_bmpsave_target(VipsImage *in, VipsTarget *target, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start(ap, target);
|
||||
result = vips_call_split("bmpsave_target", ap, in, target);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// wrapper function which hides varargs (...) from CGo
|
||||
int
|
||||
vips_bmpsave_target_go(VipsImage *in, VipsTarget *target)
|
||||
{
|
||||
return vips_bmpsave_target(in, VIPS_TARGET(target), NULL);
|
||||
}
|
10
vips/ico.go
10
vips/ico.go
@@ -57,17 +57,21 @@ func (img *Image) saveAsIco() (*imagedata.ImageData, error) {
|
||||
return nil, newVipsError("Image dimensions is too big. Max dimension size for ICO is 256")
|
||||
}
|
||||
|
||||
var ptr unsafe.Pointer
|
||||
target := C.vips_target_new_to_memory()
|
||||
|
||||
imgsize := C.size_t(0)
|
||||
|
||||
defer func() {
|
||||
C.g_free_go(&ptr)
|
||||
C.vips_unref_target(target)
|
||||
}()
|
||||
|
||||
if C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, 0, 0, 256) != 0 {
|
||||
if C.vips_pngsave_go(img.VipsImage, target, 0, 0, 256) != 0 {
|
||||
return nil, Error()
|
||||
}
|
||||
|
||||
var blob_ptr = C.vips_blob_get(target.blob, &imgsize)
|
||||
var ptr unsafe.Pointer = unsafe.Pointer(blob_ptr)
|
||||
|
||||
b := ptrToBytes(ptr, int(imgsize))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
57
vips/vips.c
57
vips/vips.c
@@ -14,6 +14,9 @@ vips_initialize()
|
||||
extern GType vips_foreign_load_bmp_source_get_type(void);
|
||||
vips_foreign_load_bmp_source_get_type();
|
||||
|
||||
extern GType vips_foreign_save_bmp_target_get_type(void);
|
||||
vips_foreign_save_bmp_target_get_type();
|
||||
|
||||
return vips_init("imgproxy");
|
||||
}
|
||||
|
||||
@@ -1008,10 +1011,10 @@ vips_strip_all(VipsImage *in, VipsImage **out)
|
||||
}
|
||||
|
||||
int
|
||||
vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace)
|
||||
vips_jpegsave_go(VipsImage *in, VipsTarget *target, int quality, int interlace)
|
||||
{
|
||||
return vips_jpegsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_jpegsave_target(
|
||||
in, target,
|
||||
"Q", quality,
|
||||
"optimize_coding", TRUE,
|
||||
"interlace", interlace,
|
||||
@@ -1019,17 +1022,17 @@ vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interl
|
||||
}
|
||||
|
||||
int
|
||||
vips_jxlsave_go(VipsImage *in, void **buf, size_t *len, int quality, int effort)
|
||||
vips_jxlsave_go(VipsImage *in, VipsTarget *target, int quality, int effort)
|
||||
{
|
||||
return vips_jxlsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_jxlsave_target(
|
||||
in, target,
|
||||
"Q", quality,
|
||||
"effort", effort,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int
|
||||
vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors)
|
||||
vips_pngsave_go(VipsImage *in, VipsTarget *target, int interlace, int quantize, int colors)
|
||||
{
|
||||
int bitdepth;
|
||||
|
||||
@@ -1055,14 +1058,14 @@ vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quant
|
||||
}
|
||||
|
||||
if (!quantize)
|
||||
return vips_pngsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_pngsave_target(
|
||||
in, target,
|
||||
"filter", VIPS_FOREIGN_PNG_FILTER_ALL,
|
||||
"interlace", interlace,
|
||||
NULL);
|
||||
|
||||
return vips_pngsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_pngsave_target(
|
||||
in, target,
|
||||
"filter", VIPS_FOREIGN_PNG_FILTER_NONE,
|
||||
"interlace", interlace,
|
||||
"palette", quantize,
|
||||
@@ -1071,10 +1074,10 @@ vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quant
|
||||
}
|
||||
|
||||
int
|
||||
vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, int effort, VipsForeignWebpPreset preset)
|
||||
vips_webpsave_go(VipsImage *in, VipsTarget *target, int quality, int effort, VipsForeignWebpPreset preset)
|
||||
{
|
||||
return vips_webpsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_webpsave_target(
|
||||
in, target,
|
||||
"Q", quality,
|
||||
"effort", effort,
|
||||
"preset", preset,
|
||||
@@ -1082,35 +1085,35 @@ vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, int effort
|
||||
}
|
||||
|
||||
int
|
||||
vips_gifsave_go(VipsImage *in, void **buf, size_t *len)
|
||||
vips_gifsave_go(VipsImage *in, VipsTarget *target)
|
||||
{
|
||||
int bitdepth = vips_get_palette_bit_depth(in);
|
||||
if (bitdepth <= 0 || bitdepth > 8)
|
||||
bitdepth = 8;
|
||||
return vips_gifsave_buffer(in, buf, len, "bitdepth", bitdepth, NULL);
|
||||
return vips_gifsave_target(in, target, "bitdepth", bitdepth, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality)
|
||||
vips_tiffsave_go(VipsImage *in, VipsTarget *target, int quality)
|
||||
{
|
||||
return vips_tiffsave_buffer(in, buf, len, "Q", quality, NULL);
|
||||
return vips_tiffsave_target(in, target, "Q", quality, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality)
|
||||
vips_heifsave_go(VipsImage *in, VipsTarget *target, int quality)
|
||||
{
|
||||
return vips_heifsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_heifsave_target(
|
||||
in, target,
|
||||
"Q", quality,
|
||||
"compression", VIPS_FOREIGN_HEIF_COMPRESSION_HEVC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int
|
||||
vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality, int speed)
|
||||
vips_avifsave_go(VipsImage *in, VipsTarget *target, int quality, int speed)
|
||||
{
|
||||
return vips_heifsave_buffer(
|
||||
in, buf, len,
|
||||
return vips_heifsave_target(
|
||||
in, target,
|
||||
"Q", quality,
|
||||
"compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1,
|
||||
"effort", 9 - speed,
|
||||
@@ -1144,3 +1147,9 @@ vips_foreign_load_read_full(VipsSource *source, void *buf, size_t len)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
vips_unref_target(VipsTarget *target)
|
||||
{
|
||||
VIPS_UNREF(target);
|
||||
}
|
||||
|
47
vips/vips.go
47
vips/vips.go
@@ -291,21 +291,21 @@ func SupportsSave(it imagetype.Type) bool {
|
||||
|
||||
switch it {
|
||||
case imagetype.JPEG:
|
||||
sup = hasOperation("jpegsave_buffer")
|
||||
sup = hasOperation("jpegsave_target")
|
||||
case imagetype.JXL:
|
||||
sup = hasOperation("jxlsave_buffer")
|
||||
sup = hasOperation("jxlsave_target")
|
||||
case imagetype.PNG, imagetype.ICO:
|
||||
sup = hasOperation("pngsave_buffer")
|
||||
sup = hasOperation("pngsave_target")
|
||||
case imagetype.WEBP:
|
||||
sup = hasOperation("webpsave_buffer")
|
||||
sup = hasOperation("webpsave_target")
|
||||
case imagetype.GIF:
|
||||
sup = hasOperation("gifsave_buffer")
|
||||
sup = hasOperation("gifsave_target")
|
||||
case imagetype.HEIC, imagetype.AVIF:
|
||||
sup = hasOperation("heifsave_buffer")
|
||||
sup = hasOperation("heifsave_target")
|
||||
case imagetype.BMP:
|
||||
sup = true
|
||||
sup = hasOperation("bmpsave_target")
|
||||
case imagetype.TIFF:
|
||||
sup = hasOperation("tiffsave_buffer")
|
||||
sup = hasOperation("tiffsave_target")
|
||||
}
|
||||
|
||||
typeSupportSave.Store(it, sup)
|
||||
@@ -429,13 +429,10 @@ func (img *Image) Save(imgtype imagetype.Type, quality int) (*imagedata.ImageDat
|
||||
return img.saveAsIco()
|
||||
}
|
||||
|
||||
if imgtype == imagetype.BMP {
|
||||
return img.saveAsBmp()
|
||||
}
|
||||
target := C.vips_target_new_to_memory()
|
||||
|
||||
var ptr unsafe.Pointer
|
||||
cancel := func() {
|
||||
C.g_free_go(&ptr)
|
||||
C.vips_unref_target(target)
|
||||
}
|
||||
|
||||
err := C.int(0)
|
||||
@@ -443,22 +440,27 @@ func (img *Image) Save(imgtype imagetype.Type, quality int) (*imagedata.ImageDat
|
||||
|
||||
switch imgtype {
|
||||
case imagetype.JPEG:
|
||||
err = C.vips_jpegsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.JpegProgressive)
|
||||
err = C.vips_jpegsave_go(img.VipsImage, target, C.int(quality), vipsConf.JpegProgressive)
|
||||
case imagetype.JXL:
|
||||
err = C.vips_jxlsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.JxlEffort)
|
||||
err = C.vips_jxlsave_go(img.VipsImage, target, C.int(quality), vipsConf.JxlEffort)
|
||||
case imagetype.PNG:
|
||||
err = C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors)
|
||||
err = C.vips_pngsave_go(img.VipsImage, target, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors)
|
||||
case imagetype.WEBP:
|
||||
err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.WebpEffort, vipsConf.WebpPreset)
|
||||
err = C.vips_webpsave_go(img.VipsImage, target, C.int(quality), vipsConf.WebpEffort, vipsConf.WebpPreset)
|
||||
case imagetype.GIF:
|
||||
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
|
||||
err = C.vips_gifsave_go(img.VipsImage, target)
|
||||
case imagetype.HEIC:
|
||||
err = C.vips_heifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
|
||||
err = C.vips_heifsave_go(img.VipsImage, target, C.int(quality))
|
||||
case imagetype.AVIF:
|
||||
err = C.vips_avifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.AvifSpeed)
|
||||
err = C.vips_avifsave_go(img.VipsImage, target, C.int(quality), vipsConf.AvifSpeed)
|
||||
case imagetype.TIFF:
|
||||
err = C.vips_tiffsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
|
||||
err = C.vips_tiffsave_go(img.VipsImage, target, C.int(quality))
|
||||
case imagetype.BMP:
|
||||
err = C.vips_bmpsave_target_go(img.VipsImage, target)
|
||||
default:
|
||||
// NOTE: probably, it would be better to use defer unref + additionally ref the target
|
||||
// before passing it to the imagedata.ImageData
|
||||
cancel()
|
||||
return nil, newVipsError("Usupported image type to save")
|
||||
}
|
||||
if err != 0 {
|
||||
@@ -466,6 +468,9 @@ func (img *Image) Save(imgtype imagetype.Type, quality int) (*imagedata.ImageDat
|
||||
return nil, Error()
|
||||
}
|
||||
|
||||
var blob_ptr = C.vips_blob_get(target.blob, &imgsize)
|
||||
var ptr unsafe.Pointer = unsafe.Pointer(blob_ptr)
|
||||
|
||||
imgdata := imagedata.ImageData{
|
||||
Type: imgtype,
|
||||
Data: ptrToBytes(ptr, int(imgsize)),
|
||||
|
17
vips/vips.h
17
vips/vips.h
@@ -93,18 +93,19 @@ int vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n);
|
||||
int vips_strip(VipsImage *in, VipsImage **out, int keep_exif_copyright);
|
||||
int vips_strip_all(VipsImage *in, VipsImage **out);
|
||||
|
||||
int vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace);
|
||||
int vips_jxlsave_go(VipsImage *in, void **buf, size_t *len, int quality, int effort);
|
||||
int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize,
|
||||
int vips_jpegsave_go(VipsImage *in, VipsTarget *target, int quality, int interlace);
|
||||
int vips_jxlsave_go(VipsImage *in, VipsTarget *target, int quality, int effort);
|
||||
int vips_pngsave_go(VipsImage *in, VipsTarget *target, int interlace, int quantize,
|
||||
int colors);
|
||||
int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, int effort, VipsForeignWebpPreset preset);
|
||||
int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
|
||||
int vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality);
|
||||
int vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality, int speed);
|
||||
int vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality);
|
||||
int vips_webpsave_go(VipsImage *in, VipsTarget *target, int quality, int effort, VipsForeignWebpPreset preset);
|
||||
int vips_gifsave_go(VipsImage *in, VipsTarget *target);
|
||||
int vips_heifsave_go(VipsImage *in, VipsTarget *target, int quality);
|
||||
int vips_avifsave_go(VipsImage *in, VipsTarget *target, int quality, int speed);
|
||||
int vips_tiffsave_go(VipsImage *in, VipsTarget *target, int quality);
|
||||
|
||||
void vips_cleanup();
|
||||
|
||||
void vips_error_go(const char *function, const char *message);
|
||||
|
||||
int vips_foreign_load_read_full(VipsSource *source, void *buf, size_t len);
|
||||
void vips_unref_target(VipsTarget *target);
|
||||
|
Reference in New Issue
Block a user