Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/goatapp/bimg
Copy link
Owner

@h2non h2non Oct 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please update it to github.com/h2non/bimg?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a master -> master PR so I can't change this, I will open a new PR later today using a branch and fix this!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I no longer work here but I can still update this if needed


go 1.17
110 changes: 92 additions & 18 deletions image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,28 +533,102 @@ func TestImageTrim(t *testing.T) {
}

func TestImageTrimParameters(t *testing.T) {
t.Run("When trim parameters include Background", func(t *testing.T) {
if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 6) {
t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.6", VipsVersion)
}

if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 6) {
t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.6", VipsVersion)
}
i := initImage("test.png")
options := Options{
Trim: true,
Background: Color{0.0, 0.0, 0.0},
Threshold: 10.0,
}
buf, err := i.Process(options)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}

i := initImage("test.png")
options := Options{
Trim: true,
Background: Color{0.0, 0.0, 0.0},
Threshold: 10.0,
}
buf, err := i.Process(options)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}
err = assertSize(buf, 400, 257)
if err != nil {
t.Errorf("The image wasn't trimmed. %s", err)
}

err = assertSize(buf, 400, 257)
if err != nil {
t.Errorf("The image wasn't trimmed.")
}
Write("testdata/parameter_trim.png", buf)
})
t.Run("When trim parameters include TrimBackground Transparent PNG", func(t *testing.T) {
if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 6) {
t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.6", VipsVersion)
}

Write("testdata/parameter_trim.png", buf)
i := initImage("transparent.png")
options := Options{
Trim: true,
TrimBackground: Color{0, 0, 0},
Threshold: 10.0,
}
buf, err := i.Process(options)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}

err = assertSize(buf, 247, 206)
if err != nil {
t.Errorf("The image wasn't trimmed. %s", err)
}

Write("testdata/trim_background.png", buf)
})
t.Run("When trim parameters include TrimBackground Background JPEG", func(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("test_1000_yeezy_additional_photo.jpeg")
options := Options{
Trim: true,
TrimBackground: Color{255, 255, 255},
Threshold: 20.0,
}
buf, err := i.Process(options)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}

err = assertSize(buf, 535, 274)
if err != nil {
t.Errorf("The image wasn't trimmed. %s", err)
}

Write("testdata/trimmed_product_additional_photo.jpeg", buf)
})
t.Run("When trim parameters include TrimBackground Background And Padding", func(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("test_1000_yeezy_additional_photo.jpeg")
options := Options{
Trim: true,
TrimBackground: Color{255, 255, 255},
Threshold: 20.0,
TrimPaddingPercent: TrimPaddingPercent{
X: 1,
Y: 1,
},
}
buf, err := i.Process(options)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}

err = assertSize(buf, 545, 288)
if err != nil {
t.Errorf("The image wasn't trimmed. %s", err)
}

Write("testdata/trimmed_product_additional_photo_padded.jpeg", buf)
})
}

func TestImageLength(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ type WatermarkImage struct {
Opacity float32
}

// represents percentage of padding on an image trim extract
type TrimPaddingPercent struct {
X int
Y int
}

// GaussianBlur represents the gaussian image transformation values.
type GaussianBlur struct {
Sigma float64
Expand Down Expand Up @@ -228,6 +234,10 @@ type Options struct {
Palette bool
// Speed defines the AVIF encoders CPU effort. Valid values are 0-8.
Speed int
// color of the background when trimming an alpha based image
TrimBackground Color

TrimPaddingPercent TrimPaddingPercent

// private fields
autoRotateOnly bool
Expand Down
30 changes: 29 additions & 1 deletion resizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,16 @@ func extractOrEmbedImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend, o.Background)
break
case o.Trim:
left, top, width, height, err := vipsTrim(image, o.Background, o.Threshold)
// keeps compatibility with old APIs that only use Background
if o.TrimBackground == ColorBlack {
o.TrimBackground = o.Background
}
left, top, width, height, err := vipsTrim(image, o.TrimBackground, o.Threshold)
if err == nil {
if o.TrimPaddingPercent.X > 0 || o.TrimPaddingPercent.Y > 0 {
left, top, width, height = calculatePadding(left, top, width, height, inWidth, inHeight, o.TrimPaddingPercent)
}

image, err = vipsExtract(image, left, top, width, height)
}
break
Expand Down Expand Up @@ -553,6 +561,26 @@ func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity)
return left, top
}

func calculatePadding(inLeft, inTop, areaWidth, areaHeight, inWidth, inHeight int, trimPaddingPercent TrimPaddingPercent) (int, int, int, int) {
top := inTop
left := inLeft
width := areaWidth
height := areaHeight
if trimPaddingPercent.X > 0 {
paddingPercent := (float64(trimPaddingPercent.X) / 100)
xBorder := math.Round(float64(areaWidth) * paddingPercent)
left = int(math.Max(0, float64(inLeft)-xBorder))
width = int(math.Min(float64(inWidth)-float64(inLeft), float64(areaWidth)+2*xBorder))
}
if trimPaddingPercent.Y > 0 {
paddingPercent := (float64(trimPaddingPercent.Y) / 100)
yBorder := math.Round(float64(inHeight) * paddingPercent)
top = int(math.Max(0, float64(inTop)-yBorder))
height = int(math.Min(float64(inHeight)-float64(inTop), float64(areaHeight)+2*yBorder))
}
return left, top, width, height
}

func calculateRotationAndFlip(image *C.VipsImage, angle Angle) (Angle, bool) {
rotate := D0
flip := false
Expand Down
1 change: 0 additions & 1 deletion vips.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,6 @@ func vipsSmartCrop(image *C.VipsImage, width, height int) (*C.VipsImage, error)
}

func vipsTrim(image *C.VipsImage, background Color, threshold float64) (int, int, int, int, error) {
defer C.g_object_unref(C.gpointer(image))

top := C.int(0)
left := C.int(0)
Expand Down