@@ -81,10 +81,10 @@ type Options struct {
81
81
Format string
82
82
83
83
// Crop rectangle params
84
- CropX int
85
- CropY int
86
- CropWidth int
87
- CropHeight int
84
+ CropX float64
85
+ CropY float64
86
+ CropWidth float64
87
+ CropHeight float64
88
88
}
89
89
90
90
func (o Options ) String () string {
@@ -114,16 +114,16 @@ func (o Options) String() string {
114
114
opts = append (opts , o .Format )
115
115
}
116
116
if o .CropX != 0 {
117
- opts = append (opts , fmt .Sprintf ("%s%d " , string (optCropX ), o .CropX ))
117
+ opts = append (opts , fmt .Sprintf ("%s%v " , string (optCropX ), o .CropX ))
118
118
}
119
119
if o .CropY != 0 {
120
- opts = append (opts , fmt .Sprintf ("%s%d " , string (optCropY ), o .CropY ))
120
+ opts = append (opts , fmt .Sprintf ("%s%v " , string (optCropY ), o .CropY ))
121
121
}
122
122
if o .CropWidth != 0 {
123
- opts = append (opts , fmt .Sprintf ("%s%d " , string (optCropWidth ), o .CropWidth ))
123
+ opts = append (opts , fmt .Sprintf ("%s%v " , string (optCropWidth ), o .CropWidth ))
124
124
}
125
125
if o .CropHeight != 0 {
126
- opts = append (opts , fmt .Sprintf ("%s%d " , string (optCropHeight ), o .CropHeight ))
126
+ opts = append (opts , fmt .Sprintf ("%s%v " , string (optCropHeight ), o .CropHeight ))
127
127
}
128
128
return strings .Join (opts , "," )
129
129
}
@@ -133,7 +133,7 @@ func (o Options) String() string {
133
133
// the presence of other fields (like Fit). A non-empty Format value is
134
134
// assumed to involve a transformation.
135
135
func (o Options ) transform () bool {
136
- return o .Width != 0 || o .Height != 0 || o .Rotate != 0 || o .FlipHorizontal || o .FlipVertical || o .Quality != 0 || o .Format != "" || ( o . CropWidth != 0 && o .CropHeight != 0 )
136
+ return o .Width != 0 || o .Height != 0 || o .Rotate != 0 || o .FlipHorizontal || o .FlipVertical || o .Quality != 0 || o .Format != "" || o . CropX != 0 || o . CropY != 0 || o . CropWidth != 0 || o .CropHeight != 0
137
137
}
138
138
139
139
// ParseOptions parses str as a list of comma separated transformation options.
@@ -144,17 +144,19 @@ func (o Options) transform() bool {
144
144
//
145
145
// There are four options controlling rectangle crop:
146
146
//
147
- // cx{x} - X coordinate of top left rectangle corner
148
- // cy{y} - Y coordinate of top left rectangle corner
149
- // cw{width} - rectangle width
150
- // ch{height} - rectangle height
147
+ // cx{x} - X coordinate of top left rectangle corner (default: 0)
148
+ // cy{y} - Y coordinate of top left rectangle corner (default: 0)
149
+ // cw{width} - rectangle width (default: image width)
150
+ // ch{height} - rectangle height (default: image height)
151
151
//
152
- // ch and cw are required to enable crop and they must be positive integers. If
153
- // the rectangle is larger than the image, crop will not be applied. If the
154
- // rectangle does not fit the image in any of the dimensions, it will be moved
155
- // to produce an image of given size. Crop is applied before any other
156
- // transformations. If the rectangle is smaller than the requested resize and
157
- // scaleUp is disabled, the image will be of the same size as the rectangle.
152
+ // For all options, integer values are interpreted as exact pixel values and
153
+ // floats between 0 and 1 are interpreted as percentages of the original image
154
+ // size. Negative values for cx and cy are measured from the right and bottom
155
+ // edges of the image, respectively.
156
+ //
157
+ // If the crop width or height exceed the width or height of the image, the
158
+ // crop width or height will be adjusted, preserving the specified cx and cy
159
+ // values. Rectangular crop is applied before any other transformations.
158
160
//
159
161
// Size and Cropping
160
162
//
@@ -224,8 +226,8 @@ func (o Options) transform() bool {
224
226
// 100,fv,fh - 100 pixels square, flipped horizontal and vertical
225
227
// 200x,q60 - 200 pixels wide, proportional height, 60% quality
226
228
// 200x,png - 200 pixels wide, converted to PNG format
227
- // cw100,ch200 - crop fragment that starts at (0,0), is 100px wide and 200px tall
228
- // cw100,ch200, cx10,cy20 - crop fragment that start at (10,20) is 100px wide and 200px tall
229
+ // cw100,ch100 - crop image to 100px square, starting at (0,0)
230
+ // cx10,cy20,cw100,ch200 - crop image starting at (10,20) is 100px wide and 200px tall
229
231
func ParseOptions (str string ) Options {
230
232
var options Options
231
233
@@ -253,16 +255,16 @@ func ParseOptions(str string) Options {
253
255
options .Signature = strings .TrimPrefix (opt , optSignaturePrefix )
254
256
case strings .HasPrefix (opt , optCropX ):
255
257
value := strings .TrimPrefix (opt , optCropX )
256
- options .CropX , _ = strconv .Atoi (value )
258
+ options .CropX , _ = strconv .ParseFloat (value , 64 )
257
259
case strings .HasPrefix (opt , optCropY ):
258
260
value := strings .TrimPrefix (opt , optCropY )
259
- options .CropY , _ = strconv .Atoi (value )
261
+ options .CropY , _ = strconv .ParseFloat (value , 64 )
260
262
case strings .HasPrefix (opt , optCropWidth ):
261
263
value := strings .TrimPrefix (opt , optCropWidth )
262
- options .CropWidth , _ = strconv .Atoi (value )
264
+ options .CropWidth , _ = strconv .ParseFloat (value , 64 )
263
265
case strings .HasPrefix (opt , optCropHeight ):
264
266
value := strings .TrimPrefix (opt , optCropHeight )
265
- options .CropHeight , _ = strconv .Atoi (value )
267
+ options .CropHeight , _ = strconv .ParseFloat (value , 64 )
266
268
case strings .Contains (opt , optSizeDelimiter ):
267
269
size := strings .SplitN (opt , optSizeDelimiter , 2 )
268
270
if w := size [0 ]; w != "" {
0 commit comments