fix(resize): auto rotate image before resize calculus

master
Tomas Aparicio 10 years ago
parent da1108f1ad
commit edeb809cc1

@ -32,6 +32,20 @@ func Resize(buf []byte, o Options) ([]byte, error) {
debug("Options: %#v", o) debug("Options: %#v", o)
// Auto rotate image based on EXIF orientation header
image, rotated, err := rotateAndFlipImage(image, o)
if err != nil {
return nil, err
}
// If JPEG image, retrieve the buffer
if rotated && imageType == JPEG && !o.NoAutoRotate {
buf, err = getImageBuffer(image)
if err != nil {
return nil, err
}
}
inWidth := int(image.Xsize) inWidth := int(image.Xsize)
inHeight := int(image.Ysize) inHeight := int(image.Ysize)
@ -68,12 +82,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
residual = float64(shrink) / factor residual = float64(shrink) / factor
} }
// Explicit or auto rotate image based on EXIF header
image, err = rotateAndFlipImage(image, o)
if err != nil {
return nil, err
}
// Zoom image, if necessary // Zoom image, if necessary
image, err = zoomImage(image, o.Zoom) image, err = zoomImage(image, o.Zoom)
if err != nil { if err != nil {
@ -249,8 +257,9 @@ func extractOrEmbedImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
return image, err return image, err
} }
func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, error) { func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, bool, error) {
var err error var err error
var rotated bool
var direction Direction = -1 var direction Direction = -1
if o.NoAutoRotate == false { if o.NoAutoRotate == false {
@ -264,6 +273,7 @@ func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
} }
if o.Rotate > 0 { if o.Rotate > 0 {
rotated = true
image, err = vipsRotate(image, getAngle(o.Rotate)) image, err = vipsRotate(image, getAngle(o.Rotate))
} }
@ -274,10 +284,11 @@ func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
} }
if direction != -1 { if direction != -1 {
rotated = true
image, err = vipsFlip(image, direction) image, err = vipsFlip(image, direction)
} }
return image, err return image, rotated, err
} }
func watermakImage(image *C.VipsImage, w Watermark) (*C.VipsImage, error) { func watermakImage(image *C.VipsImage, w Watermark) (*C.VipsImage, error) {

@ -113,7 +113,7 @@ func TestResizeCustomSizes(t *testing.T) {
} }
func TestRotate(t *testing.T) { func TestRotate(t *testing.T) {
options := Options{Width: 800, Height: 600, Rotate: 270} options := Options{Width: 800, Height: 600, Rotate: 270, Crop: true}
buf, _ := Read("fixtures/test.jpg") buf, _ := Read("fixtures/test.jpg")
newImg, err := Resize(buf, options) newImg, err := Resize(buf, options)
@ -122,19 +122,19 @@ func TestRotate(t *testing.T) {
} }
if DetermineImageType(newImg) != JPEG { if DetermineImageType(newImg) != JPEG {
t.Fatal("Image is not jpeg") t.Error("Image is not jpeg")
} }
size, _ := Size(newImg) size, _ := Size(newImg)
if size.Height != options.Width { if size.Width != options.Width || size.Height != options.Height {
t.Fatalf("Invalid image size: %dx%d", size.Width, size.Height) t.Errorf("Invalid image size: %dx%d", size.Width, size.Height)
} }
Write("fixtures/test_rotate_out.jpg", newImg) Write("fixtures/test_rotate_out.jpg", newImg)
} }
func TestInvalidRotate(t *testing.T) { func TestInvalidRotateDegrees(t *testing.T) {
options := Options{Width: 800, Height: 600, Rotate: 111} options := Options{Width: 800, Height: 600, Rotate: 111, Crop: true}
buf, _ := Read("fixtures/test.jpg") buf, _ := Read("fixtures/test.jpg")
newImg, err := Resize(buf, options) newImg, err := Resize(buf, options)
@ -143,15 +143,15 @@ func TestInvalidRotate(t *testing.T) {
} }
if DetermineImageType(newImg) != JPEG { if DetermineImageType(newImg) != JPEG {
t.Fatal("Image is not jpeg") t.Errorf("Image is not jpeg")
} }
size, _ := Size(newImg) size, _ := Size(newImg)
if size.Height != options.Width { if size.Width != options.Width || size.Height != options.Height {
t.Fatalf("Invalid image size: %dx%d", size.Width, size.Height) t.Errorf("Invalid image size: %dx%d", size.Width, size.Height)
} }
Write("fixtures/test_invalid_rotate_out.jpg", newImg) Write("fixtures/test_rotate_invalid_out.jpg", newImg)
} }
func TestCorruptedImage(t *testing.T) { func TestCorruptedImage(t *testing.T) {

@ -341,8 +341,23 @@ func vipsSave(image *C.VipsImage, o vipsSaveOptions) ([]byte, error) {
return buf, nil return buf, nil
} }
func max(x int) int { func getImageBuffer(image *C.VipsImage) ([]byte, error) {
return int(math.Max(float64(x), 0)) var ptr unsafe.Pointer
length := C.size_t(0)
interlace := C.int(0)
quality := C.int(100)
err := C.int(0)
err = C.vips_jpegsave_bridge(image, &ptr, &length, 1, quality, interlace)
if int(err) != 0 {
return nil, catchVipsError()
}
defer C.g_free(C.gpointer(ptr))
defer C.vips_error_clear()
return C.GoBytes(ptr, C.int(length)), nil
} }
func vipsExtract(image *C.VipsImage, left, top, width, height int) (*C.VipsImage, error) { func vipsExtract(image *C.VipsImage, left, top, width, height int) (*C.VipsImage, error) {
@ -484,3 +499,7 @@ func vipsSharpen(image *C.VipsImage, o Sharpen) (*C.VipsImage, error) {
} }
return out, nil return out, nil
} }
func max(x int) int {
return int(math.Max(float64(x), 0))
}

Loading…
Cancel
Save