func (ths *ImageTagServer) go_get_image(w http.ResponseWriter, r *http.Request) { path := r.URL.Query().Get("path") path = ths.imgRoot + path path = strings.Replace(path, "..", "", -1) info, infoErr := os.Stat(path) if infoErr != nil { http.Error(w, infoErr.Error(), http.StatusInternalServerError) return } if info.IsDir() == true { http.Error(w, "No an image", http.StatusBadRequest) return } img, err := imaging.Open(path) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Add("Content-Type", "image/jpeg") err = imaging.Encode(w, img, imaging.JPEG) if err != nil { http.Error(w, "Failed to thumbNail image", http.StatusInternalServerError) return } }
func (imageHandler) Handle(media MediaLibrary, file multipart.File, option *Option) error { if err := media.Store(media.URL("original"), option, file); err == nil { file.Seek(0, 0) if img, err := imaging.Decode(file); err == nil { if format, err := getImageFormat(media.URL()); err == nil { if cropOption := media.GetCropOption("original"); cropOption != nil { img = imaging.Crop(img, *cropOption) } // Save default image var buffer bytes.Buffer imaging.Encode(&buffer, img, *format) media.Store(media.URL(), option, &buffer) for key, size := range media.GetSizes() { newImage := img if cropOption := media.GetCropOption(key); cropOption != nil { newImage = imaging.Crop(newImage, *cropOption) } dst := imaging.Thumbnail(newImage, size.Width, size.Height, imaging.Lanczos) var buffer bytes.Buffer imaging.Encode(&buffer, dst, *format) media.Store(media.URL(key), option, &buffer) } return nil } else { return err } } else { return err } } else { return err } }
func Resize(src io.Reader, c *CacheContext) (io.Reader, error) { raw, err := ioutil.ReadAll(src) if err != nil { return nil, err } width := c.Width data := bytes.NewReader(raw) img, format, err := image.Decode(data) if err != nil { return nil, err } var resizedImage image.NRGBA if c.Crop { minDimension := int(math.Min(float64(img.Bounds().Size().X), float64(img.Bounds().Size().Y))) if minDimension < c.Width || c.Width == 0 { width = minDimension } resizedImage = *imaging.Fill(img, width, width, imaging.Center, imaging.Lanczos) } else { resizedImage = *imaging.Resize(img, width, 0, imaging.Lanczos) } buf := new(bytes.Buffer) var imgFormat imaging.Format switch format { case "png": imgFormat = imaging.PNG case "jpeg": imgFormat = imaging.JPEG case "tiff": imgFormat = imaging.TIFF case "bmp": imgFormat = imaging.BMP default: return nil, errors.New("unsupported image format") } err = imaging.Encode(buf, resizedImage.SubImage(resizedImage.Rect), imgFormat) if err != nil { return nil, err } return buf, err }
func getImage(filename string, small bool) (io.ReadCloser, error) { if !small { return os.Open(filename) } fullImage, err := imaging.Open(filename) if err != nil { return nil, err } resized := imaging.Fit(fullImage, config.SmallRes, config.SmallRes, imaging.Linear) r, w := io.Pipe() go imaging.Encode(w, resized, imaging.JPEG) return r, nil }
func thumbnailHandler(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() height, err := strconv.Atoi(query.Get("height")) if err != nil { height = 50 } path := filepath.Join(storage, r.URL.Path) photo, err := imaging.Open(path) if err != nil { fmt.Fprint(w, err) return } switch readRotation(path) { case 8: photo = imaging.Rotate90(photo) case 2: photo = imaging.Rotate180(photo) case 6: photo = imaging.Rotate270(photo) } thumb := imaging.Resize(photo, 0, height, imaging.Box) imaging.Encode(w, thumb, imaging.JPEG) }
// Do performs the resize func Do(r io.Reader, w io.Writer, crop *image.Rectangle, width, height int) error { // read it img, err := imaging.Decode(r) if err != nil { return err } // if crop isn't nil if crop != nil { // then crop it img = imaging.Crop(img, *crop) } // resize it img = imaging.Resize(img, width, height, imaging.MitchellNetravali) // write it if err := imaging.Encode(w, img, imaging.PNG); err != nil { return err } return nil }
/* blurImage: blur the image and save it */ func blurImage(inFilename string, outFilename string, factor float64, format imaging.Format) { // // print a message about what we are converting // fmt.Println("\t\t", inFilename, "=>", outFilename, "using factor", factor) // // Open the file and read in the image // infile, err := os.Open(inFilename) errorCheck(err) defer infile.Close() // // load in the actual image data (decode image) and work out the new dimensions // srcImage, _, err := image.Decode(infile) errorCheck(err) // // blue the image... // blurredImage := imaging.Blur(srcImage, factor) // // save the new image // outfile, err := os.Create(outFilename) errorCheck(err) defer outfile.Close() imaging.Encode(outfile, blurredImage, format) // png.Encode(outfile, blurredImage) }
func (ths *ImageTagServer) go_thumb_image(w http.ResponseWriter, r *http.Request) { imgPath := r.URL.Query().Get("path") path := imgPath path = ths.imgRoot + path path = strings.Replace(path, "..", "", -1) info, infoErr := os.Stat(path) if infoErr != nil { http.Error(w, infoErr.Error(), http.StatusInternalServerError) return } db := ths.get_db() if db == nil { return } defer db.Close() row, rerr := db.Query("SELECT Thumb FROM Image WHERE Path LIKE '" + imgPath + "';") if rerr != nil { log.Println(rerr.Error()) http.Error(w, rerr.Error(), http.StatusInternalServerError) return } if row.Next() { var result string e := row.Scan(&result) if e != nil { log.Println(e.Error()) http.Error(w, e.Error(), http.StatusInternalServerError) return } b, _ := base64.StdEncoding.DecodeString(result) w.Header().Add("Content-Type", "image/jpeg") w.Write(b) return } if info.IsDir() == true { http.Error(w, "No an image", http.StatusBadRequest) return } img, err := imaging.Open(path) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } thumb := imaging.Thumbnail(img, 300, 300, imaging.CatmullRom) buffer := bytes.NewBuffer(nil) imaging.Encode(buffer, thumb, imaging.JPEG) b64 := base64.StdEncoding.EncodeToString(buffer.Bytes()) insertRes, insertResErr := db.Exec("INSERT INTO Image(Path,Thumb) VALUES('" + imgPath + "','" + b64 + "');") if insertResErr != nil { log.Println(insertResErr.Error()) http.Error(w, insertResErr.Error(), http.StatusInternalServerError) return } iid, _ := insertRes.LastInsertId() log.Println("Added image \"" + imgPath + "\" with id " + strconv.FormatInt(iid, 10)) w.Header().Add("Content-Type", "image/jpeg") w.Write(buffer.Bytes()) if err != nil { http.Error(w, "Failed to thumbNail image", http.StatusInternalServerError) return } }
func storeImage(rw http.ResponseWriter, req *http.Request) { // Appengine var c appengine.Context // Google Cloud Storage authentication var cc gcscontext.Context // Google Cloud Storage bucket name var bucketName string = "" // Google Cloud Storage client var client *storage.Client // Google Cloud Storage bucket var bucketHandle *storage.BucketHandle // User uploaded image file name var fileName string = uuid.New() // Transform user uploaded image to a thumbnail file name var fileNameThumbnail string = uuid.New() // User uploaded image file type var contentType string = "" // User uploaded image file raw data var b []byte // Google Cloud Storage file writer var wc *storage.Writer = nil // Error var err error = nil // Result, 0: success, 1: failed var r int = http.StatusCreated // Set response in the end defer func() { // Return status. WriteHeader() must be called before call to Write if r == http.StatusCreated { // Changing the header after a call to WriteHeader (or Write) has no effect. // rw.Header().Set("Location", req.URL.String()+"/"+cKey.Encode()) rw.Header().Set("Location", "http://"+bucketName+".storage.googleapis.com/"+fileName) rw.Header().Set("X-Thumbnail", "http://"+bucketName+".storage.googleapis.com/"+fileNameThumbnail) rw.WriteHeader(r) } else { http.Error(rw, http.StatusText(r), r) } }() // To log information in Google APP Engine console c = appengine.NewContext(req) // Get data from body b, err = ioutil.ReadAll(req.Body) if err != nil { c.Errorf("%s in reading body", err) r = http.StatusInternalServerError return } c.Infof("Body length %d bytes, read %d bytes", req.ContentLength, len(b)) // Determine filename extension from content type contentType = req.Header["Content-Type"][0] switch contentType { case "image/jpeg": fileName += ".jpg" fileNameThumbnail += ".jpg" default: c.Errorf("Unknown or unsupported content type '%s'. Valid: image/jpeg", contentType) r = http.StatusBadRequest return } c.Infof("Content type %s is received, %s is detected.", contentType, http.DetectContentType(b)) // Prepare Google Cloud Storage authentication cc = gcsappengine.NewContext(req) if client, err = storage.NewClient(cc); err != nil { c.Errorf("%s in initializing a GCS client", err) r = http.StatusInternalServerError return } defer client.Close() // Get default bucket if bucketName, err = gcsfile.DefaultBucketName(cc); err != nil { c.Errorf("%s in getting default GCS bucket name", err) r = http.StatusInternalServerError return } bucketHandle = client.Bucket(bucketName) c.Infof("APP Engine Version: %s", gcsappengine.VersionID(cc)) c.Infof("Using bucket name: %s", bucketName) // Change default object ACLs if err = bucketHandle.DefaultObjectACL().Set(cc, storage.AllUsers, storage.RoleReader); err != nil { c.Errorf("%v in saving default object ACL rule for bucket %q", err, bucketName) r = http.StatusInternalServerError return } // Store rotated image in Google Cloud Storage var in *bytes.Reader = bytes.NewReader(b) var x *exif.Exif = nil var orientation *tiff.Tag = nil var beforeImage image.Image var afterImage *image.NRGBA = nil // Read EXIF if _, err = in.Seek(0, 0); err != nil { c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err) return } if x, err = exif.Decode(in); err != nil { c.Errorf("%s in decoding JPEG image", err) return } // Get Orientation if orientation, err = x.Get(exif.Orientation); err != nil { c.Warningf("%s in getting orientation from EXIF", err) return } c.Debugf("Orientation %s", orientation.String()) // Open image if _, err = in.Seek(0, 0); err != nil { c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err) return } if beforeImage, err = imaging.Decode(in); err != nil { c.Errorf("%s in opening image %s", err) return } switch orientation.String() { case "1": afterImage = beforeImage.(*image.NRGBA) case "2": afterImage = imaging.FlipH(beforeImage) case "3": afterImage = imaging.Rotate180(beforeImage) case "4": afterImage = imaging.FlipV(beforeImage) case "5": afterImage = imaging.Transverse(beforeImage) case "6": afterImage = imaging.Rotate270(beforeImage) case "7": afterImage = imaging.Transpose(beforeImage) case "8": afterImage = imaging.Rotate90(beforeImage) } // Save rotated image wc = bucketHandle.Object(fileName).NewWriter(cc) wc.ContentType = contentType if err = imaging.Encode(wc, afterImage, imaging.JPEG); err != nil { c.Errorf("%s in saving rotated image", err) return } if err = wc.Close(); err != nil { c.Errorf("CreateFile: unable to close bucket %q, file %q: %v", bucketName, fileName, err) r = 1 return } wc = nil // Make thumbnail if afterImage.Rect.Dx() > afterImage.Rect.Dy() { afterImage = imaging.Resize(afterImage, 1920, 0, imaging.Lanczos) } else { afterImage = imaging.Resize(afterImage, 0, 1920, imaging.Lanczos) } // Save thumbnail wc = bucketHandle.Object(fileNameThumbnail).NewWriter(cc) wc.ContentType = contentType if imaging.Encode(wc, afterImage, imaging.JPEG); err != nil { c.Errorf("%s in saving image thumbnail", err) return } if err = wc.Close(); err != nil { c.Errorf("CreateFileThumbnail: unable to close bucket %q, file %q: %v", bucketName, fileNameThumbnail, err) r = 1 return } c.Infof("/%v/%v, /%v/%v created", bucketName, fileName, bucketName, fileNameThumbnail) }
func (p *program) downloadWriteKey(key string, w http.ResponseWriter) error { bl, found := downloadMapper[key] if !found { http.Error(w, "Not found", 404) return nil } w.Header().Set("Content-Disposition", `attachment; filename="photos.tar"`) tw := tar.NewWriter(w) result := &bytes.Buffer{} for _, item := range bl.list { filename := filepath.Join(config.FileRoot, bl.folder, item) fi, err := os.Stat(filename) if err != nil { return err } if !bl.small { header, err := tar.FileInfoHeader(fi, "") if err != nil { return err } err = tw.WriteHeader(header) if err != nil { return err } f, err := os.Open(filename) if err != nil { return err } _, err = io.Copy(tw, f) f.Close() if err != nil { return err } } else { fullImage, err := imaging.Open(filename) if err != nil { return err } resized := imaging.Fit(fullImage, config.SmallRes, config.SmallRes, imaging.Linear) err = imaging.Encode(result, resized, imaging.JPEG) if err != nil { return err } header := &tar.Header{ Name: item, Size: int64(result.Len()), Mode: 0666, ModTime: fi.ModTime(), } err = tw.WriteHeader(header) if err != nil { return err } _, err = io.Copy(tw, result) if err != nil { return err } result.Reset() } } return tw.Close() }
func SaveAndCropImage(isCreate bool) func(scope *gorm.Scope) { return func(scope *gorm.Scope) { for _, field := range scope.Fields() { if media, ok := field.Field.Addr().Interface().(MediaLibrary); ok { option := parseTagOption(field.Tag.Get("media_library")) if media.GetFileHeader() != nil || media.NeedCrop() { var file multipart.File var err error if fileHeader := media.GetFileHeader(); fileHeader != nil { file, err = media.GetFileHeader().Open() } else { file, err = media.Retrieve(media.URL("original")) } if scope.Err(err) != nil { return } if url := media.GetURL(option, scope, field, media); url == "" { scope.Err(errors.New("invalid URL")) } else { result, _ := json.Marshal(map[string]string{"Url": url}) media.Scan(string(result)) } if isCreate && !scope.HasError() { if value, err := media.Value(); err == nil { gorm.Update(scope.New(scope.Value).InstanceSet("gorm:update_attrs", map[string]interface{}{field.DBName: value})) } } if file != nil { defer file.Close() if media.IsImage() { // Save Original Image if scope.Err(media.Store(media.URL("original"), option, file)) == nil { file.Seek(0, 0) // Crop & Resize if img, err := imaging.Decode(file); scope.Err(err) == nil { if format, err := getImageFormat(media.URL()); scope.Err(err) == nil { if cropOption := media.GetCropOption("original"); cropOption != nil { img = imaging.Crop(img, *cropOption) } // Save default image var buffer bytes.Buffer imaging.Encode(&buffer, img, *format) media.Store(media.URL(), option, &buffer) for key, size := range media.GetSizes() { newImage := img if cropOption := media.GetCropOption(key); cropOption != nil { newImage = imaging.Crop(newImage, *cropOption) } dst := imaging.Thumbnail(newImage, size.Width, size.Height, imaging.Lanczos) var buffer bytes.Buffer imaging.Encode(&buffer, dst, *format) media.Store(media.URL(key), option, &buffer) } } } } } else { // Save File scope.Err(media.Store(media.URL(), option, file)) } } } } } } }
func handleServeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) { img, err := ImageByID(sq.DB(ctx), web.Args(ctx).ByIndex(0)) switch err { case nil: // all good case sq.ErrNotFound: web.StdJSONResp(w, http.StatusNotFound) return default: log.Error("cannot get object", "object", web.Args(ctx).ByIndex(0), "error", err.Error()) web.StdJSONResp(w, http.StatusInternalServerError) return } if web.CheckLastModified(w, r, img.Created) { return } fs := FileStore(ctx) fd, err := fs.Read(img.Created.Year(), img.ImageID) if err != nil { log.Error("cannot read image file", "image", img.ImageID, "error", err.Error()) web.StdJSONResp(w, http.StatusInternalServerError) return } defer fd.Close() w.Header().Set("X-Image-ID", img.ImageID) w.Header().Set("X-Image-Width", fmt.Sprint(img.Width)) w.Header().Set("X-Image-Height", fmt.Sprint(img.Height)) w.Header().Set("X-Image-Created", img.Created.Format(time.RFC3339)) w.Header().Set("Content-Type", "image/jpeg") if r.URL.Query().Get("resize") == "" { io.Copy(w, fd) return } image, err := jpeg.Decode(fd) if err != nil { log.Error("cannot read image file", "image", img.ImageID, "error", err.Error()) web.StdJSONResp(w, http.StatusInternalServerError) return } var width, height int if _, err := fmt.Sscanf(r.URL.Query().Get("resize"), "%dx%d", &width, &height); err != nil { log.Error("cannot resize image", "image", img.ImageID, "error", err.Error()) } else { switch img.Orientation { case 1: // all good case 3: image = imaging.Rotate180(image) case 8: image = imaging.Rotate90(image) case 6: image = imaging.Rotate270(image) default: log.Debug("unknown image orientation", "decoder", "EXIF", "image", img.ImageID, "value", fmt.Sprint(img.Orientation)) } image = imaging.Fill(image, width, height, imaging.Center, imaging.Linear) } imaging.Encode(w, image, imaging.JPEG) }
func (p *program) serveFile(w http.ResponseWriter, r *http.Request, fullPath, urlPath, resolutionString string) error { if len(resolutionString) == 0 { http.ServeFile(w, r, fullPath) return nil } createThumbFrom := fullPath imgSize, err := strconv.Atoi(resolutionString) if err != nil { return err } isMovie := false cachePath := filepath.Join(p.cacheDir, r.URL.Path) if strings.HasSuffix(urlPath, ".mp4") { // Movie: avconv -i /data/store/Pictures/2015-Q1/VID_20150125_1928.mp4 -vframes 1 -ss 00:00:01 out.jpg createThumbFrom = cachePath + ".orig.jpg" cachePath = cachePath + ".jpg" isMovie = true } _, err = os.Stat(cachePath) if os.IsNotExist(err) { if isMovie { var output []byte for _, time := range movieTimes { cmd := exec.Command("avconv", "-i", fullPath, "-vframes", "1", "-ss", time, createThumbFrom) output, err = cmd.CombinedOutput() if err == nil { _, err = os.Stat(createThumbFrom) // Make sure avconv wrote file. if os.IsNotExist(err) { continue } break } } if err != nil { logger.Errorf("Problem converting thumbnail for movie: %v\n%s\n", err, output) createThumbFrom = filepath.Join(p.execDir, "template", badThumb) } } // Resize image, open cache image. cacheDir, _ := filepath.Split(cachePath) err := os.MkdirAll(cacheDir, 0777) if err != nil { return err } fullImage, err := imaging.Open(createThumbFrom) if err != nil { return err } resized := imaging.Fit(fullImage, imgSize, imgSize, imaging.Linear) // Um, assume JPG for now. cf, err := os.Create(cachePath) if err != nil { return err } err = imaging.Encode(cf, resized, imaging.JPEG) cf.Close() if err != nil { return err } } http.ServeFile(w, r, cachePath) return nil }
func thumbImage(r io.Reader, width int, height int) (buf *bytes.Buffer, err error) { buf = new(bytes.Buffer) imageData, err := ioutil.ReadAll(r) if err != nil { log.Println("cannot read response", err) return nil, err } imageBuffer := bytes.NewBuffer(imageData) img, formatString, err := image.Decode(imageBuffer) if err != nil { log.Println("cannot decode image", err) return } switch formatString { case "jpg": fallthrough case "jpeg": croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos) imaging.Encode(buf, croppedImg, imaging.JPEG) return case "png": croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos) imaging.Encode(buf, croppedImg, imaging.PNG) case "bmp": croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos) imaging.Encode(buf, croppedImg, imaging.BMP) return case "gif": imageBuffer = bytes.NewBuffer(imageData) g, err := gif.DecodeAll(imageBuffer) if err != nil { log.Println("cannot decode gif", err) return nil, err } // over-protected version, still slow // c := thumbGif(g, width, height) // for r := range c { // g.Image[r.Index] = r.Img // } // multiple reader, no wirter to golang map is ok // it's fastest var wg sync.WaitGroup wg.Add(len(g.Image)) imageArray := make([]*image.Paletted, len(g.Image)) for i := range g.Image { imageArray[i] = g.Image[i] go func(index int) { thumb := imaging.Thumbnail(imageArray[index], width, height, imaging.Lanczos) imageArray[index] = image.NewPaletted(image.Rect(0, 0, width, height), imageArray[index].Palette) draw.Draw(imageArray[index], image.Rect(0, 0, width, height), thumb, image.Pt(0, 0), draw.Over) wg.Done() }(i) } wg.Wait() for i := range g.Image { g.Image[i] = imageArray[i] } // plain single thread version, too slow // for i := range g.Image { // thumb := imaging.Thumbnail(g.Image[i], width, height, imaging.Lanczos) // g.Image[i] = image.NewPaletted(image.Rect(0, 0, width, height), g.Image[i].Palette) // draw.Draw(g.Image[i], image.Rect(0, 0, width, height), thumb, image.Pt(0, 0), draw.Over) // } g.Config.Width, g.Config.Height = width, height err = gif.EncodeAll(buf, g) if err != nil { log.Println("cannot encode gif", err) return nil, err } } return }
// CreateThumnail builds a JPG thumbnail and can rotate if an exif bit is set. func CreateThumbnail(deps dependencies.Dependencies, r io.ReadSeeker) (string, int, error) { raw, format, err := image.Decode(r) if format == "" { return "", 0, nil } if format == "jpeg" || format == "jpg" { deps.Debug("Received JPG") orientation, err := readOrientation(r) if err == nil { deps.Debug("Rotating JPG", "orientation", orientation) raw = rotate(raw, orientation) } } deps.Debug("Thumbnail format", "fmt", format) if err != nil { deps.Error("Failed to decode image") return "", 0, err } fs := deps.Fs tmpFilePath := lib.TempFilePath("thumbnail") tmpFile, err := fs.Create(tmpFilePath) if err != nil { deps.Error("Failed to create temp file", "path", tmpFilePath) return "", 0, err } // Make sure we close. closeTmpFile := func() { if tmpFile != nil { tmpFile.Close() tmpFile = nil } } defer closeTmpFile() h := sha1.New() var wc writeCounter mw := io.MultiWriter(tmpFile, h, wc) // Generate Thumbnail image data dst := imaging.Fill(raw, 200, 200, imaging.Center, imaging.Lanczos) // Write it err = imaging.Encode(mw, dst, imaging.JPEG) if err != nil { deps.Error("Failed to encode data") return "", 0, err } hash := fmt.Sprintf("%x", h.Sum(nil)) deps.Debug("Thumbnail hash", "hash:", hash) newPath := lib.LocalPath(hash) // Move temp thumbnail to final destination. err = os.Rename(tmpFilePath, newPath) if err != nil { deps.Error("Failed to rename file") // Todo delete file return hash, int(wc), err } // Set permissons err = fs.Chmod(newPath, 0644) if err != nil { deps.Error("Failed to set permissions", "path", newPath) // Todo delete file return hash, int(wc), err } return hash, int(wc), nil }