Skip to content
This repository was archived by the owner on Oct 8, 2025. It is now read-only.

Commit 53d6308

Browse files
committed
Add optional focalpoint support when cropping
1 parent cc928f2 commit 53d6308

3 files changed

Lines changed: 43 additions & 8 deletions

File tree

halfshell/image.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"net/http"
2828
"os"
2929
"path/filepath"
30+
"strconv"
31+
"strings"
3032
)
3133

3234
// Image contains a byte array of the image data and its MIME type.
@@ -71,6 +73,31 @@ type ImageDimensions struct {
7173
Height uint64
7274
}
7375

76+
// Focalpoint is an x/y pair representing the location of the image subject.
77+
// 0.5/0.5 is the middle.
78+
type Focalpoint struct {
79+
X float64
80+
Y float64
81+
}
82+
83+
// NewFocalpoint splits the given string into a Focalpoint struct. The string
84+
// format should be: "X,Y". For example: "0.1,0.1".
85+
func NewFocalpoint(s string) (fp Focalpoint) {
86+
fp = Focalpoint{0.5, 0.5}
87+
88+
pair := strings.Split(s, ",")
89+
if len(pair) != 2 {
90+
return
91+
}
92+
93+
x, _ := strconv.ParseFloat(pair[0], 64)
94+
y, _ := strconv.ParseFloat(pair[1], 64)
95+
96+
fp.X = x
97+
fp.Y = y
98+
return
99+
}
100+
74101
// AspectRatio returns the image dimension's aspect ratio.
75102
func (d ImageDimensions) AspectRatio() float64 {
76103
return float64(d.Width) / float64(d.Height)

halfshell/image_processor.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type ImageProcessorOptions struct {
4343
CropMode string
4444
BorderRadius uint64
4545
BGColor string
46+
Focalpoint Focalpoint
4647
}
4748

4849
type imageProcessor struct {
@@ -111,7 +112,7 @@ func (ip *imageProcessor) scaleWand(wand *imagick.MagickWand, request *ImageProc
111112
}
112113

113114
if request.CropMode == "fill" {
114-
if err = ip.cropImage(newDimensions, request.Dimensions, wand); err != nil {
115+
if err = ip.cropImage(wand, newDimensions, request.Dimensions, request.Focalpoint); err != nil {
115116
ip.Logger.Warnf("ImageMagick error cropping image: %s", err)
116117
return true, err
117118
}
@@ -295,13 +296,18 @@ func (ip *imageProcessor) clampDimensionsToMaxima(dimensions ImageDimensions, re
295296
return dimensions
296297
}
297298

298-
func (ip *imageProcessor) cropImage(currentDimensions ImageDimensions, requestedDimensions ImageDimensions, wand *imagick.MagickWand) (err error) {
299-
err = wand.CropImage(
300-
uint(requestedDimensions.Width),
301-
uint(requestedDimensions.Height),
302-
int((currentDimensions.Width-requestedDimensions.Width)/2),
303-
int((currentDimensions.Height-requestedDimensions.Height)/2),
304-
)
299+
func (ip *imageProcessor) cropImage(wand *imagick.MagickWand, id ImageDimensions, rd ImageDimensions, fp Focalpoint) (err error) {
300+
xo := fp.X
301+
yo := fp.Y
302+
xc := float64(id.Width)*xo - float64(rd.Width)*xo
303+
yc := float64(id.Height)*yo - float64(rd.Height)*yo
304+
305+
w := uint(rd.Width)
306+
h := uint(rd.Height)
307+
x := int(xc)
308+
y := int(yc)
309+
310+
err = wand.CropImage(w, h, x, y)
305311
return
306312
}
307313

halfshell/route.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ func (p *Route) SourceAndProcessorOptionsForRequest(r *http.Request) (
7272
borderRadius, _ := strconv.ParseUint(r.FormValue("border_radius"), 10, 32)
7373
cropMode := r.FormValue("crop_mode")
7474
bgColor := r.FormValue("bg_color")
75+
focalpoint := r.FormValue("focalpoint")
7576

7677
return &ImageSourceOptions{Path: path}, &ImageProcessorOptions{
7778
Dimensions: ImageDimensions{width, height},
7879
BlurRadius: blurRadius,
7980
BorderRadius: borderRadius,
8081
CropMode: cropMode,
8182
BGColor: bgColor,
83+
Focalpoint: NewFocalpoint(focalpoint),
8284
}
8385
}

0 commit comments

Comments
 (0)