diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a6ac45..e3acb4e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added - (pro) Add `video_meta` to the `/info` response. +- Add [zoom](https://docs.imgproxy.net/generating_the_url?id=zoom) processing option. - Add 1/2/4-bit BMP support. ### Change diff --git a/docs/generating_the_url.md b/docs/generating_the_url.md index c50faef8..73028805 100644 --- a/docs/generating_the_url.md +++ b/docs/generating_the_url.md @@ -121,6 +121,24 @@ Defines the minimum height of the resulting image. Default: `0` +### Zoom + +``` +zoom:%zoom_x_y +z:%zoom_x_y + +zoom:%zoom_x %zoom_y +z:%zoom_x %zoom_y +``` + +When set, imgproxy will multiply the image dimensions according to these factors. The values must be greater than 0. + +Can be combined with `width` and `height` options. In this case, imgproxy calculates scale factors for the provided size and then multiplies it with the provided zoom factors. + +**📝Note:** Unlike [dpr](#dpr), `zoom` doesn't set `Content-DPR` header in the response. + +Default: `1` + ### Dpr ``` @@ -129,6 +147,8 @@ dpr:%dpr When set, imgproxy will multiply the image dimensions according to this factor for HiDPI (Retina) devices. The value must be greater than 0. +**📝Note:** `dpr` also sets `Content-DPR` header in the response so the browser can render the image correctly. + Default: `1` ### Enlarge diff --git a/options/processing_options.go b/options/processing_options.go index c85c63ea..3a29a997 100644 --- a/options/processing_options.go +++ b/options/processing_options.go @@ -65,6 +65,8 @@ type ProcessingOptions struct { Height int MinWidth int MinHeight int + ZoomWidth float64 + ZoomHeight float64 Dpr float64 Gravity GravityOptions Enlarge bool @@ -115,6 +117,8 @@ func NewProcessingOptions() *ProcessingOptions { ResizingType: ResizeFit, Width: 0, Height: 0, + ZoomWidth: 1, + ZoomHeight: 1, Gravity: GravityOptions{Type: GravityCenter}, Enlarge: false, Extend: ExtendOptions{Enabled: false, Gravity: GravityOptions{Type: GravityCenter}}, @@ -375,6 +379,31 @@ func applyResizeOption(po *ProcessingOptions, args []string) error { return nil } +func applyZoomOption(po *ProcessingOptions, args []string) error { + nArgs := len(args) + + if nArgs > 2 { + return fmt.Errorf("Invalid zoom arguments: %v", args) + } + + if z, err := strconv.ParseFloat(args[0], 64); err == nil && z > 0 { + po.ZoomWidth = z + po.ZoomHeight = z + } else { + return fmt.Errorf("Invalid zoom value: %s", args[0]) + } + + if nArgs > 1 { + if z, err := strconv.ParseFloat(args[1], 64); err == nil && z > 0 { + po.ZoomHeight = z + } else { + return fmt.Errorf("Invalid zoom value: %s", args[0]) + } + } + + return nil +} + func applyDprOption(po *ProcessingOptions, args []string) error { if len(args) > 1 { return fmt.Errorf("Invalid dpr arguments: %v", args) @@ -822,6 +851,8 @@ func applyURLOption(po *ProcessingOptions, name string, args []string) error { return applyMinWidthOption(po, args) case "min-height", "mh": return applyMinHeightOption(po, args) + case "zoom", "z": + return applyZoomOption(po, args) case "dpr": return applyDprOption(po, args) case "enlarge", "el": diff --git a/processing/crop.go b/processing/crop.go index ad020e18..f983f567 100644 --- a/processing/crop.go +++ b/processing/crop.go @@ -53,8 +53,7 @@ func crop(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, func cropToResult(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error { // Crop image to the result size - resultWidth := imath.Scale(po.Width, po.Dpr) - resultHeight := imath.Scale(po.Height, po.Dpr) + resultWidth, resultHeight := resultSize(po) if po.ResizingType == options.ResizeFillDown { if resultWidth > img.Width() { diff --git a/processing/extend.go b/processing/extend.go index b80aff9f..d357515d 100644 --- a/processing/extend.go +++ b/processing/extend.go @@ -2,14 +2,12 @@ package processing import ( "github.com/imgproxy/imgproxy/v3/imagedata" - "github.com/imgproxy/imgproxy/v3/imath" "github.com/imgproxy/imgproxy/v3/options" "github.com/imgproxy/imgproxy/v3/vips" ) func extend(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error { - resultWidth := imath.Scale(po.Width, po.Dpr) - resultHeight := imath.Scale(po.Height, po.Dpr) + resultWidth, resultHeight := resultSize(po) if !po.Extend.Enabled || (resultWidth <= img.Width() && resultHeight <= img.Height()) { return nil diff --git a/processing/prepare.go b/processing/prepare.go index f896b669..c3232794 100644 --- a/processing/prepare.go +++ b/processing/prepare.go @@ -98,6 +98,9 @@ func calcScale(width, height int, po *options.ProcessingOptions, imgtype imagety } } + wshrink /= po.ZoomWidth + hshrink /= po.ZoomHeight + if !po.Enlarge && imgtype != imagetype.SVG { if wshrink < 1 { hshrink /= wshrink diff --git a/processing/result_size.go b/processing/result_size.go new file mode 100644 index 00000000..e679e749 --- /dev/null +++ b/processing/result_size.go @@ -0,0 +1,13 @@ +package processing + +import ( + "github.com/imgproxy/imgproxy/v3/imath" + "github.com/imgproxy/imgproxy/v3/options" +) + +func resultSize(po *options.ProcessingOptions) (int, int) { + resultWidth := imath.Scale(po.Width, po.Dpr*po.ZoomWidth) + resultHeight := imath.Scale(po.Height, po.Dpr*po.ZoomHeight) + + return resultWidth, resultHeight +}