mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-03-17 20:17:48 +02:00
Crop processing oprion; Resize type crop
is deprecated
This commit is contained in:
parent
518607f259
commit
dbad387eef
152
process.go
152
process.go
@ -37,15 +37,6 @@ func extractMeta(img *vipsImage) (int, int, int, bool) {
|
||||
}
|
||||
|
||||
func calcScale(width, height int, po *processingOptions, imgtype imageType) float64 {
|
||||
// If we're going only to crop, we need only to scale down to DPR.
|
||||
// Scaling up while cropping is not optimal on this stage, we'll do it later if needed.
|
||||
if po.Resize == resizeCrop {
|
||||
if po.Dpr < 1 {
|
||||
return po.Dpr
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
var scale float64
|
||||
|
||||
srcW, srcH := float64(width), float64(height)
|
||||
@ -144,14 +135,64 @@ func calcCrop(width, height, cropWidth, cropHeight int, gravity *gravityOptions)
|
||||
return
|
||||
}
|
||||
|
||||
func cropImage(img *vipsImage, cropWidth, cropHeight int, gravity *gravityOptions) error {
|
||||
if cropWidth == 0 && cropHeight == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
imgWidth, imgHeight := img.Width(), img.Height()
|
||||
|
||||
if cropWidth == 0 {
|
||||
cropWidth = imgWidth
|
||||
} else {
|
||||
cropWidth = minInt(cropWidth, imgWidth)
|
||||
}
|
||||
|
||||
if cropHeight == 0 {
|
||||
cropHeight = imgHeight
|
||||
} else {
|
||||
cropHeight = minInt(cropHeight, imgHeight)
|
||||
}
|
||||
|
||||
if cropWidth < imgWidth || cropHeight < imgHeight {
|
||||
if gravity.Type == gravitySmart {
|
||||
if err := img.CopyMemory(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := img.SmartCrop(cropWidth, cropHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
// Applying additional modifications after smart crop causes SIGSEGV on Alpine
|
||||
// so we have to copy memory after it
|
||||
return img.CopyMemory()
|
||||
} else {
|
||||
left, top := calcCrop(imgWidth, imgHeight, cropWidth, cropHeight, gravity)
|
||||
return img.Crop(left, top, cropWidth, cropHeight)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformImage(ctx context.Context, img *vipsImage, data []byte, po *processingOptions, imgtype imageType) error {
|
||||
var err error
|
||||
|
||||
imgWidth, imgHeight, angle, flip := extractMeta(img)
|
||||
srcWidth, srcHeight, angle, flip := extractMeta(img)
|
||||
|
||||
hasAlpha := img.HasAlpha()
|
||||
widthToScale, heightToScale := srcWidth, srcHeight
|
||||
cropWidth, cropHeight := po.Crop.Width, po.Crop.Height
|
||||
|
||||
scale := calcScale(imgWidth, imgHeight, po, imgtype)
|
||||
if cropWidth > 0 {
|
||||
widthToScale = minInt(cropWidth, srcWidth)
|
||||
}
|
||||
if cropHeight > 0 {
|
||||
heightToScale = minInt(cropHeight, srcHeight)
|
||||
}
|
||||
|
||||
scale := calcScale(widthToScale, heightToScale, po, imgtype)
|
||||
|
||||
cropWidth = int(float64(cropWidth) * scale)
|
||||
cropHeight = int(float64(cropHeight) * scale)
|
||||
|
||||
if scale != 1 && data != nil && canScaleOnLoad(imgtype, scale) {
|
||||
if imgtype == imageTypeWEBP || imgtype == imageTypeSVG {
|
||||
@ -168,9 +209,13 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
|
||||
}
|
||||
}
|
||||
|
||||
// Update actual image size ans scale after scale-on-load
|
||||
imgWidth, imgHeight, _, _ = extractMeta(img)
|
||||
scale = calcScale(imgWidth, imgHeight, po, imgtype)
|
||||
// Update scale after scale-on-load
|
||||
newWidth, newHeight, _, _ := extractMeta(img)
|
||||
|
||||
widthToScale = int(float64(widthToScale) * float64(newWidth) / float64(srcWidth))
|
||||
heightToScale = int(float64(heightToScale) * float64(newHeight) / float64(srcHeight))
|
||||
|
||||
scale = calcScale(widthToScale, heightToScale, po, imgtype)
|
||||
}
|
||||
|
||||
if err = img.Rad2Float(); err != nil {
|
||||
@ -189,15 +234,14 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
|
||||
}
|
||||
}
|
||||
|
||||
hasAlpha := img.HasAlpha()
|
||||
|
||||
if scale != 1 {
|
||||
if err = img.Resize(scale, hasAlpha); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update actual image size after resize
|
||||
imgWidth, imgHeight, _, _ = extractMeta(img)
|
||||
|
||||
checkTimeout(ctx)
|
||||
|
||||
if angle != vipsAngleD0 || flip {
|
||||
@ -220,58 +264,41 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
|
||||
|
||||
checkTimeout(ctx)
|
||||
|
||||
cropW, cropH := po.Width, po.Height
|
||||
dprWidth := int(float64(po.Width) * po.Dpr)
|
||||
dprHeight := int(float64(po.Height) * po.Dpr)
|
||||
|
||||
if po.Dpr < 1 || (po.Dpr > 1 && po.Resize != resizeCrop) {
|
||||
cropW = int(float64(cropW) * po.Dpr)
|
||||
cropH = int(float64(cropH) * po.Dpr)
|
||||
cropGravity := po.Crop.Gravity
|
||||
if cropGravity.Type == gravityUnknown {
|
||||
cropGravity = po.Gravity
|
||||
}
|
||||
|
||||
if cropW == 0 {
|
||||
cropW = imgWidth
|
||||
} else {
|
||||
cropW = minInt(cropW, imgWidth)
|
||||
}
|
||||
|
||||
if cropH == 0 {
|
||||
cropH = imgHeight
|
||||
} else {
|
||||
cropH = minInt(cropH, imgHeight)
|
||||
}
|
||||
|
||||
if cropW < imgWidth || cropH < imgHeight {
|
||||
if po.Gravity.Type == gravitySmart {
|
||||
if err = img.CopyMemory(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = img.SmartCrop(cropW, cropH); err != nil {
|
||||
return err
|
||||
}
|
||||
// Applying additional modifications after smart crop causes SIGSEGV on Alpine
|
||||
// so we have to copy memory after it
|
||||
if err = img.CopyMemory(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
left, top := calcCrop(imgWidth, imgHeight, cropW, cropH, &po.Gravity)
|
||||
if err = img.Crop(left, top, cropW, cropH); err != nil {
|
||||
return err
|
||||
}
|
||||
if cropGravity.Type == po.Gravity.Type && cropGravity.Type != gravityFocusPoint {
|
||||
if cropWidth == 0 {
|
||||
cropWidth = dprWidth
|
||||
} else if dprWidth > 0 {
|
||||
cropWidth = minInt(cropWidth, dprWidth)
|
||||
}
|
||||
|
||||
checkTimeout(ctx)
|
||||
}
|
||||
if cropHeight == 0 {
|
||||
cropHeight = dprHeight
|
||||
} else if dprHeight > 0 {
|
||||
cropHeight = minInt(cropHeight, dprHeight)
|
||||
}
|
||||
|
||||
if po.Enlarge && po.Resize == resizeCrop && po.Dpr > 1 {
|
||||
// We didn't enlarge the image before, because is wasn't optimal. Now it's time to do it
|
||||
if err = img.Resize(po.Dpr, hasAlpha); err != nil {
|
||||
if err = cropImage(img, cropWidth, cropHeight, &cropGravity); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = img.CopyMemory(); err != nil {
|
||||
} else {
|
||||
if err = cropImage(img, cropWidth, cropHeight, &cropGravity); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = cropImage(img, dprWidth, dprHeight, &po.Gravity); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
checkTimeout(ctx)
|
||||
|
||||
if convertToLinear {
|
||||
if err = img.FixColourspace(); err != nil {
|
||||
return err
|
||||
@ -444,6 +471,15 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if po.Resize == resizeCrop {
|
||||
logWarning("`crop` resizing type is deprecated and will be removed in future versions. Use `crop` processing option instead")
|
||||
|
||||
po.Crop.Width, po.Crop.Height = po.Width, po.Height
|
||||
|
||||
po.Resize = resizeFit
|
||||
po.Width, po.Height = 0, 0
|
||||
}
|
||||
|
||||
animationSupport := conf.MaxGifFrames > 1 && vipsSupportAnimation(imgtype) && vipsSupportAnimation(po.Format)
|
||||
|
||||
pages := 1
|
||||
|
@ -24,7 +24,8 @@ type processingHeaders struct {
|
||||
type gravityType int
|
||||
|
||||
const (
|
||||
gravityCenter gravityType = iota
|
||||
gravityUnknown gravityType = iota
|
||||
gravityCenter
|
||||
gravityNorth
|
||||
gravityEast
|
||||
gravitySouth
|
||||
@ -79,6 +80,12 @@ const (
|
||||
hexColorShortFormat = "%1x%1x%1x"
|
||||
)
|
||||
|
||||
type cropOptions struct {
|
||||
Width int
|
||||
Height int
|
||||
Gravity gravityOptions
|
||||
}
|
||||
|
||||
type watermarkOptions struct {
|
||||
Enabled bool
|
||||
Opacity float64
|
||||
@ -97,6 +104,7 @@ type processingOptions struct {
|
||||
Gravity gravityOptions
|
||||
Enlarge bool
|
||||
Expand bool
|
||||
Crop cropOptions
|
||||
Format imageType
|
||||
Quality int
|
||||
Flatten bool
|
||||
@ -240,18 +248,52 @@ func decodeURL(parts []string) (string, string, error) {
|
||||
return decodeBase64URL(parts)
|
||||
}
|
||||
|
||||
func parseDimension(d *int, name, arg string) error {
|
||||
if v, err := strconv.Atoi(arg); err == nil && v >= 0 {
|
||||
*d = v
|
||||
} else {
|
||||
return fmt.Errorf("Invalid %s: %s", name, arg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseGravity(g *gravityOptions, args []string) error {
|
||||
if t, ok := gravityTypes[args[0]]; ok {
|
||||
g.Type = t
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity: %s", args[0])
|
||||
}
|
||||
|
||||
if g.Type == gravityFocusPoint {
|
||||
if len(args) != 3 {
|
||||
return fmt.Errorf("Invalid gravity arguments: %v", args)
|
||||
}
|
||||
|
||||
if x, err := strconv.ParseFloat(args[1], 64); err == nil && x >= 0 && x <= 1 {
|
||||
g.X = x
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity X: %s", args[1])
|
||||
}
|
||||
|
||||
if y, err := strconv.ParseFloat(args[2], 64); err == nil && y >= 0 && y <= 1 {
|
||||
g.Y = y
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity Y: %s", args[2])
|
||||
}
|
||||
} else if len(args) > 1 {
|
||||
return fmt.Errorf("Invalid gravity arguments: %v", args)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyWidthOption(po *processingOptions, args []string) error {
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("Invalid width arguments: %v", args)
|
||||
}
|
||||
|
||||
if w, err := strconv.Atoi(args[0]); err == nil && w >= 0 {
|
||||
po.Width = w
|
||||
} else {
|
||||
return fmt.Errorf("Invalid width: %s", args[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
return parseDimension(&po.Width, "width", args[0])
|
||||
}
|
||||
|
||||
func applyHeightOption(po *processingOptions, args []string) error {
|
||||
@ -259,13 +301,7 @@ func applyHeightOption(po *processingOptions, args []string) error {
|
||||
return fmt.Errorf("Invalid height arguments: %v", args)
|
||||
}
|
||||
|
||||
if h, err := strconv.Atoi(args[0]); err == nil && h >= 0 {
|
||||
po.Height = h
|
||||
} else {
|
||||
return fmt.Errorf("Invalid height: %s", args[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
return parseDimension(&po.Height, "height", args[0])
|
||||
}
|
||||
|
||||
func applyEnlargeOption(po *processingOptions, args []string) error {
|
||||
@ -369,30 +405,26 @@ func applyDprOption(po *processingOptions, args []string) error {
|
||||
}
|
||||
|
||||
func applyGravityOption(po *processingOptions, args []string) error {
|
||||
if g, ok := gravityTypes[args[0]]; ok {
|
||||
po.Gravity.Type = g
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity: %s", args[0])
|
||||
return parseGravity(&po.Gravity, args)
|
||||
}
|
||||
|
||||
func applyCropOption(po *processingOptions, args []string) error {
|
||||
if len(args) > 5 {
|
||||
return fmt.Errorf("Invalid crop arguments: %v", args)
|
||||
}
|
||||
|
||||
if po.Gravity.Type == gravityFocusPoint {
|
||||
if len(args) != 3 {
|
||||
return fmt.Errorf("Invalid gravity arguments: %v", args)
|
||||
}
|
||||
if err := parseDimension(&po.Crop.Width, "crop width", args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x, err := strconv.ParseFloat(args[1], 64); err == nil && x >= 0 && x <= 1 {
|
||||
po.Gravity.X = x
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity X: %s", args[1])
|
||||
if len(args) > 1 {
|
||||
if err := parseDimension(&po.Crop.Height, "crop height", args[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if y, err := strconv.ParseFloat(args[2], 64); err == nil && y >= 0 && y <= 1 {
|
||||
po.Gravity.Y = y
|
||||
} else {
|
||||
return fmt.Errorf("Invalid gravity Y: %s", args[2])
|
||||
}
|
||||
} else if len(args) > 1 {
|
||||
return fmt.Errorf("Invalid gravity arguments: %v", args)
|
||||
if len(args) > 2 {
|
||||
return parseGravity(&po.Crop.Gravity, args[2:])
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -625,6 +657,10 @@ func applyProcessingOption(po *processingOptions, name string, args []string) er
|
||||
if err := applyGravityOption(po, args); err != nil {
|
||||
return err
|
||||
}
|
||||
case "crop", "c":
|
||||
if err := applyCropOption(po, args); err != nil {
|
||||
return err
|
||||
}
|
||||
case "quality", "q":
|
||||
if err := applyQualityOption(po, args); err != nil {
|
||||
return err
|
||||
|
Loading…
x
Reference in New Issue
Block a user