Files
kenaito-media-picker/internal/probe/bmp.go
T
odboy 7e49accf2b fix: BMP头解析、移动语义与空文件处理
- probe/bmp: 兼容 BITMAPCOREHEADER(12B) 等 info 头变体,按 Size 字段分支解析
- mover: moveOne 返回三态结果,复制成功但删源失败时明确告警,不再静默视为完全成功
- scanner: 跳过 0 字节文件,避免空文件进入 MIME/ffprobe 探测
2025-04-15 21:05:26 +08:00

69 lines
1.7 KiB
Go

package probe
import (
"encoding/binary"
"fmt"
"os"
)
// probeBmp 读取 BMP 文件头中的宽高;自顶向下 BMP 的高度为负值,取绝对值。
// 兼容常见 info 头:BITMAPCOREHEADER(12B, OS/2)、BITMAPINFOHEADER(40B) 及更长的 V4/V5 变体。
func probeBmp(filePath string) (*ProbeResult, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
var fileHeader struct {
FileType [2]byte
FileSize uint32
Reserved1 uint16
Reserved2 uint16
DataOffset uint32
}
if err := binary.Read(f, binary.LittleEndian, &fileHeader); err != nil {
return nil, err
}
if string(fileHeader.FileType[:]) != "BM" {
return nil, fmt.Errorf("not a valid BMP file")
}
var infoSize uint32
if err := binary.Read(f, binary.LittleEndian, &infoSize); err != nil {
return nil, err
}
switch {
case infoSize >= 40:
// BITMAPINFOHEADER(40B)/BITMAPV4HEADER(108B)/BITMAPV5HEADER(124B)/OS2(64B):宽高为 int32
var width, height int32
if err := binary.Read(f, binary.LittleEndian, &width); err != nil {
return nil, err
}
if err := binary.Read(f, binary.LittleEndian, &height); err != nil {
return nil, err
}
return &ProbeResult{Width: abs32(width), Height: abs32(height)}, nil
case infoSize >= 12:
// BITMAPCOREHEADER(12B, OS/2 1.x):宽高为 uint16
var width, height uint16
if err := binary.Read(f, binary.LittleEndian, &width); err != nil {
return nil, err
}
if err := binary.Read(f, binary.LittleEndian, &height); err != nil {
return nil, err
}
return &ProbeResult{Width: int(width), Height: int(height)}, nil
default:
return nil, fmt.Errorf("unsupported BMP info header size: %d", infoSize)
}
}
func abs32(v int32) int {
if v < 0 {
return int(-v)
}
return int(v)
}