agi.image.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. package agi
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "image"
  7. "image/jpeg"
  8. _ "image/jpeg"
  9. "image/png"
  10. _ "image/png"
  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. "imuslab.com/arozos/mod/neuralnet"
  19. user "imuslab.com/arozos/mod/user"
  20. )
  21. /*
  22. AJGI Image Processing Library
  23. This is a library for handling image related functionalities in agi scripts.
  24. */
  25. func (g *Gateway) ImageLibRegister() {
  26. err := g.RegisterLib("imagelib", g.injectImageLibFunctions)
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. }
  31. func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User) {
  32. //Get image dimension, requires filepath (virtual)
  33. vm.Set("_imagelib_getImageDimension", func(call otto.FunctionCall) otto.Value {
  34. imageFileVpath, err := call.Argument(0).ToString()
  35. if err != nil {
  36. g.raiseError(err)
  37. return otto.FalseValue()
  38. }
  39. fsh, imagePath, err := virtualPathToRealPath(imageFileVpath, u)
  40. if err != nil {
  41. g.raiseError(err)
  42. return otto.FalseValue()
  43. }
  44. if !fsh.FileSystemAbstraction.FileExists(imagePath) {
  45. g.raiseError(errors.New("File not exists! Given " + imagePath))
  46. return otto.FalseValue()
  47. }
  48. panic("fix point 1")
  49. file, err := os.Open(imagePath)
  50. if err != nil {
  51. g.raiseError(err)
  52. return otto.FalseValue()
  53. }
  54. image, _, err := image.DecodeConfig(file)
  55. if err != nil {
  56. g.raiseError(err)
  57. return otto.FalseValue()
  58. }
  59. file.Close()
  60. rawResults := []int{image.Width, image.Height}
  61. result, _ := vm.ToValue(rawResults)
  62. return result
  63. })
  64. //Resize image, require (filepath, outputpath, width, height)
  65. vm.Set("_imagelib_resizeImage", func(call otto.FunctionCall) otto.Value {
  66. vsrc, err := call.Argument(0).ToString()
  67. if err != nil {
  68. g.raiseError(err)
  69. return otto.FalseValue()
  70. }
  71. vdest, err := call.Argument(1).ToString()
  72. if err != nil {
  73. g.raiseError(err)
  74. return otto.FalseValue()
  75. }
  76. width, err := call.Argument(2).ToInteger()
  77. if err != nil {
  78. g.raiseError(err)
  79. return otto.FalseValue()
  80. }
  81. height, err := call.Argument(3).ToInteger()
  82. if err != nil {
  83. g.raiseError(err)
  84. return otto.FalseValue()
  85. }
  86. //Convert the virtual paths to real paths
  87. _, rsrc, err := virtualPathToRealPath(vsrc, u)
  88. if err != nil {
  89. g.raiseError(err)
  90. return otto.FalseValue()
  91. }
  92. destfsh, rdest, err := virtualPathToRealPath(vdest, u)
  93. if err != nil {
  94. g.raiseError(err)
  95. return otto.FalseValue()
  96. }
  97. ext := strings.ToLower(filepath.Ext(rdest))
  98. if !inArray([]string{".jpg", ".jpeg", ".png"}, ext) {
  99. g.raiseError(errors.New("File extension not supported. Only support .jpg and .png"))
  100. return otto.FalseValue()
  101. }
  102. if destfsh.FileSystemAbstraction.FileExists(rdest) {
  103. err := destfsh.FileSystemAbstraction.Remove(rdest)
  104. if err != nil {
  105. g.raiseError(err)
  106. return otto.FalseValue()
  107. }
  108. }
  109. //Resize the image
  110. src, err := imaging.Open(rsrc)
  111. if err != nil {
  112. //Opening failed
  113. g.raiseError(err)
  114. return otto.FalseValue()
  115. }
  116. src = imaging.Resize(src, int(width), int(height), imaging.Lanczos)
  117. err = imaging.Save(src, rdest)
  118. if err != nil {
  119. g.raiseError(err)
  120. return otto.FalseValue()
  121. }
  122. return otto.TrueValue()
  123. })
  124. //Crop the given image, require (input, output, posx, posy, width, height)
  125. vm.Set("_imagelib_cropImage", func(call otto.FunctionCall) otto.Value {
  126. vsrc, err := call.Argument(0).ToString()
  127. if err != nil {
  128. g.raiseError(err)
  129. return otto.FalseValue()
  130. }
  131. vdest, err := call.Argument(1).ToString()
  132. if err != nil {
  133. g.raiseError(err)
  134. return otto.FalseValue()
  135. }
  136. posx, err := call.Argument(2).ToInteger()
  137. if err != nil {
  138. posx = 0
  139. }
  140. posy, err := call.Argument(3).ToInteger()
  141. if err != nil {
  142. posy = 0
  143. }
  144. width, err := call.Argument(4).ToInteger()
  145. if err != nil {
  146. g.raiseError(errors.New("Image width not defined"))
  147. return otto.FalseValue()
  148. }
  149. height, err := call.Argument(5).ToInteger()
  150. if err != nil {
  151. g.raiseError(errors.New("Image height not defined"))
  152. return otto.FalseValue()
  153. }
  154. //Convert the virtual paths to realpaths
  155. srcFsh, rsrc, err := virtualPathToRealPath(vsrc, u)
  156. if err != nil {
  157. g.raiseError(err)
  158. return otto.FalseValue()
  159. }
  160. srcFshAbs := srcFsh.FileSystemAbstraction
  161. destFsh, rdest, err := virtualPathToRealPath(vdest, u)
  162. if err != nil {
  163. g.raiseError(err)
  164. return otto.FalseValue()
  165. }
  166. destFshAbs := destFsh.FileSystemAbstraction
  167. fmt.Println("WIP", destFshAbs)
  168. //Try to read the source image
  169. imageBytes, err := srcFshAbs.ReadFile(rsrc)
  170. if err != nil {
  171. g.raiseError(err)
  172. return otto.FalseValue()
  173. }
  174. img, _, err := image.Decode(bytes.NewReader(imageBytes))
  175. if err != nil {
  176. g.raiseError(err)
  177. return otto.FalseValue()
  178. }
  179. //Crop the image
  180. croppedImg, err := cutter.Crop(img, cutter.Config{
  181. Width: int(width),
  182. Height: int(height),
  183. Anchor: image.Point{int(posx), int(posy)},
  184. Mode: cutter.TopLeft,
  185. })
  186. //Create the new image
  187. out, err := os.Create(rdest)
  188. if err != nil {
  189. g.raiseError(err)
  190. return otto.FalseValue()
  191. }
  192. if strings.ToLower(filepath.Ext(rdest)) == ".png" {
  193. png.Encode(out, croppedImg)
  194. } else if strings.ToLower(filepath.Ext(rdest)) == ".jpg" {
  195. jpeg.Encode(out, croppedImg, nil)
  196. } else {
  197. g.raiseError(errors.New("Not supported format: Only support jpg or png"))
  198. return otto.FalseValue()
  199. }
  200. out.Close()
  201. return otto.TrueValue()
  202. })
  203. //Get the given file's thumbnail in base64
  204. vm.Set("_imagelib_loadThumbString", func(call otto.FunctionCall) otto.Value {
  205. vsrc, err := call.Argument(0).ToString()
  206. if err != nil {
  207. g.raiseError(err)
  208. return otto.FalseValue()
  209. }
  210. fsh, err := u.GetFileSystemHandlerFromVirtualPath(vsrc)
  211. if err != nil {
  212. g.raiseError(err)
  213. return otto.FalseValue()
  214. }
  215. rpath, _ := fsh.FileSystemAbstraction.VirtualPathToRealPath(vsrc, u.Username)
  216. //Get the files' thumb base64 string
  217. base64String, err := g.Option.FileSystemRender.LoadCache(fsh, rpath, false)
  218. if err != nil {
  219. return otto.FalseValue()
  220. } else {
  221. value, _ := vm.ToValue(base64String)
  222. return value
  223. }
  224. })
  225. vm.Set("_imagelib_classify", func(call otto.FunctionCall) otto.Value {
  226. vsrc, err := call.Argument(0).ToString()
  227. if err != nil {
  228. g.raiseError(err)
  229. return otto.FalseValue()
  230. }
  231. classifier, err := call.Argument(1).ToString()
  232. if err != nil {
  233. classifier = "default"
  234. }
  235. if classifier == "" || classifier == "undefined" {
  236. classifier = "default"
  237. }
  238. //Convert the vsrc to real path
  239. _, rsrc, err := virtualPathToRealPath(vsrc, u)
  240. if err != nil {
  241. g.raiseError(err)
  242. return otto.FalseValue()
  243. }
  244. if classifier == "default" || classifier == "darknet19" {
  245. //Use darknet19 for classification
  246. r, err := neuralnet.AnalysisPhotoDarknet19(rsrc)
  247. if err != nil {
  248. g.raiseError(err)
  249. return otto.FalseValue()
  250. }
  251. result, err := vm.ToValue(r)
  252. if err != nil {
  253. g.raiseError(err)
  254. return otto.FalseValue()
  255. }
  256. return result
  257. } else if classifier == "yolo3" {
  258. //Use yolo3 for classification, return positions of object as well
  259. r, err := neuralnet.AnalysisPhotoYOLO3(rsrc)
  260. if err != nil {
  261. g.raiseError(err)
  262. return otto.FalseValue()
  263. }
  264. result, err := vm.ToValue(r)
  265. if err != nil {
  266. g.raiseError(err)
  267. return otto.FalseValue()
  268. }
  269. return result
  270. } else {
  271. //Unsupported classifier
  272. log.Println("[AGI] Unsupported image classifier name: " + classifier)
  273. g.raiseError(err)
  274. return otto.FalseValue()
  275. }
  276. })
  277. //Wrap all the native code function into an imagelib class
  278. vm.Run(`
  279. var imagelib = {};
  280. imagelib.getImageDimension = _imagelib_getImageDimension;
  281. imagelib.resizeImage = _imagelib_resizeImage;
  282. imagelib.cropImage = _imagelib_cropImage;
  283. imagelib.loadThumbString = _imagelib_loadThumbString;
  284. imagelib.classify = _imagelib_classify;
  285. `)
  286. }