diff --git a/image.go b/image.go index fa02dd3..2836787 100644 --- a/image.go +++ b/image.go @@ -4,6 +4,11 @@ type Image struct { buffer []byte } +// Creates a new image +func NewImage(buf []byte) *Image { + return &Image{buf} +} + // Resize the image to fixed width and height func (i *Image) Resize(width, height int) ([]byte, error) { options := Options{ @@ -190,8 +195,3 @@ func (i *Image) Size() (ImageSize, error) { func (i *Image) Image() []byte { return i.buffer } - -// Creates a new image -func NewImage(buf []byte) *Image { - return &Image{buf} -} diff --git a/image_test.go b/image_test.go index fb20c62..e396857 100644 --- a/image_test.go +++ b/image_test.go @@ -246,6 +246,19 @@ func TestImageConvert(t *testing.T) { Write("fixtures/test_image_convert_out.png", buf) } +func TestTransparentImageConvert(t *testing.T) { + image := initImage("transparent.png") + options := Options{ + Type: JPEG, + Background: Color{255, 255, 255}, + } + buf, err := image.Process(options) + if err != nil { + t.Errorf("Cannot process the image: %#v", err) + } + Write("fixtures/test_transparent_image_convert_out.jpg", buf) +} + func TestImageMetadata(t *testing.T) { data, err := initImage("test.png").Metadata() if err != nil { diff --git a/options.go b/options.go index 9526914..8dcc2a9 100644 --- a/options.go +++ b/options.go @@ -80,6 +80,10 @@ type Color struct { R, G, B uint8 } +// Shortcut to black RGB color representation +var ColorBlack = Color{0, 0, 0} + +// Text-based watermark configuration type Watermark struct { Width int DPI int @@ -96,6 +100,7 @@ type GaussianBlur struct { MinAmpl float64 } +// Supported image transformation options type Options struct { Height int Width int @@ -117,6 +122,7 @@ type Options struct { NoProfile bool Interlace bool Rotate Angle + Background Color Gravity Gravity Watermark Watermark Type ImageType diff --git a/resize.go b/resize.go index e234841..87600c2 100644 --- a/resize.go +++ b/resize.go @@ -102,6 +102,12 @@ func Resize(buf []byte, o Options) ([]byte, error) { return nil, err } + // Flatten image on a background, if necessary + image, err = imageFlatten(image, imageType, o) + if err != nil { + return nil, err + } + saveOptions := vipsSaveOptions{ Quality: o.Quality, Type: o.Type, @@ -303,6 +309,15 @@ func watermakImage(image *C.VipsImage, w Watermark) (*C.VipsImage, error) { return image, nil } +func imageFlatten(image *C.VipsImage, imageType ImageType, o Options) (*C.VipsImage, error) { + // Only PNG images are supported for now + if imageType != PNG || o.Background == ColorBlack { + return image, nil + } + + return vipsFlattenBackground(image, o.Background) +} + func zoomImage(image *C.VipsImage, zoom int) (*C.VipsImage, error) { if zoom == 0 { return image, nil diff --git a/vips.go b/vips.go index 9fcbc5b..f30eb09 100644 --- a/vips.go +++ b/vips.go @@ -252,6 +252,26 @@ func vipsInterpretation(image *C.VipsImage) Interpretation { return Interpretation(C.vips_image_guess_interpretation_bridge(image)) } +func vipsFlattenBackground(image *C.VipsImage, background Color) (*C.VipsImage, error) { + var outImage *C.VipsImage + + backgroundC := [3]C.double{ + C.double(background.R), + C.double(background.G), + C.double(background.B), + } + + err := C.vips_flatten_background_brigde(image, &outImage, (*C.double)(&backgroundC[0])) + if int(err) != 0 { + return nil, catchVipsError() + } + + C.g_object_unref(C.gpointer(image)) + image = outImage + + return image, nil +} + func vipsPreSave(image *C.VipsImage, o *vipsSaveOptions) (*C.VipsImage, error) { // Remove ICC profile metadata if o.NoProfile { @@ -267,8 +287,8 @@ func vipsPreSave(image *C.VipsImage, o *vipsSaveOptions) (*C.VipsImage, error) { // Apply the proper colour space var outImage *C.VipsImage if vipsColourspaceIsSupported(image) { - err := int(C.vips_colourspace_bridge(image, &outImage, interpretation)) - if err != 0 { + err := C.vips_colourspace_bridge(image, &outImage, interpretation) + if int(err) != 0 { return nil, catchVipsError() } C.g_object_unref(C.gpointer(image)) diff --git a/vips.h b/vips.h index 0a52b39..8685a1c 100644 --- a/vips.h +++ b/vips.h @@ -226,6 +226,15 @@ vips_webpsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int qual ); } +int +vips_flatten_background_brigde(VipsImage *in, VipsImage **out, double background[3]) { + VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3); + return vips_flatten(in, out, + "background", vipsBackground, + NULL + ); +} + int vips_init_image (void *buf, size_t len, int imageType, VipsImage **out) { int code = 1;