-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 15d183a
Showing
6 changed files
with
556 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# imgproxyurl | ||
|
||
imgproxyurl is a small library to help you build urls for [imgproxy](https://github.com/imgproxy/imgproxy). | ||
|
||
This is a WIP. | ||
|
||
### Usage | ||
Have a look at an example to understand what's it all about: | ||
```go | ||
url, err := imgproxyurl. | ||
New("/path/to/image.jpg"). | ||
SetKey("e99bd6542067de7dac460558ecada3987dd2d18b066180eaa1c3abc66fb22e463d177ac8f64c93c44d0d78c35adcdda7e0b5f5a116b23ac3d1fa7a305d0727c4"). | ||
SetSalt("a997d51b78d28ba8c05f39b6e634a044b9551352b105f70a4c0fc4c0eca5982719a33527d0253810273bf4d8b747a261cd4898d3e46916cc57d1de8aac132870"). | ||
SetWidth(400). | ||
SetHeight(300). | ||
SetResizingType(imgproxyurl.ResizingTypeFit). | ||
GetAbsolute("http://localhost:8080") | ||
|
||
// url = "http://localhost:8080/a3eK6TO-pMwXvXtakEZjTov3qDrUoDeGL1Xb_1p-Ue4/w:400/h:300/rt:fit/L3BhdGgvdG8vaW1hZ2UuanBn" | ||
``` | ||
|
||
Load key and salt from environment variables `IMGPROXY_KEY` and `IMGPROXY_SALT`: | ||
```go | ||
url, err := imgproxyurl. | ||
NewFromEnvironment("/path/to/image.jpg"). | ||
SetWidth(400). | ||
SetHeight(300). | ||
SetResizingType(imgproxyurl.ResizingTypeFit). | ||
Get() | ||
|
||
// url = "/a3eK6TO-pMwXvXtakEZjTov3qDrUoDeGL1Xb_1p-Ue4/w:400/h:300/rt:fit/L3BhdGgvdG8vaW1hZ2UuanBn" | ||
``` | ||
|
||
### Supported processing options | ||
- [resizing type](https://docs.imgproxy.net/#/generating_the_url_advanced?id=resizing-type) | ||
- [resizing algorithm](https://docs.imgproxy.net/#/generating_the_url_advanced?id=resizing-algorithm) | ||
- [width](https://docs.imgproxy.net/#/generating_the_url_advanced?id=width) | ||
- [height](https://docs.imgproxy.net/#/generating_the_url_advanced?id=height) | ||
- [dpr](https://docs.imgproxy.net/#/generating_the_url_advanced?id=dpr) | ||
- [enlarge](https://docs.imgproxy.net/#/generating_the_url_advanced?id=enlarge) | ||
- [extend](https://docs.imgproxy.net/#/generating_the_url_advanced?id=extend) | ||
- [gravity](https://docs.imgproxy.net/#/generating_the_url_advanced?id=gravity) | ||
- [crop](https://docs.imgproxy.net/#/generating_the_url_advanced?id=crop) | ||
- [padding](https://docs.imgproxy.net/#/generating_the_url_advanced?id=padding) | ||
- [trim](https://docs.imgproxy.net/#/generating_the_url_advanced?id=trim) | ||
- [quality](https://docs.imgproxy.net/#/generating_the_url_advanced?id=quality) | ||
- [max bytes](https://docs.imgproxy.net/#/generating_the_url_advanced?id=max-bytes) | ||
- [background](https://docs.imgproxy.net/#/generating_the_url_advanced?id=background) | ||
- [background alpha](https://docs.imgproxy.net/#/generating_the_url_advanced?id=background-alpha) | ||
|
||
Not all options are supported at the moment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module imgproxyurl | ||
|
||
go 1.15 | ||
|
||
require github.com/pkg/errors v0.9.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,305 @@ | ||
package imgproxyurl | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strconv" | ||
) | ||
|
||
//ResizingType defines how imgproxy will resize the source image. | ||
type ResizingType string | ||
|
||
const ( | ||
//ResizingTypeFit resizes the image while keeping aspect ratio to fit given size | ||
ResizingTypeFit ResizingType = "fit" | ||
//ResizingTypeFill resizes the image while keeping aspect ratio to fill given size and cropping projecting parts | ||
ResizingTypeFill ResizingType = "fill" | ||
//if both source and resulting dimensions have the same orientation (portrait or landscape), imgproxy will use ResizingTypeFill. Otherwise, it will use ResizingTypeFit | ||
ResizingTypeAuto ResizingType = "auto" | ||
) | ||
|
||
// SetResizingType defines how imgproxy will resize the source image | ||
func (url *Url) SetResizingType(resizingType ResizingType) *Url { | ||
url.setOption("rt", string(resizingType)) | ||
return url | ||
} | ||
|
||
// ResizingAlgorithm defines the algorithm that imgproxy will use for resizing | ||
type ResizingAlgorithm string | ||
|
||
const ( | ||
ResizingAlgorithmNearest ResizingAlgorithm = "nearest" | ||
ResizingAlgorithmLinear ResizingAlgorithm = "linear" | ||
ResizingAlgorithmCubic ResizingAlgorithm = "cubic" | ||
ResizingAlgorithmLanczos2 ResizingAlgorithm = "lanczos2" | ||
ResizingAlgorithmLanczos3 ResizingAlgorithm = "lanczos3" | ||
) | ||
|
||
// SetResizingAlgorithm defines the algorithm that imgproxy will use for resizing | ||
func (url *Url) SetResizingAlgorithm(resizingAlgorithm ResizingAlgorithm) *Url { | ||
url.setOption("ra", string(resizingAlgorithm)) | ||
return url | ||
} | ||
|
||
// SetWidth defines the width of the resulting image. | ||
// When set to 0, imgproxy will calculate the resulting width using the defined height and source aspect ratio. | ||
func (url *Url) SetWidth(width int) *Url { | ||
url.setOption("w", strconv.Itoa(width)) | ||
return url | ||
} | ||
|
||
// SetHeight defines the height of the resulting image. | ||
// When set to 0, imgproxy will calculate resulting height using the defined width and source aspect ratio. | ||
func (url *Url) SetHeight(height int) *Url { | ||
url.setOption("h", strconv.Itoa(height)) | ||
return url | ||
} | ||
|
||
// When set, imgproxy will multiply the image dimensions according to this factor for HiDPI (Retina) devices. | ||
// The value must be greater than 0. | ||
func (url *Url) SetDpr(dpr int) *Url { | ||
url.setOption("dpr", strconv.Itoa(dpr)) | ||
return url | ||
} | ||
|
||
// When set, imgproxy will enlarge the image if it is smaller than the given size. | ||
func (url *Url) SetEnlarge(enlarge bool) *Url { | ||
if enlarge { | ||
url.setOption("el", "1") | ||
} else { | ||
url.unsetOption("el") | ||
} | ||
|
||
return url | ||
} | ||
|
||
type GravityType string | ||
|
||
const ( | ||
//GravityTypeDefault lets imgproxy use the default gravity. This is equal to not specifying the gravity on the url | ||
GravityTypeDefault GravityType = "" | ||
GravityTypeNorth GravityType = "no" | ||
GravityTypeSouth GravityType = "so" | ||
GravityTypeEast GravityType = "ea" | ||
GravityTypeWest GravityType = "we" | ||
GravityTypeNorthEast GravityType = "noea" | ||
GravityTypeNorthWest GravityType = "nowe" | ||
GravityTypeSouthEast GravityType = "soea" | ||
GravityTypeSouthWest GravityType = "sowe" | ||
GravityTypeCenter GravityType = "ce" | ||
GravityTypeSmart GravityType = "sm" | ||
GravityTypeFocusPoint GravityType = "fp" | ||
) | ||
|
||
type GravityOffsets interface { | ||
IsGravityOffset() bool | ||
} | ||
|
||
type GravityIntegerOffsets struct { | ||
X int | ||
Y int | ||
} | ||
|
||
func (g GravityIntegerOffsets) IsGravityOffset() bool { | ||
return true | ||
} | ||
|
||
type GravityFloatOffsets struct { | ||
X float64 | ||
Y float64 | ||
} | ||
|
||
func (g GravityFloatOffsets) IsGravityOffset() bool { | ||
return true | ||
} | ||
|
||
func (url *Url) getGravityArguments(gravityType GravityType, offsets GravityOffsets) []string { | ||
if gravityType == GravityTypeDefault { | ||
url.setError(errors.New("specific gravity type is required")) | ||
} | ||
|
||
var gravityOffsetsTypeInteger bool | ||
if offsets != nil { | ||
switch offsets.(type) { | ||
case GravityIntegerOffsets: | ||
gravityOffsetsTypeInteger = true | ||
case GravityFloatOffsets: | ||
gravityOffsetsTypeInteger = false | ||
if offsets.(GravityFloatOffsets).X < 0 || | ||
offsets.(GravityFloatOffsets).X > 1 || | ||
offsets.(GravityFloatOffsets).Y < 0 || | ||
offsets.(GravityFloatOffsets).Y > 1 { | ||
url.setError(errors.New("float offsets must within (0,1) range")) | ||
} | ||
} | ||
} | ||
|
||
arguments := []string{string(gravityType)} | ||
if gravityType == GravityTypeSmart { | ||
if offsets != nil { | ||
url.setError(errors.New("offsets are not applicable for smart gravity")) | ||
} | ||
} else if gravityType == GravityTypeFocusPoint { | ||
if offsets == nil { | ||
url.setError(errors.New("offsets are required for focus point gravity")) | ||
} else if gravityOffsetsTypeInteger { | ||
url.setError(errors.New("focus point gravity requires floating-point offsets")) | ||
} else { | ||
arguments = append(arguments, fmt.Sprintf("%.3f", offsets.(GravityFloatOffsets).X), fmt.Sprintf("%.3f", offsets.(GravityFloatOffsets).Y)) | ||
} | ||
} else { | ||
if offsets != nil && !gravityOffsetsTypeInteger { | ||
url.setError(errors.New("integer offsets are required")) | ||
} else if offsets != nil { | ||
arguments = append(arguments, strconv.Itoa(offsets.(GravityIntegerOffsets).X), strconv.Itoa(offsets.(GravityIntegerOffsets).Y)) | ||
} | ||
} | ||
|
||
return arguments | ||
} | ||
|
||
//When imgproxy needs to cut some parts of the image, it is guided by the gravity. | ||
func (url *Url) SetGravity(gravityType GravityType, offsets GravityOffsets) *Url { | ||
url.setOption("g", url.getGravityArguments(gravityType, offsets)...) | ||
return url | ||
} | ||
|
||
func (url *Url) SetExtendWithGravityOffsets(extend bool, gravityType GravityType, gravityOffsets GravityOffsets) *Url { | ||
if !extend { | ||
url.unsetOption("ex") | ||
} else { | ||
arguments := []string{"1"} | ||
|
||
if gravityType == GravityTypeDefault { | ||
if gravityOffsets != nil { | ||
url.setError(errors.New("offsets are not applicable for default gravity")) | ||
} | ||
} else if gravityType == GravityTypeSmart { | ||
url.setError(errors.New("smart gravity type is not applicable here")) | ||
} else { | ||
arguments = append(arguments, url.getGravityArguments(gravityType, gravityOffsets)...) | ||
} | ||
|
||
url.setOption("ex", arguments...) | ||
} | ||
|
||
return url | ||
} | ||
func (url *Url) SetExtendWithGravity(extend bool, gravityType GravityType) *Url { | ||
return url.SetExtendWithGravityOffsets(extend, gravityType, nil) | ||
} | ||
func (url *Url) SetExtend(extend bool) *Url { | ||
return url.SetExtendWithGravityOffsets(extend, GravityTypeDefault, nil) | ||
} | ||
|
||
func (url *Url) SetCropWithGravityOffsets(width int, height int, gravityType GravityType, gravityOffsets GravityOffsets) *Url { | ||
arguments := []string{strconv.Itoa(width), strconv.Itoa(height)} | ||
|
||
if gravityType == GravityTypeDefault { | ||
if gravityOffsets != nil { | ||
url.setError(errors.New("offsets are not applicable for default gravity")) | ||
} | ||
} else { | ||
arguments = append(arguments, url.getGravityArguments(gravityType, gravityOffsets)...) | ||
} | ||
|
||
url.setOption("c", arguments...) | ||
|
||
return url | ||
} | ||
func (url *Url) SetCropWithGravity(width int, height int, gravityType GravityType) *Url { | ||
return url.SetCropWithGravityOffsets(width, height, gravityType, nil) | ||
} | ||
func (url *Url) SetCrop(width int, height int) *Url { | ||
return url.SetCropWithGravityOffsets(width, height, GravityTypeDefault, nil) | ||
} | ||
|
||
func (url *Url) SetPadding(top int, right int, bottom int, left int) *Url { | ||
url.setOption("pd", strconv.Itoa(top), strconv.Itoa(right), strconv.Itoa(bottom), strconv.Itoa(left)) | ||
return url | ||
} | ||
|
||
func (url *Url) SetPaddingAll(padding int) *Url { | ||
url.setOption("pd", strconv.Itoa(padding)) | ||
return url | ||
} | ||
|
||
type TrimOption interface { | ||
IsTrimOptions() bool | ||
} | ||
type TrimOptionColor struct { | ||
Color string | ||
} | ||
|
||
func (t TrimOptionColor) IsTrimOptions() bool { | ||
return true | ||
} | ||
|
||
type TrimOptionEqualHor struct{} | ||
|
||
func (t TrimOptionEqualHor) IsTrimOptions() bool { | ||
return true | ||
} | ||
|
||
type TrimOptionEqualVer struct{} | ||
|
||
func (t TrimOptionEqualVer) IsTrimOptions() bool { | ||
return true | ||
} | ||
|
||
//SetTrim Removes surrounding background. | ||
func (url *Url) SetTrim(threshold int, options ...TrimOption) *Url { | ||
arguments := []string{strconv.Itoa(threshold), "", "", ""} | ||
|
||
for _, option := range options { | ||
switch option.(type) { | ||
case TrimOptionColor: | ||
arguments[1] = option.(TrimOptionColor).Color | ||
case TrimOptionEqualHor: | ||
arguments[2] = "1" | ||
case TrimOptionEqualVer: | ||
arguments[3] = "1" | ||
} | ||
} | ||
|
||
url.setOption("t", arguments...) | ||
return url | ||
} | ||
|
||
//SetQuality Redefines quality of the resulting image, percentage. | ||
func (url *Url) SetQuality(quality int) *Url { | ||
url.setOption("q", strconv.Itoa(quality)) | ||
return url | ||
} | ||
|
||
//When set, imgproxy automatically degrades the quality of the image until the image is under the specified amount of bytes. | ||
func (url *Url) SetMaxBytes(maxBytes int) *Url { | ||
url.setOption("mb", strconv.Itoa(maxBytes)) | ||
return url | ||
} | ||
|
||
// When set, imgproxy will fill the resulting image background with the specified color. | ||
// red, green and blue are channel values of the background color (0-255). | ||
// Useful when you convert an image with alpha-channel to JPEG. | ||
// | ||
// When not set, disables any background manipulations. | ||
func (url *Url) SetBackgroundRGB(red int, green int, blue int) *Url { | ||
url.setOption("bg", strconv.Itoa(red), strconv.Itoa(green), strconv.Itoa(blue)) | ||
return url | ||
} | ||
|
||
// When set, imgproxy will fill the resulting image background with the specified color. | ||
// color is a hex-coded value of the color.. | ||
// Useful when you convert an image with alpha-channel to JPEG. | ||
// | ||
// When not set, disables any background manipulations. | ||
func (url *Url) SetBackgroundHex(color string) *Url { | ||
url.setOption("bg", color) | ||
return url | ||
} | ||
|
||
//SetBackgroundAlpha adds alpha channel to background. alpha is a positive floating point number between 0 and 1. | ||
func (url *Url) SetBackgroundAlpha(alpha float64) *Url { | ||
url.setOption("bga", fmt.Sprintf("%.3f", alpha)) | ||
return url | ||
} |
Oops, something went wrong.