jpeg Exif file format Marker APP1 简介
jpeg Exif file format Marker APP1 分析
参考: Description of Exif file format
Exif 文件格式与 JPEG 文件格式相同。 Exif 按照JPEG规范将图片的相关信息数据和缩略图图像插入JPEG。 因此可以使用 Internet 浏览器/图片浏览器/照片修饰软件等查看Exif格式的图像文件。
- 图片的相关信息: 制造商、日期、曝光时间、焦距、光圈值等信息。
JPEG 的数据流如下:
Exif 数据结构:
Exif(APP1)基本结构如下面的表格所示:
TIFF Header:
TiFF header 指的是 TIFF 格式的前 8 个字节,前两个定义了 TIFF 数据采用何种字节顺序:
- 如果是
0x4949
= II,表示采用 Inter 的小端字节顺序(49 49:01001001 01001001
); - 如果为
0x4d4d
= MM,表示采用 Motorola 的大端字节顺序(4d 4d:01001101 01001101
);
例如:十进制值 305419896
的十六进制表示是:12345678
,如果以 Motroal 式的 big-endian 进行存储,对应的 code unit 就是 0x12 0x34 0x56 0x78
;而如果是 Intel 式的 little-endian 进行存储,则对应 0x78 0x56 0x34 0x12
。
IFD : Image file directory
以上表格中:
TTTT
(2 个字节)表示的是 Tag number,表示一种类型的数据;ffff
(2 个字节)表示数据的格式;- NNNNNNNN 4byte :表示所组成元素的数量,实际长度 = 元素个数 x 数据格式, 如 unsigned long 占 4 byte (4N)
- DDDDDDDD 4byte :表示所包含数据的长度,或者是数据存储地址的偏移量。如果总数据长度小于4字节,则“DDDDDDDD”存储该标记的值。如果其大小超过4字节,'DDDDDDDD'存储数据存储地址的偏移量。偏移的基准是 TIFF header (0x0C)
数据格式
IFD data structure
在 Exif 格式中,第一个图像文件目录(IFD)是 IFD0(主图像的 IFD),之后是 IFD1(缩略图的 IFD),接着图像文件目录链(IFD link)结束。IFD0/IFD1 中没有快门速度(shutter speed),焦距(focal length)等任何关于数码相机的信息。IFD0 有一个特别的标签(Tag)Exif Offset(0x8769),在这个标签中是 Exif SubIFD 的偏移量。Exif SubIFD 的数据格式也是 IFD 的数据格式,它包含了数码相机的相关信息。
IFD 标签
详细信息参阅:Description of Exif file format
libexif是一个用于解析,编辑和保存EXIF数据的库 https://github.com/libexif/libexif libexif API
下面用 C 语言结构体描述 IFD 便签的信息。
// uint16_t app1_length[2]; // short , 数据长度
typedef struct IFD
{uint16_t tagNO; // 标签编号uint16_t format; // 数据格式uint32_t length; // 数据长度uint32_t offset; // 数据偏移量,基地址 0x0C (Byte align)char tagName[50]; // 标签名
} IFD_S;static const IFD_S IFD0[] =
{{0x010e, 2, 32, 0x0C, "ImageDescription"}, // 图片信息{0x010f, 2, 32, 0x0C, "Make"}, //相机制造商信息{0x0110, 2, 32, 0x0C, "Model"}, //相机模组信息{0x0112, 3, 2, 0x0C, "Orientation"}, // 方向{0x011a, 5, 8, 0x0C, "XResolution"}, // X分辨率{0x011b, 5, 8, 0x0C, "YResolution"}, // Y分辨率{0x0128, 3, 2, 0x0C, "ResolutionUnit"}, // 分辨率单位, 1'表示无单位,'2'表示英寸,'3'表示厘米{0x0131, 2, 32, 0x0C, "Software"}, // 软件{0x0132, 2, 20, 0x0C, "DateTime"}, // 日期{0x013e, 5, 8 * 2, 0x0C, "WhitePoint"}, // 照度{0x013f, 5, 8 * 6, 0x0C, "PrimaryChromaticities"}, // 色度{0x0211, 5, 8 * 3, 0x0C, "YCbCrCoefficients"}, // YCbCrCoefficients 颜色空间转换矩阵系数{0x0213, 3, 2, 0x0C, "YCbCrPositioning"}, // YCbCrPositioning 色相定位,色相配置{0x0214, 5, 8 * 5, 0x0C, "ReferenceBlackWhite"}, // ReferenceBlackWhite 黑白参照值{0x8298, 2, 32, 0x0C, "Copyright"}, // 版权{0x8769, 4, 4, 0x0C, "ExifOffset"}, // Offset to Exif Sub IFD
};static const IFD_S subIFD[] =
{{0x829a, 5, 8, 0x0C, "ExposureTime"}, // 曝光时间{0x829d, 5, 8, 0x0C, "FNumber"}, // 光圈值{0x8822, 3, 2, 0x0C, "ExposureProgram"}, // 曝光模式{0x8827, 3, 2 * 2, 0x0C, "ISOSpeedRatings"}, // 感光度{0x9000, 7, 1 * 4, 0x0C, "ExifVersion"}, // Exif 版本{0x9003, 2, 20, 0x0C, "DateTimeOriginal"}, // 拍摄日期{0x9004, 2, 20, 0x0C, "DateTimeDigitized"}, // 数字日期{0x9101, 7, 1 * 4, 0x0C, "ComponentConfiguration"}, // ComponentConfiguration{0x9102, 5, 8, 0x0C, "CompressedBitsPerPixel"}, // 压缩时每像素色彩位{0x9201, 10, 8, 0x0C, "ShutterSpeedValue"}, // 快门速度{0x9202, 5, 8, 0x0C, "ApertureValue"}, // 光圈值{0x9203, 10, 8, 0x0C, "BrightnessValue"}, // 亮度值{0x9204, 10, 8, 0x0C, "ExposureBiasValue"}, // 曝光补偿{0x9205, 5, 8, 0x0C, "MaxApertureValue"}, // 最大光圈{0x9206, 10, 8, 0x0C, "SubjectDistance"}, // 物距{0x9207, 3, 2, 0x0C, "MeteringMode"}, // 曝光模式{0x9208, 3, 2, 0x0C, "LightSource"}, // 光源{0x9209, 3, 2, 0x0C, "Flash"}, // 闪光灯{0x920a, 5, 8, 0x0C, "FocalLength"}, // 焦距{0x927c, 7, 1, 0x0C, "MakerNote"}, // 制造商注释{0x9286, 7, 1, 0x0C, "UserComment"}, // 自定义注释{0xa000, 7, 1 * 4, 0x0C, "FlashPixVersion"}, // FlashPix版本{0xa001, 3, 2, 0x0C, "ColorSpace"}, // 色彩空间{0xa002, 3, 2, 0x0C, "ExifImageWidth"}, // Exif 图像宽度{0xa003, 3, 2, 0x0C, "ExifImageHeight"}, // Exif 图像高度{0xa004, 2, 32, 0x0C, "RelatedSoundFile"}, // 关联的声音文件{0xa005, 4, 4, 0x0C, "ExifInteroperabilityOffset"}, // 焦距平面X轴解析度{0xa20e, 5, 8, 0x0C, "FocalPlaneXResolution"}, // 焦距平面Y轴解析度{0xa20f, 5, 8, 0x0C, "FocalPlaneYResolution"}, // 焦距平面解析度单位{0xa210, 3, 2, 0x0C, "FocalPlaneResolutionUnit"}, // 焦距平面解析度单位{0xa217, 3, 2, 0x0C, "SensingMethod"}, // 显示图像传感器单元的类型{0xa300, 7, 1, 0x0C, "FileSource"}, // 源文件{0xa301, 7, 1, 0x0C, "SceneType"}, // 场景类型
};static const IFD_S IFD1[] =
{{0x0100, 3, 2, 0x0C, "ImageWidth"}, // 图像宽度{0x0101, 3, 2, 0x0C, "ImageLength"}, // 图像高度{0x0102, 3, 2 * 3, 0x0C, "BitsPerSample"}, // 比特采样率/每个像素点位数{0x0103, 3, 2, 0x0C, "Compression"}, // 压缩比{0x0106, 3, 2, 0x0C, "PhotometricInterpretation"}, // 像素合成{0x0111, 3, 2, 0x0C, "StripOffsets"}, // 长度不定, 图像资料位置,条的偏移量{0x0115, 3, 2, 0x0C, "SamplesPerPixel"}, // 像素数{0x0116, 3, 2, 0x0C, "RowsPerStrip"}, // Strip 行数{0x0117, 3, 2, 0x0C, "StripByteConunts"}, // 长度不定 , Strip 字节数{0x011a, 5, 8, 0x0C, "XResolution"}, // X 水平分辨率{0x011b, 5, 8, 0x0C, "YResolution"}, // Y 水平分辨率{0x011c, 3, 2, 0x0C, "PlanarConfiguration"}, // 平面配置{0x0128, 3, 2, 0x0C, "ResolutionUnit"}, // 解析度,分辨率单位{0x0201, 4, 4, 0x0C, "JpegIFOffset"}, // JPEG 偏移量{0x0202, 4, 4, 0x0C, "JpegIFByteCount"}, // JPEG 图像数据大小{0x0211, 5, 8 * 3, 0x0C, "YCbCrCoefficients"}, // 颜色空间转换矩阵系数{0x0212, 3, 2 * 2, 0x0C, "YCbCrSubSampling"}, // 色相抽样比率{0x0213, 3, 2, 0x0C, "YCbCrPositioning"}, // 色相定位,色相配置{0x0214, 5, 8 * 6, 0x0C, "ReferenceBlackWhite"}, // 黑白参照值};static const IFD_S miscTags[] =
{{0x00fe, 4, 4, 0x0C, "NewSubfileType"}, // 新的子文件类型{0x00ff, 3, 2, 0x0C, "SubfileType"}, // 子文件类型{0x012d, 3, 2 * 3, 0x0C, "TransferFunction"}, // 传输函数{0x013b, 2, 32, 0x0C, "Artist"}, // 艺术家{0x013d, 3, 2, 0x0C, "Predictor"}, // 预测器{0x0142, 3, 2, 0x0C, "TileWidth"}, // Tile 宽度{0x0143, 3, 2, 0x0C, "TileLength"}, // Tile 高度{0x0144, 4, 4, 0x0C, "TileOffsets"}, // 长度不定, Tile 偏移量{0x0145, 3, 2, 0x0C, "TileByteCounts"}, // 长度不定, Tile 字节数{0x014a, 4, 4, 0x0C, "SubIFDs"}, // 长度不定,{0x015b, 7, 1, 0x0C, "JPEGTables"}, // 长度不定,JPEG 表格/附录{0x828d, 3, 2 * 2, 0x0C, "CFARepeatPatternDim"}, //{0x828e, 1, 1, 0x0C, "CFAPattern"}, //{0x828f, 3, 2, 0x0C, "BatteryLevel"}, // 电池电量{0x83bb, 5, 8, 0x0C, "IPTC//NAA"}, // 长度不定{0x8773, 7, 1, 0x0C, "InterColorProfile"}, // 长度不定{0x8824, 2, 32, 0x0C, "SpectralSensitivity"}, // 光谱灵敏度,光谱感光度{0x8825, 4, 4, 0x0C, "GPSInfo"}, //{0x8828, 7, 1, 0x0C, "OECF"}, // 长度不定{0x8829, 3, 2, 0x0C, "Interlace"}, // Interlace 交错{0x882a, 3, 2, 0x0C, "TimeZoneOffset"}, // 时区偏移量{0x882b, 3, 2, 0x0C, "SelfTimerMode"}, // 自拍模式{0x920b, 5, 8, 0x0C, "FlashEnergy"}, // 闪光灯强度{0x920c, 7, 1, 0x0C, "SpatialFrequencyResponse"}, // 长度不定, 空间频率反应{0x920d, 7, 1, 0x0C, "Noise"}, // 长度不定, 噪声{0x9211, 4, 4, 0x0C, "ImageNumber"}, // 图像编号{0x9212, 2, 1, 0x0C, "SecurityClassification"}, // 安全等级{0x9213, 2, 32, 0x0C, "ImageHistory"}, //{0x9214, 3, 2 * 4, 0x0C, "SubjectLocation"}, // 物体位置{0x9215, 5, 8, 0x0C, "ExposureIndex"}, // 曝光指数{0x9216, 1, 1 * 4, 0x0C, "TIFF//EPStandardID"}, //{0x9290, 2, 32, 0x0C, "SubSecTime"}, //{0x9291, 2, 32, 0x0C, "SubSecTimeOriginal"}, //{0x9292, 2, 32, 0x0C, "SubSecTimeDigitized"}, //{0xa20b, 5, 8, 0x0C, "FlashEnergy"}, // 闪光灯强度{0xa20c, 3, 2, 0x0C, "SpatialFrequencyResponse"}, // 空间频率反应{0xa214, 3, 2, 0x0C, "SubjectLocation"}, // 物体位置{0xa215, 5, 8, 0x0C, "ExposureIndex"}, // 曝光指数{0xa302, 7, 1, 0x0C, "CFAPattern"}, //
};