// Resize given image file & write it to io.Writer func resize(w io.Writer, r io.Reader, size []int) error { img, mimetype, err := image.Decode(r) if size == nil || err != nil { io.Copy(w, r) return nil } ib := img.Bounds() size = fitToActualSize(&img, size) x := size[0] y := size[1] // set optimal thumbnail size wrat := float64(x) / float64(ib.Dx()) hrat := float64(y) / float64(ib.Dy()) if wrat <= hrat { y = int(wrat * float64(ib.Dy())) } else { x = int(hrat * float64(ib.Dx())) } dst := image.NewRGBA(image.Rect(0, 0, x, y)) graphics.Thumbnail(dst, img) return writeByMimetype(w, dst, mimetype) }
func (c Creature) CropImage(width, height, max int, ctx appengine.Context) (image.Image, error) { url, _ := aeimg.ServingURL(ctx, c.BlobKey, &aeimg.ServingURLOptions{Size: max, Crop: true}) client := urlfetch.Client(ctx) resp, _ := client.Get(url.String()) // Just in case if resp.StatusCode != 200 { return nil, errors.New("Blob not found") } // Do we need further cropping? if width == height { return jpeg.Decode(resp.Body) } src, err := jpeg.Decode(resp.Body) dest := image.NewRGBA(image.Rect(0, 0, width, height)) if err != nil { return nil, err } graphics.Thumbnail(dest, src) return dest, nil }
// Crop given image file & write it to io.Writer func crop(w io.Writer, r io.Reader, size []int) error { img, mimetype, err := image.Decode(r) if size == nil || err != nil { io.Copy(w, r) return nil } size = setMaxSize(fitToActualSize(&img, size)) dst := image.NewRGBA(image.Rect(0, 0, size[0], size[1])) graphics.Thumbnail(dst, img) return writeByMimetype(w, dst, mimetype) }
func (processor LocalImageProcessor) Process(src multipart.File, contentType string) (string, error) { filename := generateRandomFilename(contentType) if err := os.MkdirAll(settings.UploadsDir, 0777); err != nil && !os.IsExist(err) { return filename, err } if err := os.MkdirAll(settings.ThumbnailsDir, 0777); err != nil && !os.IsExist(err) { return filename, err } // make thumbnail var ( img image.Image err error ) if contentType == "image/png" { img, err = png.Decode(src) } else { img, err = jpeg.Decode(src) } if err != nil { return filename, err } thumb := image.NewRGBA(image.Rect(0, 0, 300, 300)) graphics.Thumbnail(thumb, img) dst, err := os.Create(path.Join(settings.ThumbnailsDir, filename)) if err != nil { return filename, err } defer dst.Close() if contentType == "image/png" { png.Encode(dst, thumb) } else if contentType == "image/jpeg" { jpeg.Encode(dst, thumb, nil) } src.Seek(0, 0) dst, err = os.Create(path.Join(settings.UploadsDir, filename)) if err != nil { return filename, err } defer dst.Close() _, err = io.Copy(dst, src) if err != nil { return filename, err } return filename, nil }
func GetImages(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/images/" { ListFolder() jsonData, err := json.MarshalIndent(files, "", " ") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") if len(files) == 0 { w.Write([]byte("[]")) } else { w.Write(jsonData) } } else { filename := filepath.FromSlash(r.URL.Path[1:]) absFilename, err := filepath.Abs(filename) if err != nil { fmt.Printf("Error: %s\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } wd, _ := os.Getwd() if !strings.HasPrefix(absFilename, wd) { w.WriteHeader(http.StatusBadRequest) return } if r.Method == "GET" { width, err1 := strconv.Atoi(r.URL.Query().Get("width")) height, err2 := strconv.Atoi(r.URL.Query().Get("height")) var x, y int if x, err = strconv.Atoi(r.URL.Query().Get("x")); err != nil { x = -1 } if y, err = strconv.Atoi(r.URL.Query().Get("y")); err != nil { y = -1 } if err1 == nil && err2 == nil && width > 0 && height > 0 { ext := filepath.Ext(filename) resizedFilename := strings.TrimRight(filepath.Base(filename), ext) resizedFilename += "_" + strconv.Itoa(width) resizedFilename += "_" + strconv.Itoa(height) resizedFilename += "_" + strconv.Itoa(x) resizedFilename += "_" + strconv.Itoa(y) resizedFilename += ext resizedFilename = filepath.Join(*cache, resizedFilename) if _, err := os.Stat(resizedFilename); os.IsNotExist(err) { fSrc, err := os.Open(filename) if err != nil { fmt.Printf("Error: %s\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer fSrc.Close() src, _, err := image.Decode(fSrc) if err != nil { fmt.Printf("Error: %s\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } if !(src.Bounds().Max.X == width && src.Bounds().Max.Y == height) || x > -1 || y > -1 { var dst draw.Image if x > -1 || y > -1 { if x < 0 { x = 0 } if y < 0 { y = 0 } dst = image.NewRGBA(image.Rect(0, 0, src.Bounds().Max.X-x, src.Bounds().Max.Y-y)) draw.Draw(dst, dst.Bounds(), src, image.Point{x, y}, draw.Src) } else { dst = image.NewRGBA(image.Rect(0, 0, width, height)) graphics.Thumbnail(dst, src) } fDst, err := os.Create(resizedFilename) if err != nil { fmt.Printf("Error: %s\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer fDst.Close() if ext == ".png" { png.Encode(fDst, dst) } else { jpeg.Encode(fDst, dst, &jpeg.Options{95}) } filename = resizedFilename } } else { filename = resizedFilename } } http.ServeFile(w, r, filename) fmt.Printf("Serving image %s\n", filename) } else if r.Method == "DELETE" { if err := os.Remove(filename); err != nil { fmt.Printf("Error: %s\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } removeCached(filename) fmt.Printf("Removed %s\n", filename) w.WriteHeader(http.StatusNoContent) } } }
// 根据需求实时获取缩略图片 // way string 缩略图生成方式: // 'auto': 原图全显优先,获取width或height最大,原图不会被截断 // 'full': 图片填充优先,将widthd和height,按照比例全部填充, 原图将会被截断 // func Thumb(way string, width uint, height uint, picturePath string) (*os.File, error) { /* 获取配置文件中上传根路径 */ revel.Config.SetSection(revel.RunMode) uploadRoot, _ := revel.Config.String("uploadpath") ext := filepath.Ext(picturePath) /* 检测是否是获取一个远端url图片的缩率图 */ picUrl, err := url.ParseRequestURI(picturePath) isRemotePic := false //if err == nil && picUrl.Scheme == "http" && (picUrl.Host == "img.show.wepiao.com" || picUrl.Host == "img.wxmovie.com" || picUrl.Host == "static.show.wepiao.com" || picUrl.Host == "static.task.18.tl:86") { if err == nil && picUrl.Scheme == "http" { isRemotePic = true uploadRoot += "/upload" savePath, saveName := HelperForFilePathCreator(uploadRoot, picturePath, false) picturePath = savePath + "/" + saveName + ext } if way != "full" { way = "auto" } fname := uploadRoot + "/" + picturePath thumbFile := fmt.Sprintf("%s_%s_%v_%v%v", fname, way, width, height, ext) /* 检查有没有现成的缩略图 */ _, err = os.Stat(thumbFile) if err == nil { // 如果有,直接读出 thumb, _ := os.Open(thumbFile) return thumb, nil } // fmt.Printf("没有现成缩率图\n") /* 没有现成的缩略图,需要实施生成, 查找原图片文件是否存在 */ finfo, err := os.Stat(fname) if err != nil { // 如果是获取远端图片,那就先获取. if isRemotePic { // fmt.Printf("是远端图片\n") client := http.Client{} reqImg, err := client.Get(picUrl.Scheme + "://" + picUrl.Host + picUrl.Path) defer reqImg.Body.Close() if err != nil { return nil, err } //如果是4开头的错误状态 则生成默认图片 if '4' == reqImg.Status[0] { fname = "/opt/www/static/pc/img/logo.png" way = "auto" } else { out, err := os.Create(fname) if err != nil { return nil, err } defer out.Close() io.Copy(out, reqImg.Body) } finfo, err = os.Stat(fname) // fmt.Printf("存储远端图片到: %#v\n", fname) } else if os.IsNotExist(err) || err.(*os.PathError).Err == syscall.ENOTDIR { return nil, errors.New("20108") } else { return nil, err } } if finfo.Mode().IsDir() { return nil, errors.New("10016") } file, err := os.Open(fname) if err != nil { if os.IsNotExist(err) { return nil, errors.New("20108") } return nil, err } defer file.Close() /* 生成缩略图 */ var img image.Image img, _, err = image.Decode(file) if err != nil { return nil, err } // 产生缩略图,等比例缩放 out, errF := os.Create(thumbFile) if errF != nil { return nil, errors.New("20108") } defer out.Close() var m image.Image // fmt.Printf("生成缩率图\n") origBounds := img.Bounds() origWidth := uint(origBounds.Dx()) origHeight := uint(origBounds.Dy()) if way == "full" { dst := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) graphics.Thumbnail(dst, img) m = dst } else if width >= origWidth && height >= origHeight { bg := imaging.New(int(width), int(height), color.NRGBA{255, 255, 255, 255}) m = imaging.PasteCenter(bg, img) } else { m = resize.Thumbnail(width, height, img, resize.Lanczos3) } /* 生成文件 */ err = jpeg.Encode(out, m, &jpeg.Options{90}) if err != nil { err = png.Encode(out, m) } if err != nil { err = gif.Encode(out, m, nil) } if err != nil { return nil, err } /* 这里不知道如何将 image.Image类型转换为 io.Writer类型, 所以只有暂时在保存后,又重新读了次文件 */ thumb, _ := os.Open(thumbFile) return thumb, nil }
func (f *defaultFileStorage) store(src readable, filename, contentType string) error { if err := os.MkdirAll(f.uploadsDir, 0777); err != nil && !os.IsExist(err) { return errgo.Mask(err) } if err := os.MkdirAll(f.thumbnailsDir, 0777); err != nil && !os.IsExist(err) { return errgo.Mask(err) } // make thumbnail var ( img image.Image err error ) switch contentType { case "image/png": img, err = png.Decode(src) break case "image/jpeg": img, err = jpeg.Decode(src) break case "image/jpg": img, err = jpeg.Decode(src) break case "image/gif": img, err = gif.Decode(src) break default: return errors.New("invalid content type:" + contentType) } if err != nil { return errgo.Mask(err) } thumb := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) graphics.Thumbnail(thumb, img) dst, err := os.Create(path.Join(f.thumbnailsDir, filename)) if err != nil { return errgo.Mask(err) } g := gift.New(gift.Contrast(-30)) g.Draw(thumb, thumb) if err != nil { return errgo.Mask(err) } defer dst.Close() switch contentType { case "image/png": err = png.Encode(dst, thumb) break case "image/jpeg": err = jpeg.Encode(dst, thumb, nil) break case "image/jpg": err = jpeg.Encode(dst, thumb, nil) break case "image/gif": err = gif.Encode(dst, thumb, nil) } if err != nil { return errgo.Mask(err) } src.Seek(0, 0) dst, err = os.Create(path.Join(f.uploadsDir, filename)) if err != nil { return errgo.Mask(err) } defer dst.Close() _, err = io.Copy(dst, src) if err != nil { return errgo.Mask(err) } return nil }
func MakeThumbnail(src image.Image, x int, y int) (image.Image, error) { tgt := image.NewRGBA(image.Rect(0, 0, x, y)) err := graphics.Thumbnail(tgt, src) return tgt, err }
func (c Application) PostUpload(name string) rev.Result { c.Validation.Required(name) if c.Validation.HasErrors() { c.FlashParams() c.Validation.Keep() return c.Redirect(Application.Upload) } photoDir := path.Join(PHOTO_DIRECTORY, name) thumbDir := path.Join(PHOTO_DIRECTORY, "thumbs", name) err := os.MkdirAll(photoDir, 0777) if err != nil { c.FlashParams() c.Flash.Error("Error making directory:", err) return c.Redirect(Application.Upload) } err = os.MkdirAll(thumbDir, 0777) if err != nil { c.FlashParams() c.Flash.Error("Error making directory:", err) return c.Redirect(Application.Upload) } photos := c.Params.Files["photos[]"] for _, photoFileHeader := range photos { // Open the photo. input, err := photoFileHeader.Open() if err != nil { c.FlashParams() c.Flash.Error("Error opening photo:", err) return c.Redirect(Application.Upload) } photoBytes, err := ioutil.ReadAll(input) if err != nil || len(photoBytes) == 0 { rev.ERROR.Println("Failed to read image:", err) continue } input.Close() // Decode the photo. photoImage, format, err := image.Decode(bytes.NewReader(photoBytes)) if err != nil { rev.ERROR.Println("Failed to decode image:", err) continue } // Decode the EXIF data x, err := exif.Decode(bytes.NewReader(photoBytes)) if err != nil { rev.ERROR.Println("Failed to decode image exif:", err) continue } var orientation int = 1 if orientationTag, err := x.Get(exif.Orientation); err == nil { orientation = int(orientationTag.Int(0)) } photoName := path.Base(photoFileHeader.Filename) // Create a thumbnail thumbnail := image.NewRGBA(image.Rect(0, 0, 256, 256)) err = graphics.Thumbnail(thumbnail, photoImage) if err != nil { rev.ERROR.Println("Failed to create thumbnail:", err) continue } // If the EXIF said to, rotate the thumbnail. // TODO: maintain the EXIF in the thumb instead. if orientation != 1 { if angleRadians, ok := ORIENTATION_ANGLES[orientation]; ok { rotatedThumbnail := image.NewRGBA(image.Rect(0, 0, 256, 256)) err = graphics.Rotate(rotatedThumbnail, thumbnail, &graphics.RotateOptions{Angle: angleRadians}) if err != nil { rev.ERROR.Println("Failed to rotate:", err) } else { thumbnail = rotatedThumbnail } } } thumbnailFile, err := os.Create(path.Join(thumbDir, photoName)) if err != nil { c.FlashParams() c.Flash.Error("Error creating file:", err) return c.Redirect(Application.Upload) } err = jpeg.Encode(thumbnailFile, thumbnail, nil) if err != nil { c.FlashParams() c.Flash.Error("Failed to save thumbnail:", err) return c.Redirect(Application.Upload) } // Save the photo output, err := os.Create(path.Join(photoDir, photoName)) if err != nil { c.FlashParams() c.Flash.Error("Error creating file:", err) return c.Redirect(Application.Upload) } _, err = io.Copy(output, bytes.NewReader(photoBytes)) output.Close() if err != nil { c.FlashParams() c.Flash.Error("Error writing photo:", err) return c.Redirect(Application.Upload) } var taken time.Time if takenTag, err := x.Get("DateTimeOriginal"); err == nil { taken, err = time.Parse("2006:01:02 15:04:05", takenTag.StringVal()) if err != nil { rev.ERROR.Println("Failed to parse time:", takenTag.StringVal(), ":", err) } } // Save a record of the photo to our database. rect := photoImage.Bounds() photo := models.Photo{ Username: name, Format: format, Name: photoName, Width: rect.Max.X - rect.Min.X, Height: rect.Max.Y - rect.Min.Y, Uploaded: time.Now(), Taken: taken, } c.Txn.Insert(&photo) } c.Flash.Success("%d photos uploaded.", len(photos)) return c.Redirect(Application.View) }
func serveThumb(resp http.ResponseWriter, req *http.Request, path string) { var outerr error log.Println("Requested image", path) //log.Println( "Oldest: ", icache.Top() ) //log.Println( "heap: ", icache.GetPaths() ) defer func() { if recover() != nil { if outerr == nil { http.Error(resp, "Internal Server Error", 500) } else { http.Error(resp, outerr.Error(), 500) } } }() /* if icache == nil { //icache = make( map[string]*bytes.Reader, 100 ) icache = &ImageCache{} } */ cached, ok := icache.Find(path) if ok { icache.Update(path) } else { log.Println("Generating thumbnail") fd, err := os.Open(config.Root + "/" + path) defer fd.Close() if err != nil { outerr = err log.Panic("ERROR: file open error ", err.Error()) } img, _, err := image.Decode(fd) if err != nil { outerr = err log.Panic("ERROR: Could not decode. ", err.Error()) } scaled := image.NewRGBA(image.Rect(0, 0, 100, 100)) graphics.Thumbnail(scaled, img) var buf bytes.Buffer err = jpeg.Encode(&buf, scaled, &jpeg.Options{jpeg.DefaultQuality}) if err != nil { outerr = err log.Panic("ERROR: could not encode to jpeg. ", err.Error()) } data, err := ioutil.ReadAll(&buf) if err != nil { outerr = err log.Panic("ERROR: ", err.Error()) } cached = bytes.NewReader(data) heap.Push(icache, NewCacheItem(path, cached)) if icache.Len() > config.MaxImages { log.Println("Dropping oldest cache: ", heap.Pop(icache).(*CacheItem).path) } //icache[ path ] = cached } cached.Seek(0, 0) io.Copy(resp, cached) }