package rest import ( "fmt" "github.com/disintegration/imaging" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" "image" "net/http" "os" "path/filepath" "strconv" "strings" ) //@Service type ImageCacheService struct { BaseBean imageCacheDao *ImageCacheDao userDao *UserDao matterDao *MatterDao } func (this *ImageCacheService) Init() { this.BaseBean.Init() b := core.CONTEXT.GetBean(this.imageCacheDao) if b, ok := b.(*ImageCacheDao); ok { this.imageCacheDao = b } b = core.CONTEXT.GetBean(this.userDao) if b, ok := b.(*UserDao); ok { this.userDao = b } b = core.CONTEXT.GetBean(this.matterDao) if b, ok := b.(*MatterDao); ok { this.matterDao = b } } func (this *ImageCacheService) Detail(uuid string) *ImageCache { imageCache := this.imageCacheDao.CheckByUuid(uuid) return imageCache } // prepare the resize parameters. func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess bool, resizeMode string, resizeWidth int, resizeHeight int) { var err error if request.FormValue("ir") != "" { //mode_w_h if w or h equal means not required. imageResizeStr := request.FormValue("ir") arr := strings.Split(imageResizeStr, "_") if len(arr) != 3 { panic(result.BadRequest("param error. the format is mode_w_h")) } imageResizeM := arr[0] if imageResizeM == "" { imageResizeM = "fit" } else if imageResizeM != "fit" && imageResizeM != "fill" && imageResizeM != "fixed" { panic(result.BadRequest("mode can only be fit/fill/fixed")) } imageResizeWStr := arr[1] var imageResizeW int if imageResizeWStr != "" { imageResizeW, err = strconv.Atoi(imageResizeWStr) this.PanicError(err) if imageResizeW < 0 || imageResizeW > 4096 { panic(result.BadRequest("zoom size cannot exceed 4096")) } } imageResizeHStr := arr[2] var imageResizeH int if imageResizeHStr != "" { imageResizeH, err = strconv.Atoi(imageResizeHStr) this.PanicError(err) if imageResizeH < 0 || imageResizeH > 4096 { panic(result.BadRequest("zoom size cannot exceed 4096")) } } return true, imageResizeM, imageResizeW, imageResizeH } else { return false, "", 0, 0 } } //resize image. func (this *ImageCacheService) ResizeImage(request *http.Request, filePath string) *image.NRGBA { diskFile, err := os.Open(filePath) this.PanicError(err) defer func() { e := diskFile.Close() this.PanicError(e) }() _, imageResizeM, imageResizeW, imageResizeH := this.ResizeParams(request) if imageResizeM == "fit" { //fit mode. if imageResizeW != 0 { //eg. width = 100 height auto in proportion src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, imageResizeW, 0, imaging.Lanczos) } else if imageResizeH != 0 { //eg. height = 100 width auto in proportion src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, 0, imageResizeH, imaging.Lanczos) } else { panic(result.BadRequest("mode fit required width or height")) } } else if imageResizeM == "fill" { //fill mode. specify the width and height if imageResizeW > 0 && imageResizeH > 0 { src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Fill(src, imageResizeW, imageResizeH, imaging.Center, imaging.Lanczos) } else { panic(result.BadRequest("mode fill required width and height")) } } else if imageResizeM == "fixed" { //fixed mode if imageResizeW > 0 && imageResizeH > 0 { src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, imageResizeW, imageResizeH, imaging.Lanczos) } else { panic(result.BadRequest("mode fixed required width and height")) } } else { panic(result.BadRequest("not support mode %s", imageResizeM)) } } //cache an image func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *http.Request, matter *Matter) *ImageCache { //only these image can do. extension := util.GetExtension(matter.Name) formats := map[string]imaging.Format{ ".jpg": imaging.JPEG, ".jpeg": imaging.JPEG, ".png": imaging.PNG, ".tif": imaging.TIFF, ".tiff": imaging.TIFF, ".bmp": imaging.BMP, ".gif": imaging.GIF, } _, imageResizeM, imageResizeW, imageResizeH := this.ResizeParams(request) mode := fmt.Sprintf("%s_%d_%d", imageResizeM, imageResizeW, imageResizeH) format, ok := formats[extension] if !ok { panic(result.BadRequest("not support this kind of image's (%s) resize", extension)) } user := this.userDao.FindByUuid(matter.UserUuid) dstImage := this.ResizeImage(request, matter.AbsolutePath()) cacheImageName := util.GetSimpleFileName(matter.Name) + "_" + mode + extension cacheImageRelativePath := util.GetSimpleFileName(matter.Path) + "_" + mode + extension cacheImageAbsolutePath := GetUserCacheRootDir(user.Username) + util.GetSimpleFileName(matter.Path) + "_" + mode + extension //create directory dir := filepath.Dir(cacheImageAbsolutePath) util.MakeDirAll(dir) fileWriter, err := os.Create(cacheImageAbsolutePath) this.PanicError(err) defer func() { e := fileWriter.Close() this.PanicError(e) }() //store on disk after handle err = imaging.Encode(fileWriter, dstImage, format) this.PanicError(err) fileInfo, err := fileWriter.Stat() this.PanicError(err) imageCache := &ImageCache{ Name: cacheImageName, UserUuid: matter.UserUuid, Username: user.Username, MatterUuid: matter.Uuid, MatterName: matter.Name, Mode: mode, Size: fileInfo.Size(), Path: cacheImageRelativePath, } this.imageCacheDao.Create(imageCache) return imageCache }