// GetHash returns a phash string for a JPEG image func GetHash(reader io.Reader) (string, error) { image, err := imaging.Decode(reader) if err != nil { return "", err } image = imaging.Resize(image, 32, 32, imaging.Lanczos) image = imaging.Grayscale(image) imageMatrixData := getImageMatrix(image) dctMatrix := getDCTMatrix(imageMatrixData) smallDctMatrix := reduceMatrix(dctMatrix, 8) dctMeanValue := calculateMeanValue(smallDctMatrix) return buildHash(smallDctMatrix, dctMeanValue), nil }
// 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 }
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 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 TestDummyApplication(t *testing.T) { ts := newHTTPServer() defer ts.Close() defer ts.CloseClientConnections() app := newDummyApplication() for _, filename := range []string{"avatar.png", "schwarzy.jpg", "giphy.gif"} { u, _ := url.Parse(ts.URL + "/" + filename) contentType := mime.TypeByExtension(path.Ext(filename)) tests := []*TestRequest{ &TestRequest{ URL: fmt.Sprintf("http://example.com/display?url=%s&w=50&h=50&op=resize", u.String()), Dimensions: &Dimension{ Width: 50, Height: 50, }, }, &TestRequest{ URL: fmt.Sprintf("http://example.com/display?url=%s&w=100&h=30&op=resize", u.String()), Dimensions: &Dimension{ Width: 100, Height: 30, }, }, &TestRequest{ URL: fmt.Sprintf("http://example.com/display?url=%s&w=50&h=50&op=thumbnail", u.String()), Dimensions: &Dimension{ Width: 50, Height: 50, }, }, &TestRequest{ URL: fmt.Sprintf("http://example.com/display?url=%s&w=50&h=50&op=thumbnail&fmt=jpg", u.String()), Dimensions: &Dimension{ Width: 50, Height: 50, }, ContentType: "image/jpeg", }, } for _, test := range tests { request, _ := http.NewRequest("GET", test.URL, nil) res := httptest.NewRecorder() handler := app.ServeHTTP(ImageHandler) handler.ServeHTTP(res, request) img, err := imaging.Decode(res.Body) assert.Nil(t, err) if test.ContentType != "" { assert.Equal(t, res.Header().Get("Content-Type"), test.ContentType) } else { assert.Equal(t, res.Header().Get("Content-Type"), contentType) } assert.Equal(t, res.Code, 200) if img.Bounds().Max.X != test.Dimensions.Width { t.Fatalf("Invalid width for %s: %d != %d", filename, img.Bounds().Max.X, test.Dimensions.Width) } if img.Bounds().Max.Y != test.Dimensions.Height { t.Fatalf("Invalid width for %s: %d != %d", filename, img.Bounds().Max.Y, test.Dimensions.Height) } } } }
func (e *GoImageEngine) Source(img *imagefile.ImageFile) (image.Image, error) { return imaging.Decode(bytes.NewReader(img.Source)) }
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)) } } } } } } }