Пример #1
0
// 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
}
Пример #2
0
// 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
}
Пример #3
0
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
	}
}
Пример #4
0
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)
}
Пример #5
0
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)
			}
		}
	}
}
Пример #6
0
func (e *GoImageEngine) Source(img *imagefile.ImageFile) (image.Image, error) {
	return imaging.Decode(bytes.NewReader(img.Source))
}
Пример #7
0
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))
						}
					}
				}
			}
		}
	}
}