processing_options.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package main
  2. import (
  3. "C"
  4. "encoding/base64"
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "strconv"
  9. "strings"
  10. )
  11. var resizeTypes = map[string]resizeType{
  12. "fit": FIT,
  13. "fill": FILL,
  14. "crop": CROP,
  15. }
  16. type processingOptions struct {
  17. Resize resizeType
  18. Width int
  19. Height int
  20. Gravity gravityType
  21. Enlarge bool
  22. Format imageType
  23. }
  24. func defaultProcessingOptions() processingOptions {
  25. return processingOptions{
  26. Resize: FIT,
  27. Width: 0,
  28. Height: 0,
  29. Gravity: CENTER,
  30. Enlarge: false,
  31. Format: JPEG,
  32. }
  33. }
  34. func decodeUrl(parts []string) (string, imageType, error) {
  35. var imgType imageType = JPEG
  36. urlParts := strings.Split(strings.Join(parts, ""), ".")
  37. if len(urlParts) > 2 {
  38. return "", 0, errors.New("Invalid url encoding")
  39. }
  40. if len(urlParts) == 2 {
  41. if f, ok := imageTypes[urlParts[1]]; ok {
  42. imgType = f
  43. } else {
  44. return "", 0, fmt.Errorf("Invalid image format: %s", urlParts[1])
  45. }
  46. }
  47. url, err := base64.RawURLEncoding.DecodeString(urlParts[0])
  48. if err != nil {
  49. return "", 0, errors.New("Invalid url encoding")
  50. }
  51. return string(url), imgType, nil
  52. }
  53. func applyWidthOption(po *processingOptions, args []string) error {
  54. if len(args) > 1 {
  55. return fmt.Errorf("Invalid width arguments: %v", args)
  56. }
  57. if w, err := strconv.Atoi(args[0]); err == nil || w >= 0 {
  58. po.Width = w
  59. } else {
  60. return fmt.Errorf("Invalid width: %s", args[0])
  61. }
  62. return nil
  63. }
  64. func applyHeightOption(po *processingOptions, args []string) error {
  65. if len(args) > 1 {
  66. return fmt.Errorf("Invalid height arguments: %v", args)
  67. }
  68. if h, err := strconv.Atoi(args[0]); err == nil || po.Height >= 0 {
  69. po.Height = h
  70. } else {
  71. return fmt.Errorf("Invalid height: %s", args[0])
  72. }
  73. return nil
  74. }
  75. func applyEnlargeOption(po *processingOptions, args []string) error {
  76. if len(args) > 1 {
  77. return fmt.Errorf("Invalid enlarge arguments: %v", args)
  78. }
  79. po.Enlarge = args[0] != "0"
  80. return nil
  81. }
  82. func applySizeOption(po *processingOptions, args []string) (err error) {
  83. if len(args) > 3 {
  84. return fmt.Errorf("Invalid size arguments: %v", args)
  85. }
  86. if len(args) >= 1 {
  87. if err = applyWidthOption(po, args[0:1]); err != nil {
  88. return
  89. }
  90. }
  91. if len(args) >= 2 {
  92. if err = applyHeightOption(po, args[1:2]); err != nil {
  93. return
  94. }
  95. }
  96. if len(args) == 3 {
  97. if err = applyEnlargeOption(po, args[2:3]); err != nil {
  98. return
  99. }
  100. }
  101. return nil
  102. }
  103. func applyResizeOption(po *processingOptions, args []string) error {
  104. if len(args) > 4 {
  105. return fmt.Errorf("Invalid resize arguments: %v", args)
  106. }
  107. if r, ok := resizeTypes[args[0]]; ok {
  108. po.Resize = r
  109. } else {
  110. return fmt.Errorf("Invalid resize type: %s", args[0])
  111. }
  112. if len(args) > 1 {
  113. if err := applySizeOption(po, args[1:]); err != nil {
  114. return err
  115. }
  116. }
  117. return nil
  118. }
  119. func applyGravityOption(po *processingOptions, args []string) error {
  120. if len(args) > 1 {
  121. return fmt.Errorf("Invalid resize arguments: %v", args)
  122. }
  123. if g, ok := gravityTypes[args[0]]; ok {
  124. po.Gravity = g
  125. } else {
  126. return fmt.Errorf("Invalid gravity: %s", args[0])
  127. }
  128. return nil
  129. }
  130. func applyFormatOption(po *processingOptions, imgType imageType) error {
  131. if !vipsTypeSupportSave[imgType] {
  132. return errors.New("Resulting image type not supported")
  133. }
  134. po.Format = imgType
  135. return nil
  136. }
  137. func applyProcessingOption(po *processingOptions, name string, args []string) error {
  138. switch name {
  139. case "resize":
  140. if err := applyResizeOption(po, args); err != nil {
  141. return err
  142. }
  143. case "size":
  144. if err := applySizeOption(po, args); err != nil {
  145. return err
  146. }
  147. case "width":
  148. if err := applyWidthOption(po, args); err != nil {
  149. return err
  150. }
  151. case "height":
  152. if err := applyHeightOption(po, args); err != nil {
  153. return err
  154. }
  155. case "enlarge":
  156. if err := applyEnlargeOption(po, args); err != nil {
  157. return err
  158. }
  159. case "gravity":
  160. if err := applyGravityOption(po, args); err != nil {
  161. return err
  162. }
  163. }
  164. return nil
  165. }
  166. func parsePathAdvanced(parts []string) (string, processingOptions, error) {
  167. var urlStart int
  168. po := defaultProcessingOptions()
  169. for i, part := range parts {
  170. args := strings.Split(part, ":")
  171. if len(args) == 1 {
  172. urlStart = i
  173. break
  174. }
  175. if err := applyProcessingOption(&po, args[0], args[1:]); err != nil {
  176. return "", po, err
  177. }
  178. }
  179. url, imgType, err := decodeUrl(parts[urlStart:])
  180. if err != nil {
  181. return "", po, err
  182. }
  183. if err := applyFormatOption(&po, imgType); err != nil {
  184. return "", po, errors.New("Resulting image type not supported")
  185. }
  186. return string(url), po, nil
  187. }
  188. func parsePathSimple(parts []string) (string, processingOptions, error) {
  189. var po processingOptions
  190. var err error
  191. if len(parts) < 6 {
  192. return "", po, errors.New("Invalid path")
  193. }
  194. po.Resize = resizeTypes[parts[0]]
  195. if err = applyWidthOption(&po, parts[1:2]); err != nil {
  196. return "", po, err
  197. }
  198. if err = applyHeightOption(&po, parts[2:3]); err != nil {
  199. return "", po, err
  200. }
  201. if err = applyGravityOption(&po, parts[3:4]); err != nil {
  202. return "", po, err
  203. }
  204. if err = applyEnlargeOption(&po, parts[4:5]); err != nil {
  205. return "", po, err
  206. }
  207. url, imgType, err := decodeUrl(parts[5:])
  208. if err != nil {
  209. return "", po, err
  210. }
  211. if err := applyFormatOption(&po, imgType); err != nil {
  212. return "", po, errors.New("Resulting image type not supported")
  213. }
  214. return string(url), po, nil
  215. }
  216. func parsePath(r *http.Request) (string, processingOptions, error) {
  217. path := r.URL.Path
  218. parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
  219. if len(parts) < 3 {
  220. return "", processingOptions{}, errors.New("Invalid path")
  221. }
  222. // if err := validatePath(parts[0], strings.TrimPrefix(path, fmt.Sprintf("/%s", parts[0]))); err != nil {
  223. // return "", processingOptions{}, err
  224. // }
  225. if _, ok := resizeTypes[parts[1]]; ok {
  226. return parsePathSimple(parts[1:])
  227. } else {
  228. return parsePathAdvanced(parts[1:])
  229. }
  230. }