Files
kenaito-media-picker/internal/probe/exif_test.go
T
odboy 66faed75a2 feat: 增加 EXIF 旋转图片自动转正
- 解析 JPEG EXIF Orientation,方向 5/6/7/8 的竖拍横存图不再误入横屏目录
- 配置 ffmpeg 时用 ffmpeg 物理转正像素并保留原 EXIF;无 ffmpeg 时按显示方向归类
- 新增 ffmpeg.path / organize.rotateImages 配置项
- 补充 EXIF 解析与旋转幂等测试
2025-05-19 21:15:58 +08:00

104 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package probe
import (
"encoding/binary"
"os"
"path/filepath"
"testing"
)
// buildJpegWithOrientation 拼一个带 Exif 方向标记的最小 JPEG:
// SOI + APP1(Exif) + EOI,APP1 里只放 TIFF 头 + IFD0 一条 Orientation。
func buildJpegWithOrientation(t *testing.T, orientation uint16, bigEndian bool) []byte {
t.Helper()
var order binary.ByteOrder = binary.LittleEndian
if bigEndian {
order = binary.BigEndian
}
bom := []byte("II")
if bigEndian {
bom = []byte("MM")
}
// TIFF 头(8) + IFD0 计数(2) + 一条目(12)
tiff := make([]byte, 0, 8+2+12)
tiff = append(tiff, bom...)
magic := make([]byte, 2)
order.PutUint16(magic, 42)
tiff = append(tiff, magic...)
ifdOff := make([]byte, 4)
order.PutUint32(ifdOff, 8)
tiff = append(tiff, ifdOff...)
count := make([]byte, 2)
order.PutUint16(count, 1)
tiff = append(tiff, count...)
// 一条目:tag=0x0112 type=SHORT count=1 value=orientation
entry := make([]byte, 12)
order.PutUint16(entry[0:2], 0x0112)
order.PutUint16(entry[2:4], 3) // SHORT
order.PutUint32(entry[4:8], 1) // count
order.PutUint16(entry[8:10], orientation)
tiff = append(tiff, entry...)
app1Data := append([]byte("Exif\x00\x00"), tiff...)
segLen := len(app1Data) + 2
out := []byte{0xFF, 0xD8} // SOI
out = append(out, 0xFF, 0xE1)
lenB := make([]byte, 2)
binary.BigEndian.PutUint16(lenB, uint16(segLen))
out = append(out, lenB...)
out = append(out, app1Data...)
out = append(out, 0xFF, 0xD9) // EOI
return out
}
func TestReadExifOrientation(t *testing.T) {
dir := t.TempDir()
cases := []struct {
name string
ori uint16
bigEnd bool
want int
}{
{"le6", 6, false, 6},
{"be8", 8, true, 8},
{"le1", 1, false, 1},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
p := filepath.Join(dir, c.name+".jpg")
if err := os.WriteFile(p, buildJpegWithOrientation(t, c.ori, c.bigEnd), 0644); err != nil {
t.Fatal(err)
}
if got := ReadExifOrientation(p); got != c.want {
t.Fatalf("ReadExifOrientation = %d, want %d", got, c.want)
}
})
}
// 非 JPEG 返回 0
p := filepath.Join(dir, "notjpeg.txt")
if err := os.WriteFile(p, []byte("hello"), 0644); err != nil {
t.Fatal(err)
}
if got := ReadExifOrientation(p); got != 0 {
t.Fatalf("non-jpeg ReadExifOrientation = %d, want 0", got)
}
// 不存在的文件返回 0
if got := ReadExifOrientation(filepath.Join(dir, "missing.jpg")); got != 0 {
t.Fatalf("missing ReadExifOrientation = %d, want 0", got)
}
}
func TestNeedsDimensionSwap(t *testing.T) {
cases := map[int]bool{
1: false, 2: false, 3: false, 4: false,
5: true, 6: true, 7: true, 8: true,
0: false, 9: false,
}
for ori, want := range cases {
if got := NeedsDimensionSwap(ori); got != want {
t.Fatalf("NeedsDimensionSwap(%d) = %v, want %v", ori, got, want)
}
}
}