mirror of
https://github.com/talgo-cloud/bimg.git
synced 2026-03-15 10:25:55 -07:00
Merge pull request #147 from h2non/revert-143-master
Revert "Fix for memory issue when watermarking images"
This commit is contained in:
commit
71db9b9765
4 changed files with 118 additions and 48 deletions
|
|
@ -354,7 +354,13 @@ func watermarkImageWithAnotherImage(image *C.VipsImage, w WatermarkImage) (*C.Vi
|
||||||
w.Opacity = 1.0
|
w.Opacity = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := vipsDrawWatermark(image, w)
|
watermark, _, err := loadImage(w.Buf)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
image, err = vipsDrawWatermark(image, watermark, w)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
11
vips.go
11
vips.go
|
|
@ -596,12 +596,15 @@ func max(x int) int {
|
||||||
return int(math.Max(float64(x), 0))
|
return int(math.Max(float64(x), 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func vipsDrawWatermark(image *C.VipsImage, o WatermarkImage) (*C.VipsImage, error) {
|
func vipsDrawWatermark(image *C.VipsImage, watermark *C.VipsImage, o WatermarkImage) (*C.VipsImage, error) {
|
||||||
var out *C.VipsImage
|
var out *C.VipsImage
|
||||||
|
|
||||||
watermark, _, e := vipsRead(o.Buf)
|
if !vipsHasAlpha(image) {
|
||||||
if e != nil {
|
C.vips_add_band(image, &image, C.double(255.0))
|
||||||
return nil, e
|
}
|
||||||
|
|
||||||
|
if !vipsHasAlpha(watermark) {
|
||||||
|
C.vips_add_band(watermark, &watermark, C.double(255.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := vipsWatermarkImageOptions{C.int(o.Left), C.int(o.Top), C.float(o.Opacity)}
|
opts := vipsWatermarkImageOptions{C.int(o.Left), C.int(o.Top), C.float(o.Opacity)}
|
||||||
|
|
|
||||||
141
vips.h
141
vips.h
|
|
@ -463,51 +463,112 @@ vips_add_band(VipsImage *in, VipsImage **out, double c) {
|
||||||
|
|
||||||
int
|
int
|
||||||
vips_watermark_image(VipsImage *in, VipsImage *sub, VipsImage **out, WatermarkImageOptions *o) {
|
vips_watermark_image(VipsImage *in, VipsImage *sub, VipsImage **out, WatermarkImageOptions *o) {
|
||||||
VipsImage *base = vips_image_new();
|
int bands = in->Bands;
|
||||||
VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
|
double background[4] = {0.0, 0.0, 0.0, 0.0};
|
||||||
|
|
||||||
// add in and sub for unreffing and later use
|
VipsArrayDouble *vipsBackground = vips_array_double_new(background, 4);
|
||||||
t[0] = in;
|
|
||||||
t[1] = sub;
|
|
||||||
|
|
||||||
if (has_alpha_channel(in) == 0) {
|
VipsImage *base = vips_image_new();
|
||||||
vips_bandjoin_const1(in, &t[0], 255.0, NULL);
|
VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 10);
|
||||||
// in is no longer in the array and won't be unreffed, so add it at the end
|
|
||||||
t[8] = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_alpha_channel(sub) == 0) {
|
t[0] = in;
|
||||||
vips_bandjoin_const1(sub, &t[1], 255.0, NULL);
|
t[1] = sub;
|
||||||
// sub is no longer in the array and won't be unreffed, so add it at the end
|
|
||||||
t[9] = sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place watermark image in the right place and size it to the size of the
|
if (vips_embed(t[1], &t[2], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, "extend", VIPS_EXTEND_BACKGROUND, "background", vipsBackground, NULL)) {
|
||||||
// image that should be watermarked
|
g_object_unref(base);
|
||||||
if (
|
return 1;
|
||||||
vips_embed(t[1], &t[2], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
|
}
|
||||||
g_object_unref(base);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a mask image based on the alpha band from the watermark image
|
//Get Sub bands without alpha
|
||||||
// and place it in the right position
|
if (vips_extract_band(t[2], &t[3], 0, "n", t[2]->Bands - 1, NULL)) {
|
||||||
if (
|
g_object_unref(base);
|
||||||
vips_extract_band(t[1], &t[3], t[1]->Bands - 1, "n", 1, NULL) ||
|
return 1;
|
||||||
vips_linear1(t[3], &t[4], o->Opacity, 0.0, NULL) ||
|
}
|
||||||
vips_cast(t[4], &t[5], VIPS_FORMAT_UCHAR, NULL) ||
|
|
||||||
vips_copy(t[5], &t[6], "interpretation", t[0]->Type, NULL) ||
|
|
||||||
vips_embed(t[6], &t[7], o->Left, o->Top, t[0]->Xsize, t[0]->Ysize, NULL)) {
|
|
||||||
g_object_unref(base);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blend the mask and watermark image and write to output.
|
//Get Sub Image alpha
|
||||||
if (vips_ifthenelse(t[7], t[2], t[0], out, "blend", TRUE, NULL)) {
|
if (
|
||||||
g_object_unref(base);
|
vips_extract_band(t[2], &t[4], t[2]->Bands - 1, "n", 1, NULL) ||
|
||||||
return 1;
|
vips_linear1(t[4], &t[4], o->Opacity / 255.0, 0.0, NULL)
|
||||||
}
|
) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
g_object_unref(base);
|
//Apply alpha to other sub bands to remove unwanted pixels
|
||||||
return 0;
|
if (vips_multiply(t[3], t[4], &t[3], NULL)) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get in bands without alpha
|
||||||
|
if (vips_extract_band(t[0], &t[5], 0, "n", t[0]->Bands - 1, NULL)) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get in alpha
|
||||||
|
if (
|
||||||
|
vips_extract_band(t[0], &t[6], t[0]->Bands - 1, "n", 1, NULL) ||
|
||||||
|
vips_linear1(t[6], &t[6], 1.0 / 255.0, 0.0, NULL)
|
||||||
|
) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute normalized output alpha channel:
|
||||||
|
//
|
||||||
|
// References:
|
||||||
|
// - http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||||
|
// - https://github.com/jcupitt/ruby-vips/issues/28#issuecomment-9014826
|
||||||
|
//
|
||||||
|
// out_a = src_a + dst_a * (1 - src_a)
|
||||||
|
// ^^^^^^^^^^^
|
||||||
|
|
||||||
|
if (
|
||||||
|
vips_linear1(t[4], &t[7], -1.0, 1.0, NULL) ||
|
||||||
|
vips_multiply(t[6], t[7], &t[8], NULL)
|
||||||
|
) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//outAlphaNormalized in t[8]
|
||||||
|
if (vips_add(t[4], t[8], &t[8], NULL)) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute output RGB channels:
|
||||||
|
//
|
||||||
|
// Wikipedia:
|
||||||
|
// out_rgb = (src_rgb * src_a + dst_rgb * dst_a * (1 - src_a)) / out_a
|
||||||
|
// ^^^^^^^^^^^
|
||||||
|
// t0
|
||||||
|
//
|
||||||
|
// Omit division by `out_a` since `Compose` is supposed to output a
|
||||||
|
// premultiplied RGBA image as reversal of premultiplication is handled
|
||||||
|
// externally.
|
||||||
|
|
||||||
|
if (vips_multiply(t[5], t[7], &t[9], NULL)) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//outRGBPremultiplied in t[9]
|
||||||
|
if (vips_add(t[3], t[9], &t[9], NULL)) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
vips_linear1(t[8], &t[8], 255.0, 0.0, NULL) ||
|
||||||
|
vips_bandjoin2(t[9], t[8], out, NULL)
|
||||||
|
) {
|
||||||
|
g_object_unref(base);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(base);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,10 +123,10 @@ func TestVipsWatermark(t *testing.T) {
|
||||||
func TestVipsWatermarkWithImage(t *testing.T) {
|
func TestVipsWatermarkWithImage(t *testing.T) {
|
||||||
image, _, _ := vipsRead(readImage("test.jpg"))
|
image, _, _ := vipsRead(readImage("test.jpg"))
|
||||||
|
|
||||||
watermark := readImage("transparent.png")
|
watermark, _, _ := vipsRead(readImage("transparent.png"))
|
||||||
|
|
||||||
options := WatermarkImage{Left: 100, Top: 100, Opacity: 1.0, Buf: watermark}
|
options := WatermarkImage{Left: 100, Top: 100, Opacity: 1.0}
|
||||||
newImg, err := vipsDrawWatermark(image, options)
|
newImg, err := vipsDrawWatermark(image, watermark, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Cannot add watermark: %s", err)
|
t.Errorf("Cannot add watermark: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue