Skip to content

Commit

Permalink
Merge pull request #1 from aybabtme/api_work
Browse files Browse the repository at this point in the history
Add docs, more errors, fix tests, add examples.
  • Loading branch information
tobi committed Apr 20, 2014
2 parents fa7ec06 + a33cd86 commit 6383d92
Show file tree
Hide file tree
Showing 17 changed files with 451 additions and 190 deletions.
74 changes: 55 additions & 19 deletions bounds.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,76 @@
package mogrify

import (
"math"
"fmt"
"fmt"
"math"
"regexp"
"strconv"
)

var boundFinder = regexp.MustCompile("([0-9]*)x([0-9]*)")

// Bounds of an image.
type Bounds struct {
Width, Height int
Width, Height int
}

func (b Bounds) String() string {
return fmt.Sprintf("%dx%d", b.Width, b.Height)
// BoundsFromString creates a Bounds from strings of the form:
// "100x150" -> Width 100, Height 150
// "x150" -> Width 0, Height 150
// "100x" -> Width 100, Height 0
// "x" -> Width 0, Height 0
// "no match" -> error
func BoundsFromString(bounds string) (*Bounds, error) {

dimensions := boundFinder.FindStringSubmatch(bounds)
if len(dimensions) != 3 {
return nil, fmt.Errorf("malformed bound string")
}

atoiOrZero := func(str string) int {
if str == "" {
return 0
}
val, _ := strconv.Atoi(str)
return val
}

return &Bounds{
Width: atoiOrZero(dimensions[1]),
Height: atoiOrZero(dimensions[2]),
}, nil
}

// ScaleProportionally the bounds to the smallest side.
func (b Bounds) ScaleProportionally(targetWidth, targetHeight int) Bounds {
scalex := (float64)(targetWidth) / (float64)(b.Width)
scaley := (float64)(targetHeight) / (float64)(b.Height)
scale := math.Min(scalex, scaley)
scalex := float64(targetWidth) / float64(b.Width)
scaley := float64(targetHeight) / float64(b.Height)
scale := math.Min(scalex, scaley)

return Bounds{ (int)(math.Floor((float64)(b.Width) * scale)), (int)(math.Floor((float64)(b.Height) * scale)) }
return Bounds{
Width: int(math.Floor(float64(b.Width) * scale)),
Height: int(math.Floor(float64(b.Height) * scale)),
}
}

// ShrinkProportionally the bounds only if both sides are larger than
// the target.
func (b Bounds) ShrinkProportionally(targetWidth, targetHeight int) Bounds {
// Make sure there is work to be done
if b.Width < targetWidth || b.Height < targetHeight {
return b
}
// Make sure there is work to be done
if b.Width < targetWidth || b.Height < targetHeight {
return b
}

return b.ScaleProportionally(targetWidth, targetHeight)
return b.ScaleProportionally(targetWidth, targetHeight)
}

// GrowProportionally the bounds only if both sides are smaller than
// the target.
func (b Bounds) GrowProportionally(targetWidth, targetHeight int) Bounds {
// Make sure there is work to be done
if b.Width > targetWidth || b.Height > targetHeight {
return b
}
// Make sure there is work to be done
if b.Width > targetWidth || b.Height > targetHeight {
return b
}

return b.ScaleProportionally(targetWidth, targetHeight)
return b.ScaleProportionally(targetWidth, targetHeight)
}
171 changes: 125 additions & 46 deletions bounds_test.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,144 @@
package mogrify

import (
"testing"
"testing"
)


func TestBounds(t *testing.T) {

bounds := Bounds{100, 50}
if bounds.Width != 100 {
t.FailNow()
}
bounds := Bounds{100, 50}
if bounds.Width != 100 {
t.FailNow()
}

if bounds.Height != 50 {
t.FailNow()
}
if bounds.Height != 50 {
t.FailNow()
}

}

func TestProportionalOperation(t *testing.T) {
// half
bounds := Bounds{100, 50}.ScaleProportionally(50, 50)
if bounds.Width != 50 { t.FailNow() }
if bounds.Height != 25 { t.FailNow() }

// no changes
bounds = Bounds{100, 50}.ScaleProportionally(100, 100)
if bounds.Width != 100 { t.FailNow() }
if bounds.Height != 50 { t.FailNow() }

// no changes
bounds = Bounds{100, 50}.ScaleProportionally(100, 100000000)
if bounds.Width != 100 { t.FailNow() }
if bounds.Height != 50 { t.FailNow() }

// scale up
bounds = Bounds{100, 50}.ScaleProportionally(1000, 1000)
if bounds.Width != 1000 { t.FailNow() }
if bounds.Height != 500 { t.FailNow() }
// half
bounds := Bounds{100, 50}.ScaleProportionally(50, 50)
if bounds.Width != 50 {
t.FailNow()
}
if bounds.Height != 25 {
t.FailNow()
}

// no changes
bounds = Bounds{100, 50}.ScaleProportionally(100, 100)
if bounds.Width != 100 {
t.FailNow()
}
if bounds.Height != 50 {
t.FailNow()
}

// no changes
bounds = Bounds{100, 50}.ScaleProportionally(100, 100000000)
if bounds.Width != 100 {
t.FailNow()
}
if bounds.Height != 50 {
t.FailNow()
}

// scale up
bounds = Bounds{100, 50}.ScaleProportionally(1000, 1000)
if bounds.Width != 1000 {
t.FailNow()
}
if bounds.Height != 500 {
t.FailNow()
}
}

func TestShrink(t *testing.T) {
// half
bounds := Bounds{100, 50}.ShrinkProportionally(50, 50)
if bounds.Width != 50 { t.Errorf("Width is wrong: %d", bounds.Width) }
if bounds.Height != 25 { t.Errorf("Height is wrong: %d", bounds.Height) }

// no changes
bounds = Bounds{100, 50}.ShrinkProportionally(100000, 100000)
if bounds.Width != 100 { t.Errorf("Width is wrong: %d", bounds.Width) }
if bounds.Height != 50 { t.Errorf("Height is wrong: %d", bounds.Height) }
// half
bounds := Bounds{100, 50}.ShrinkProportionally(50, 50)
if bounds.Width != 50 {
t.Errorf("Width is wrong: %d", bounds.Width)
}
if bounds.Height != 25 {
t.Errorf("Height is wrong: %d", bounds.Height)
}

// no changes
bounds = Bounds{100, 50}.ShrinkProportionally(100000, 100000)
if bounds.Width != 100 {
t.Errorf("Width is wrong: %d", bounds.Width)
}
if bounds.Height != 50 {
t.Errorf("Height is wrong: %d", bounds.Height)
}
}

func TestGrow(t *testing.T) {
// no changes
bounds := Bounds{100, 50}.GrowProportionally(50, 50)
if bounds.Width != 100 { t.Errorf("Width is wrong: %d", bounds.Width) }
if bounds.Height != 50 { t.Errorf("Height is wrong: %d", bounds.Height) }

// no changes
bounds = Bounds{100, 50}.GrowProportionally(100000, 100000)
if bounds.Width != 100000 { t.Errorf("Width is wrong: %d", bounds.Width) }
if bounds.Height != 50000 { t.Errorf("Height is wrong: %d", bounds.Height) }
// no changes
bounds := Bounds{100, 50}.GrowProportionally(50, 50)
if bounds.Width != 100 {
t.Errorf("Width is wrong: %d", bounds.Width)
}
if bounds.Height != 50 {
t.Errorf("Height is wrong: %d", bounds.Height)
}

// no changes
bounds = Bounds{100, 50}.GrowProportionally(100000, 100000)
if bounds.Width != 100000 {
t.Errorf("Width is wrong: %d", bounds.Width)
}
if bounds.Height != 50000 {
t.Errorf("Height is wrong: %d", bounds.Height)
}
}

var stringTests = []struct {
name string
bounds string
want *Bounds
shouldErr bool
}{
{"Two proper sizes", "100x50", &Bounds{100, 50}, false},
{"Only height", "x50", &Bounds{0, 50}, false},
{"Only width", "100x", &Bounds{100, 0}, false},
{"An invalid bound", "not a bound", nil, true},
}

func TestFromString(t *testing.T) {
for _, tt := range stringTests {
t.Logf("Extracting bounds: %s", tt.name)
bounds, err := BoundsFromString(tt.bounds)

switch {

case tt.shouldErr && err == nil:
t.Error("want an error, got nothing")

case !tt.shouldErr && err != nil:
t.Errorf("want no error, got '%v'", err)

case tt.want == nil && bounds != nil:
t.Errorf("want nil bound, got '%#v'", bounds)

case tt.want != nil && bounds == nil:
t.Errorf("want '%#v', got nothing", tt.want)

}

if tt.shouldErr {
continue // tt.bounds will be nil
}

// not an error case, bounds is not nil
if tt.want.Width != bounds.Width {
t.Errorf("want width %d, got %d", tt.want.Width, bounds.Width)
}

if tt.want.Height != bounds.Height {
t.Errorf("want height %d, got %d", tt.want.Height, bounds.Height)
}
}
}
40 changes: 0 additions & 40 deletions example/resize.go

This file was deleted.

Loading

0 comments on commit 6383d92

Please sign in to comment.