-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from aybabtme/api_work
Add docs, more errors, fix tests, add examples.
- Loading branch information
Showing
17 changed files
with
451 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.