Merge pull request #192 from greut/trim

Add the Trim operation
master
Tomás Aparicio 8 years ago committed by GitHub
commit 37aea4bd76

@ -35,7 +35,7 @@ If you're using `gopkg.in`, you can still rely in the `v0` without worrying abou
- Resize - Resize
- Enlarge - Enlarge
- Crop (including smart crop support) - Crop (including smart crop support, libvips 8.5+)
- Rotate (with auto-rotate based on EXIF orientation) - Rotate (with auto-rotate based on EXIF orientation)
- Flip (with auto-flip based on EXIF metadata) - Flip (with auto-flip based on EXIF metadata)
- Flop - Flop
@ -47,6 +47,7 @@ If you're using `gopkg.in`, you can still rely in the `v0` without worrying abou
- Custom output color space (RGB, grayscale...) - Custom output color space (RGB, grayscale...)
- Format conversion (with additional quality/compression settings) - Format conversion (with additional quality/compression settings)
- EXIF metadata (size, alpha channel, profile, orientation...) - EXIF metadata (size, alpha channel, profile, orientation...)
- Trim (libvips 8.6+)
## Prerequisites ## Prerequisites

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

@ -178,6 +178,13 @@ func (i *Image) Colourspace(c Interpretation) ([]byte, error) {
return i.Process(options) return i.Process(options)
} }
// Trim removes the background from the picture. It can result in a 0x0 output
// if the image is all background.
func (i *Image) Trim() ([]byte, error) {
options := Options{Trim: true}
return i.Process(options)
}
// Process processes the image based on the given transformation options, // Process processes the image based on the given transformation options,
// talking with libvips bindings accordingly and returning the resultant // talking with libvips bindings accordingly and returning the resultant
// image buffer. // image buffer.

@ -457,8 +457,8 @@ func TestFluentInterface(t *testing.T) {
func TestImageSmartCrop(t *testing.T) { func TestImageSmartCrop(t *testing.T) {
if !(VipsMajorVersion >= 8 && VipsMinorVersion > 4) { if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 5) {
t.Skipf("Skipping this test, libvips doesn't meet version requirement %s > 8.4", VipsVersion) t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.5", VipsVersion)
} }
i := initImage("northern_cardinal_bird.jpg") i := initImage("northern_cardinal_bird.jpg")
@ -475,6 +475,26 @@ func TestImageSmartCrop(t *testing.T) {
Write("fixtures/test_smart_crop.jpg", buf) Write("fixtures/test_smart_crop.jpg", buf)
} }
func TestImageTrim(t *testing.T) {
if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 6) {
t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.6", VipsVersion)
}
i := initImage("transparent.png")
buf, err := i.Trim()
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}
err = assertSize(buf, 250, 208)
if err != nil {
t.Errorf("The image wasn't trimmed.")
}
Write("fixtures/transparent_trim.png", buf)
}
func TestImageLength(t *testing.T) { func TestImageLength(t *testing.T) {
i := initImage("test.jpg") i := initImage("test.jpg")

@ -205,6 +205,7 @@ type Options struct {
NoProfile bool NoProfile bool
Interlace bool Interlace bool
StripMetadata bool StripMetadata bool
Trim bool
Extend Extend Extend Extend
Rotate Angle Rotate Angle
Background Color Background Color

@ -175,7 +175,8 @@ func normalizeOperation(o *Options, inWidth, inHeight int) {
func shouldTransformImage(o Options, inWidth, inHeight int) bool { func shouldTransformImage(o Options, inWidth, inHeight int) bool {
return o.Force || (o.Width > 0 && o.Width != inWidth) || return o.Force || (o.Width > 0 && o.Width != inWidth) ||
(o.Height > 0 && o.Height != inHeight) || o.AreaWidth > 0 || o.AreaHeight > 0 (o.Height > 0 && o.Height != inHeight) || o.AreaWidth > 0 || o.AreaHeight > 0 ||
o.Trim
} }
func shouldApplyEffects(o Options) bool { func shouldApplyEffects(o Options) bool {
@ -268,7 +269,12 @@ func extractOrEmbedImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
left, top := (o.Width-inWidth)/2, (o.Height-inHeight)/2 left, top := (o.Width-inWidth)/2, (o.Height-inHeight)/2
image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend, o.Background) image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend, o.Background)
break break
case o.Trim:
left, top, width, height, err := vipsTrim(image)
if err == nil {
image, err = vipsExtract(image, left, top, width, height)
}
break
case o.Top != 0 || o.Left != 0 || o.AreaWidth != 0 || o.AreaHeight != 0: case o.Top != 0 || o.Left != 0 || o.AreaWidth != 0 || o.AreaHeight != 0:
if o.AreaWidth == 0 { if o.AreaWidth == 0 {
o.AreaHeight = o.Width o.AreaHeight = o.Width

@ -503,6 +503,22 @@ func vipsSmartCrop(image *C.VipsImage, width, height int) (*C.VipsImage, error)
return buf, nil return buf, nil
} }
func vipsTrim(image *C.VipsImage) (int, int, int, int, error) {
defer C.g_object_unref(C.gpointer(image))
top := C.int(0)
left := C.int(0)
width := C.int(0)
height := C.int(0)
err := C.vips_find_trim_bridge(image, &top, &left, &width, &height)
if err != 0 {
return 0, 0, 0, 0, catchVipsError()
}
return int(top), int(left), int(width), int(height), nil
}
func vipsShrinkJpeg(buf []byte, input *C.VipsImage, shrink int) (*C.VipsImage, error) { func vipsShrinkJpeg(buf []byte, input *C.VipsImage, shrink int) (*C.VipsImage, error) {
var image *C.VipsImage var image *C.VipsImage
var ptr = unsafe.Pointer(&buf[0]) var ptr = unsafe.Pointer(&buf[0])

@ -539,3 +539,11 @@ vips_smartcrop_bridge(VipsImage *in, VipsImage **out, int width, int height) {
return 0; return 0;
#endif #endif
} }
int vips_find_trim_bridge(VipsImage *in, int *top, int *left, int *width, int *height) {
#if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 6)
return vips_find_trim(in, top, left, width, height, NULL);
#else
return 0;
#endif
}

Loading…
Cancel
Save