From 667e7eac9639c9c39b63af4cb460c01cdf83f167 Mon Sep 17 00:00:00 2001 From: Artem Nezvigin Date: Thu, 13 Nov 2014 15:57:23 -0800 Subject: [PATCH 1/3] Add crop focalpoint support --- halfshell/image.go | 21 +++++++++++++++++++++ halfshell/image_processor.go | 19 ++++++++----------- halfshell/route.go | 2 ++ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/halfshell/image.go b/halfshell/image.go index eb86c55..da2f096 100644 --- a/halfshell/image.go +++ b/halfshell/image.go @@ -25,6 +25,7 @@ import ( "io" "io/ioutil" "os" + "strconv" "strings" "github.com/rafikk/imagick/imagick" @@ -109,3 +110,23 @@ type ResizeDimensions struct { Scale ImageDimensions Crop ImageDimensions } + +// Focalpoint is a float pair representing the location of the image subject. +// (0.5, 0.5) is the middle. (1, 1) is the bottom right. (0, 0) is the top left. +type Focalpoint struct { + X float64 + Y float64 +} + +// NewFocalpointFromString splits the given string into a Focalpoint struct. The +// string format should be: "X,Y". For example: "0.1,0.1". +func NewFocalpointFromString(s string) (fp Focalpoint) { + pair := strings.Split(s, ",") + if len(pair) != 2 { + return Focalpoint{0.5, 0.5} + } + + x, _ := strconv.ParseFloat(pair[0], 64) + y, _ := strconv.ParseFloat(pair[1], 64) + return Focalpoint{x, y} +} diff --git a/halfshell/image_processor.go b/halfshell/image_processor.go index 42170ad..c5b87f4 100644 --- a/halfshell/image_processor.go +++ b/halfshell/image_processor.go @@ -48,6 +48,7 @@ type ImageProcessorOptions struct { Dimensions ImageDimensions BlurRadius float64 ScaleMode uint + Focalpoint Focalpoint } type imageProcessor struct { @@ -153,7 +154,7 @@ func (ip *imageProcessor) resize(img *Image, req *ImageProcessorOptions) error { } if resize.Crop != EmptyImageDimensions { - err = ip.cropApply(img, resize.Crop) + err = ip.cropApply(img, resize.Crop, req.Focalpoint) if err != nil { return err } @@ -292,17 +293,13 @@ func (ip *imageProcessor) resizeApply(img *Image, dimensions ImageDimensions) er return nil } -func (ip *imageProcessor) cropApply(img *Image, reqDimensions ImageDimensions) error { - if reqDimensions == EmptyImageDimensions { - return nil - } +func (ip *imageProcessor) cropApply(img *Image, reqDimensions ImageDimensions, focalpoint Focalpoint) error { oldDimensions := img.GetDimensions() - return img.Wand.CropImage( - reqDimensions.Width, - reqDimensions.Height, - int((oldDimensions.Width-reqDimensions.Width)/2), - int((oldDimensions.Height-reqDimensions.Height)/2), - ) + x := int(float64(oldDimensions.Width)*focalpoint.X - float64(reqDimensions.Width)*focalpoint.X) + y := int(float64(oldDimensions.Height)*focalpoint.Y - float64(reqDimensions.Height)*focalpoint.Y) + w := reqDimensions.Width + h := reqDimensions.Height + return img.Wand.CropImage(w, h, x, y) } func (ip *imageProcessor) blur(image *Image, request *ImageProcessorOptions) error { diff --git a/halfshell/route.go b/halfshell/route.go index c54ed60..12a529d 100644 --- a/halfshell/route.go +++ b/halfshell/route.go @@ -69,6 +69,7 @@ func (p *Route) SourceAndProcessorOptionsForRequest(r *http.Request) ( width, _ := strconv.ParseUint(r.FormValue("w"), 10, 32) height, _ := strconv.ParseUint(r.FormValue("h"), 10, 32) blurRadius, _ := strconv.ParseFloat(r.FormValue("blur"), 64) + focalpoint := r.FormValue("focalpoint") scaleModeName := r.FormValue("scale_mode") scaleMode, _ := ScaleModes[scaleModeName] @@ -77,5 +78,6 @@ func (p *Route) SourceAndProcessorOptionsForRequest(r *http.Request) ( Dimensions: ImageDimensions{uint(width), uint(height)}, BlurRadius: blurRadius, ScaleMode: uint(scaleMode), + Focalpoint: NewFocalpointFromString(focalpoint), } } From 53c35e3a4f498bfeb73a4fc533991dca7f0d2ee0 Mon Sep 17 00:00:00 2001 From: Artem Nezvigin Date: Sat, 6 Dec 2014 10:38:29 -0800 Subject: [PATCH 2/3] Clearer focalpoint X/Y calculation --- halfshell/image_processor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halfshell/image_processor.go b/halfshell/image_processor.go index c5b87f4..8e53895 100644 --- a/halfshell/image_processor.go +++ b/halfshell/image_processor.go @@ -295,8 +295,8 @@ func (ip *imageProcessor) resizeApply(img *Image, dimensions ImageDimensions) er func (ip *imageProcessor) cropApply(img *Image, reqDimensions ImageDimensions, focalpoint Focalpoint) error { oldDimensions := img.GetDimensions() - x := int(float64(oldDimensions.Width)*focalpoint.X - float64(reqDimensions.Width)*focalpoint.X) - y := int(float64(oldDimensions.Height)*focalpoint.Y - float64(reqDimensions.Height)*focalpoint.Y) + x := int(focalpoint.X * (float64(oldDimensions.Width) - float64(reqDimensions.Width))) + y := int(focalpoint.Y * (float64(oldDimensions.Height) - float64(reqDimensions.Height))) w := reqDimensions.Width h := reqDimensions.Height return img.Wand.CropImage(w, h, x, y) From 7b9b1c07cd3f0bec02f04f0df8c0888f35150041 Mon Sep 17 00:00:00 2001 From: Artem Nezvigin Date: Sat, 6 Dec 2014 10:42:58 -0800 Subject: [PATCH 3/3] Better handling of default focalpoint --- halfshell/image.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/halfshell/image.go b/halfshell/image.go index da2f096..8b69100 100644 --- a/halfshell/image.go +++ b/halfshell/image.go @@ -33,6 +33,7 @@ import ( var EmptyImageDimensions = ImageDimensions{} var EmptyResizeDimensions = ResizeDimensions{} +var DefaultFocalPoint = Focalpoint{0.5, 0.5} type Image struct { Wand *imagick.MagickWand @@ -123,10 +124,18 @@ type Focalpoint struct { func NewFocalpointFromString(s string) (fp Focalpoint) { pair := strings.Split(s, ",") if len(pair) != 2 { - return Focalpoint{0.5, 0.5} + return DefaultFocalPoint + } + + x, err := strconv.ParseFloat(pair[0], 64) + if err != nil { + return DefaultFocalPoint + } + + y, err := strconv.ParseFloat(pair[1], 64) + if err != nil { + return DefaultFocalPoint } - x, _ := strconv.ParseFloat(pair[0], 64) - y, _ := strconv.ParseFloat(pair[1], 64) return Focalpoint{x, y} }