forked from MilanMisak/pixlserv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparameters.go
158 lines (138 loc) · 5.04 KB
/
parameters.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"fmt"
"regexp"
"strconv"
"strings"
)
const (
parameterWidth = "w"
parameterHeight = "h"
parameterCropping = "c"
parameterGravity = "g"
parameterFilter = "f"
parameterScale = "s"
// CroppingModeExact crops an image exactly to given dimensions
CroppingModeExact = "e"
// CroppingModeAll crops an image so that all of it is displayed in a frame of at most given dimensions
CroppingModeAll = "a"
// CroppingModePart crops an image so that it fills a frame of given dimensions
CroppingModePart = "p"
// CroppingModeKeepScale crops an image so that it fills a frame of given dimensions, keeps scale
CroppingModeKeepScale = "k"
// CroppingModeWidthThenPart, resizes an image first to the right width and then crops an image so that it fills a frame of given dimensions
CroppingModeWidthThenPart = "w"
GravityNorth = "n"
GravityNorthEast = "ne"
GravityEast = "e"
GravitySouthEast = "se"
GravitySouth = "s"
GravitySouthWest = "sw"
GravityWest = "w"
GravityNorthWest = "nw"
GravityCenter = "c"
FilterGrayScale = "grayscale"
FilterPixelate = "pixel"
FilterGrayPixelate = "graypixel"
DefaultScale = 1
DefaultCroppingMode = CroppingModeExact
DefaultGravity = GravityNorthWest
DefaultFilter = "none"
)
var (
transformationNameRe = regexp.MustCompile("^t_([0-9A-Za-z-]+)$")
)
// Params is a struct of parameters specifying an image transformation
type Params struct {
width, height, scale int
cropping, gravity, filter string
}
// ToString turns parameters into a unique string for each possible assignment of parameters
func (p Params) ToString() string {
// 0 as a value for width or height means that it will be calculated
return fmt.Sprintf("%s_%s,%s_%s,%s_%d,%s_%d,%s_%s,%s_%d", parameterCropping, p.cropping, parameterGravity, p.gravity, parameterHeight, p.height, parameterWidth, p.width, parameterFilter, p.filter, parameterScale, p.scale)
}
// WithScale returns a copy of a Params struct with the scale set to the given value
func (p Params) WithScale(scale int) Params {
return Params{p.width, p.height, scale, p.cropping, p.gravity, p.filter}
}
// Turns a string like "w_400,h_300" and an image path into a Params struct
// The second return value is an error message
// Also validates the parameters to make sure they have valid values
// w = width, h = height
func parseParameters(parametersStr string) (Params, error) {
params := Params{0, 0, DefaultScale, DefaultCroppingMode, DefaultGravity, DefaultFilter}
parts := strings.Split(parametersStr, ",")
for _, part := range parts {
keyAndValue := strings.SplitN(part, "_", 2)
key := keyAndValue[0]
value := keyAndValue[1]
switch key {
case parameterWidth, parameterHeight:
value, err := strconv.Atoi(value)
if err != nil {
return params, fmt.Errorf("could not parse value for parameter: %q", key)
}
if value <= 0 {
return params, fmt.Errorf("value %d must be > 0: %q", value, key)
}
if key == parameterWidth {
params.width = value
} else {
params.height = value
}
case parameterCropping:
value = strings.ToLower(value)
if len(value) > 1 {
return params, fmt.Errorf("value %q must have only 1 character", key)
}
if !isValidCroppingMode(value) {
return params, fmt.Errorf("invalid value for %q", key)
}
params.cropping = value
case parameterGravity:
value = strings.ToLower(value)
if len(value) > 2 {
return params, fmt.Errorf("value %q must have at most 2 characters", key)
}
if !isValidGravity(value) {
return params, fmt.Errorf("invalid value for %q", key)
}
params.gravity = value
case parameterFilter:
value = strings.ToLower(value)
if !isValidFilter(value) {
return params, fmt.Errorf("invalid value for %q", key)
}
params.filter = value
}
}
if params.width == 0 && params.height == 0 {
return params, fmt.Errorf("both width and height can't be 0")
}
return params, nil
}
// Parses transformation name from a parameters string (e.g. photo from t_photo).
// Returns "" if there is no transformation name.
func parseTransformationName(parametersStr string) string {
matches := transformationNameRe.FindStringSubmatch(parametersStr)
if len(matches) == 0 {
return ""
}
return matches[1]
}
func isValidCroppingMode(str string) bool {
return str == CroppingModeExact || str == CroppingModeAll || str == CroppingModePart || str == CroppingModeKeepScale || str == CroppingModeWidthThenPart
}
func isValidGravity(str string) bool {
return str == GravityNorth || str == GravityNorthEast || str == GravityEast || str == GravitySouthEast || str == GravitySouth || str == GravitySouthWest || str == GravityWest || str == GravityNorthWest || str == GravityCenter
}
func isValidFilter(str string) bool {
return str == FilterGrayScale || str == FilterPixelate || str == FilterGrayPixelate
}
func isEasternGravity(str string) bool {
return str == GravityNorthEast || str == GravityEast || str == GravitySouthEast
}
func isSouthernGravity(str string) bool {
return str == GravitySouthWest || str == GravitySouth || str == GravitySouthEast
}