mirror of
https://github.com/willnorris/imageproxy.git
synced 2026-05-03 16:52:40 +02:00
add support for exif orientation tag
if any transformation is requested, first apply any additional transformation necessary to correct for the EXIF orientation tag, since it is stripped from the resulting image. Fixes #63
This commit is contained in:
parent
07c54b46e3
commit
67619a67ae
2 changed files with 138 additions and 1 deletions
|
|
@ -16,6 +16,7 @@ package imageproxy
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
|
@ -39,7 +40,7 @@ var (
|
|||
// newImage creates a new NRGBA image with the specified dimensions and pixel
|
||||
// color data. If the length of pixels is 1, the entire image is filled with
|
||||
// that color.
|
||||
func newImage(w, h int, pixels ...color.NRGBA) image.Image {
|
||||
func newImage(w, h int, pixels ...color.Color) image.Image {
|
||||
m := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||
if len(pixels) == 1 {
|
||||
draw.Draw(m, m.Bounds(), &image.Uniform{pixels[0]}, image.ZP, draw.Src)
|
||||
|
|
@ -145,6 +146,77 @@ func TestTransform(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test that each of the eight EXIF orientations is applied to the transformed
|
||||
// image appropriately.
|
||||
func TestTransform_EXIF(t *testing.T) {
|
||||
ref := newImage(2, 2, red, green, blue, yellow)
|
||||
|
||||
// reference image encoded as TIF, with each of the 8 EXIF orientations
|
||||
// applied in reverse and the EXIF tag set. When orientation is
|
||||
// applied, each should display as the ref image.
|
||||
tests := []string{
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAAAQAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAGQAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nPrPwPAfDBn+////n+E/IAAA//9DzAj4AA==", // Orientation=1
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAAAgAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAGQAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nGL4z/D/PwPD////GcAUIAAA//9HyAj4AA==", // Orientation=2
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAAAwAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAFwAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nPr/n+E/AwOY/A9iAAIAAP//T8AI+AA=", // Orientation=3
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAABAAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAGgAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nGJg+P///3+G//8ZGP6DICAAAP//S8QI+A==", // Orientation=4
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAABQAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAGAAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nPrPwABC/xn+M/wHkYAAAAD//0PMCPg=", // Orientation=5
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAABgAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAGAAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nGL4z/D/PwgzMIDQf0AAAAD//0vECPg=", // Orientation=6
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAABwAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAFgAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nPr/nwECGf7/BxGAAAAA//9PwAj4", // Orientation=7
|
||||
"SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAACAAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAFQAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nGJg+P//P4QAQ0AAAAD//0fICPgA", // Orientation=8
|
||||
}
|
||||
|
||||
for _, src := range tests {
|
||||
in, err := base64.StdEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding source: %v", err)
|
||||
}
|
||||
out, err := Transform(in, Options{Height: -1, Width: -1, Format: "tiff"})
|
||||
if err != nil {
|
||||
t.Errorf("Transform(%q) returned error: %v", src, err)
|
||||
}
|
||||
d, _, err := image.Decode(bytes.NewReader(out))
|
||||
if err != nil {
|
||||
t.Errorf("error decoding transformed image: %v", err)
|
||||
}
|
||||
|
||||
// construct new image with same colors as decoded image for easy comparison
|
||||
got := newImage(2, 2, d.At(0, 0), d.At(1, 0), d.At(0, 1), d.At(1, 1))
|
||||
if want := ref; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Transform(%v) returned image %#v, want %#v", src, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that EXIF orientation and any additional transforms don't conflict.
|
||||
// This is tested with orientation=7, which involves both a rotation and a
|
||||
// flip, combined with an additional rotation transform.
|
||||
func TestTransform_EXIF_Rotate(t *testing.T) {
|
||||
// base64-encoded TIF image (2x2 yellow green blue red) with EXIF
|
||||
// orientation=7. When orientation applied, displays as (2x2 red green
|
||||
// blue yellow).
|
||||
src := "SUkqAAgAAAAOAAABAwABAAAAAgAAAAEBAwABAAAAAgAAAAIBAwAEAAAAtgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAAzgAAABIBAwABAAAABwAAABUBAwABAAAABAAAABYBAwABAAAAAgAAABcBBAABAAAAFgAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAAFIBAwABAAAAAgAAAAAAAAAIAAgACAAIAEgAAAABAAAASAAAAAEAAAB4nPr/nwECGf7/BxGAAAAA//9PwAj4"
|
||||
|
||||
in, err := base64.StdEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding source: %v", err)
|
||||
}
|
||||
out, err := Transform(in, Options{Rotate: 90, Format: "tiff"})
|
||||
if err != nil {
|
||||
t.Errorf("Transform(%q) returned error: %v", src, err)
|
||||
}
|
||||
d, _, err := image.Decode(bytes.NewReader(out))
|
||||
if err != nil {
|
||||
t.Errorf("error decoding transformed image: %v", err)
|
||||
}
|
||||
|
||||
// construct new image with same colors as decoded image for easy comparison
|
||||
got := newImage(2, 2, d.At(0, 0), d.At(1, 0), d.At(0, 1), d.At(1, 1))
|
||||
want := newImage(2, 2, green, yellow, red, blue)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Transform(%v) returned image %#v, want %#v", src, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformImage(t *testing.T) {
|
||||
// ref is a 2x2 reference image containing four colors
|
||||
ref := newImage(2, 2, red, green, blue, yellow)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue