agi.image.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package agi
  2. import (
  3. "bytes"
  4. "errors"
  5. "image"
  6. "image/jpeg"
  7. _ "image/jpeg"
  8. "image/png"
  9. _ "image/png"
  10. "io/ioutil"
  11. "log"
  12. "os"
  13. "path/filepath"
  14. "strings"
  15. "github.com/disintegration/imaging"
  16. "github.com/oliamb/cutter"
  17. "github.com/robertkrimen/otto"
  18. user "imuslab.com/arozos/mod/user"
  19. )
  20. /*
  21. AJGI Image Processing Library
  22. This is a library for handling image related functionalities in agi scripts.
  23. */
  24. func (g *Gateway) ImageLibRegister() {
  25. err := g.RegisterLib("imagelib", g.injectImageLibFunctions)
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. }
  30. func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User) {
  31. //Get image dimension, requires filepath (virtual)
  32. vm.Set("_imagelib_getImageDimension", func(call otto.FunctionCall) otto.Value {
  33. imageFileVpath, err := call.Argument(0).ToString()
  34. if err != nil {
  35. g.raiseError(err)
  36. return otto.FalseValue()
  37. }
  38. imagePath, err := virtualPathToRealPath(imageFileVpath, u)
  39. if err != nil {
  40. g.raiseError(err)
  41. return otto.FalseValue()
  42. }
  43. if !fileExists(imagePath) {
  44. g.raiseError(errors.New("File not exists! Given " + imagePath))
  45. return otto.FalseValue()
  46. }
  47. file, err := os.Open(imagePath)
  48. if err != nil {
  49. g.raiseError(err)
  50. return otto.FalseValue()
  51. }
  52. image, _, err := image.DecodeConfig(file)
  53. if err != nil {
  54. g.raiseError(err)
  55. return otto.FalseValue()
  56. }
  57. file.Close()
  58. rawResults := []int{image.Width, image.Height}
  59. result, _ := vm.ToValue(rawResults)
  60. return result
  61. })
  62. //Resize image, require (filepath, outputpath, width, height)
  63. vm.Set("_imagelib_resizeImage", func(call otto.FunctionCall) otto.Value {
  64. vsrc, err := call.Argument(0).ToString()
  65. if err != nil {
  66. g.raiseError(err)
  67. return otto.FalseValue()
  68. }
  69. vdest, err := call.Argument(1).ToString()
  70. if err != nil {
  71. g.raiseError(err)
  72. return otto.FalseValue()
  73. }
  74. width, err := call.Argument(2).ToInteger()
  75. if err != nil {
  76. g.raiseError(err)
  77. return otto.FalseValue()
  78. }
  79. height, err := call.Argument(3).ToInteger()
  80. if err != nil {
  81. g.raiseError(err)
  82. return otto.FalseValue()
  83. }
  84. //Convert the virtual paths to real paths
  85. rsrc, err := virtualPathToRealPath(vsrc, u)
  86. if err != nil {
  87. g.raiseError(err)
  88. return otto.FalseValue()
  89. }
  90. rdest, err := virtualPathToRealPath(vdest, u)
  91. if err != nil {
  92. g.raiseError(err)
  93. return otto.FalseValue()
  94. }
  95. ext := strings.ToLower(filepath.Ext(rdest))
  96. if !inArray([]string{".jpg", ".jpeg", ".png"}, ext) {
  97. g.raiseError(errors.New("File extension not supported. Only support .jpg and .png"))
  98. return otto.FalseValue()
  99. }
  100. if fileExists(rdest) {
  101. err := os.Remove(rdest)
  102. if err != nil {
  103. g.raiseError(err)
  104. return otto.FalseValue()
  105. }
  106. }
  107. //Resize the image
  108. src, err := imaging.Open(rsrc)
  109. if err != nil {
  110. //Opening failed
  111. g.raiseError(err)
  112. return otto.FalseValue()
  113. }
  114. src = imaging.Resize(src, int(width), int(height), imaging.Lanczos)
  115. err = imaging.Save(src, rdest)
  116. if err != nil {
  117. g.raiseError(err)
  118. return otto.FalseValue()
  119. }
  120. return otto.TrueValue()
  121. })
  122. //Crop the given image, require (input, output, posx, posy, width, height)
  123. vm.Set("_imagelib_cropImage", func(call otto.FunctionCall) otto.Value {
  124. vsrc, err := call.Argument(0).ToString()
  125. if err != nil {
  126. g.raiseError(err)
  127. return otto.FalseValue()
  128. }
  129. vdest, err := call.Argument(1).ToString()
  130. if err != nil {
  131. g.raiseError(err)
  132. return otto.FalseValue()
  133. }
  134. posx, err := call.Argument(2).ToInteger()
  135. if err != nil {
  136. posx = 0
  137. }
  138. posy, err := call.Argument(3).ToInteger()
  139. if err != nil {
  140. posy = 0
  141. }
  142. width, err := call.Argument(4).ToInteger()
  143. if err != nil {
  144. g.raiseError(errors.New("Image width not defined"))
  145. return otto.FalseValue()
  146. }
  147. height, err := call.Argument(5).ToInteger()
  148. if err != nil {
  149. g.raiseError(errors.New("Image height not defined"))
  150. return otto.FalseValue()
  151. }
  152. //Convert the virtual paths to realpaths
  153. rsrc, err := virtualPathToRealPath(vsrc, u)
  154. if err != nil {
  155. g.raiseError(err)
  156. return otto.FalseValue()
  157. }
  158. rdest, err := virtualPathToRealPath(vdest, u)
  159. if err != nil {
  160. g.raiseError(err)
  161. return otto.FalseValue()
  162. }
  163. //Try to read the source image
  164. imageBytes, err := ioutil.ReadFile(rsrc)
  165. if err != nil {
  166. g.raiseError(err)
  167. return otto.FalseValue()
  168. }
  169. img, _, err := image.Decode(bytes.NewReader(imageBytes))
  170. if err != nil {
  171. g.raiseError(err)
  172. return otto.FalseValue()
  173. }
  174. //Crop the image
  175. croppedImg, err := cutter.Crop(img, cutter.Config{
  176. Width: int(width),
  177. Height: int(height),
  178. Anchor: image.Point{int(posx), int(posy)},
  179. Mode: cutter.TopLeft,
  180. })
  181. //Create the new image
  182. out, err := os.Create(rdest)
  183. if err != nil {
  184. g.raiseError(err)
  185. return otto.FalseValue()
  186. }
  187. if strings.ToLower(filepath.Ext(rdest)) == ".png" {
  188. png.Encode(out, croppedImg)
  189. } else if strings.ToLower(filepath.Ext(rdest)) == ".jpg" {
  190. jpeg.Encode(out, croppedImg, nil)
  191. } else {
  192. g.raiseError(errors.New("Not supported format: Only support jpg or png"))
  193. return otto.FalseValue()
  194. }
  195. out.Close()
  196. return otto.TrueValue()
  197. })
  198. //Get the given file's thumbnail in base64
  199. vm.Set("_imagelib_loadThumbString", func(call otto.FunctionCall) otto.Value {
  200. vsrc, err := call.Argument(0).ToString()
  201. if err != nil {
  202. g.raiseError(err)
  203. return otto.FalseValue()
  204. }
  205. //Convert the vsrc to real path
  206. rsrc, err := virtualPathToRealPath(vsrc, u)
  207. if err != nil {
  208. g.raiseError(err)
  209. return otto.FalseValue()
  210. }
  211. //Get the files' thumb base64 string
  212. base64String, err := g.Option.FileSystemRender.LoadCache(rsrc, false)
  213. if err != nil {
  214. return otto.FalseValue()
  215. } else {
  216. value, _ := vm.ToValue(base64String)
  217. return value
  218. }
  219. })
  220. //Wrap all the native code function into an imagelib class
  221. vm.Run(`
  222. var imagelib = {};
  223. imagelib.getImageDimension = _imagelib_getImageDimension;
  224. imagelib.resizeImage = _imagelib_resizeImage;
  225. imagelib.cropImage = _imagelib_cropImage;
  226. imagelib.loadThumbString = _imagelib_loadThumbString;
  227. `)
  228. }