github.com/go-oss/image@v0.1.1-0.20230517025328-001b78555e78/imageutil/exif.go (about) 1 package imageutil 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "image" 8 "image/jpeg" 9 "io" 10 11 "github.com/disintegration/imaging" 12 "github.com/rwcarlsen/goexif/exif" 13 ) 14 15 // RemoveExif remove JPEG EXIF metadata and rotate image for orientation tag. 16 func RemoveExif(r io.Reader) (io.Reader, error) { 17 buff := new(bytes.Buffer) 18 defer buff.Reset() 19 r = io.TeeReader(r, buff) 20 21 img, err := jpeg.Decode(r) 22 if err != nil { 23 return nil, err 24 } 25 26 // check EXIF and apply orientation 27 meta, err := exif.Decode(buff) 28 if err == nil { 29 // エラーが発生した場合は入力画像の EXIF が不正なだけなので無視する 30 newImg, _ := applyOrientation(img, meta) 31 if newImg != nil { 32 img = newImg 33 } 34 } 35 36 // Remove EXIF metadata 37 reader, writer := io.Pipe() 38 go func() { 39 var err error 40 defer func() { 41 if cause := recover(); cause != nil && err == nil { 42 err = fmt.Errorf("panic: %+v", cause) 43 } 44 writer.CloseWithError(err) 45 }() 46 err = jpeg.Encode(writer, img, &jpeg.Options{Quality: 100}) 47 }() 48 return reader, nil 49 } 50 51 func applyOrientation(img image.Image, meta *exif.Exif) (image.Image, error) { 52 tag, err := meta.Get(exif.Orientation) 53 if err != nil { 54 return nil, err 55 } 56 orientation, err := tag.Int(0) 57 if err != nil { 58 return nil, err 59 } 60 if orientation < 1 || orientation > 8 { 61 return nil, errors.New("invalid orientation") 62 } 63 64 // ref: http://www.exif.org/Exif2-2.PDF 65 // ref: http://www.cipa.jp/std/documents/j/DC-008-2012_J.pdf 66 switch orientation { 67 case 1: // The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. 68 return img, nil 69 case 2: // The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. 70 img = imaging.FlipH(img) 71 case 3: // The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. 72 img = imaging.FlipH(img) 73 img = imaging.FlipV(img) 74 case 4: // The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. 75 img = imaging.FlipV(img) 76 case 5: // The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. 77 img = imaging.Rotate270(img) 78 img = imaging.FlipH(img) 79 case 6: // The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. 80 img = imaging.Rotate270(img) 81 case 7: // The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 82 img = imaging.Rotate90(img) 83 img = imaging.FlipH(img) 84 case 8: // The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 85 img = imaging.Rotate90(img) 86 } 87 88 return img, nil 89 }