我想从 jpegs 中提取缩略图,没有任何外部库。我的意思是这并不太难,因为我需要知道缩略图从哪里开始,在文件中结束,然后简单地剪切它。我研究了许多文档(即:http ://www.media.mit.edu/pia/Research/deepview/exif.html ),并尝试分析 jpeg,但并非一切都清楚。我试图一步一步地跟踪字节,但在深处我感到困惑。是否有任何好的文档或可读的源代码来提取 jpeg 文件中有关缩略图开始和结束位置的信息?
谢谢!
Exiftool非常有能力快速轻松地做到这一点:
exiftool -b -ThumbnailImage my_image.jpg > my_thumbnail.jpg
对于由手机或数码相机创建的大多数 JPEG 图像,缩略图(如果存在)存储在 APP1 标记 (FFE1) 中。此标记段内部是一个 TIFF 文件,其中包含主图像的 EXIF 信息和存储为 JPEG 压缩图像的可选缩略图图像。TIFF 文件通常包含两个“页面”,其中第一页是 EXIF 信息,第二页是以“旧”TIFF 类型 6 格式存储的缩略图。类型 6 格式是指 JPEG 文件按原样存储在 TIFF 包装器内。如果您想要最简单的代码将缩略图提取为 JFIF,则需要执行以下步骤:
这个问题有一个更简单的解决方案,但我不知道它有多可靠:从第三个字节开始读取 JPEG 文件并搜索 FFD8(JPEG 图像标记的开始),然后搜索 FFD9(JPEG 图像的结尾标记)。提取它,瞧,这就是你的缩略图。
一个简单的 JavaScript 实现:
function getThumbnail(file, callback) {
if (file.type == "image/jpeg") {
var reader = new FileReader();
reader.onload = function (e) {
var array = new Uint8Array(e.target.result),
start, end;
for (var i = 2; i < array.length; i++) {
if (array[i] == 0xFF) {
if (!start) {
if (array[i + 1] == 0xD8) {
start = i;
}
} else {
if (array[i + 1] == 0xD9) {
end = i;
break;
}
}
}
}
if (start && end) {
callback(new Blob([array.subarray(start, end)], {type:"image/jpeg"}));
} else {
// TODO scale with canvas
}
}
reader.readAsArrayBuffer(file.slice(0, 50000));
} else if (file.type.indexOf("image/") === 0) {
// TODO scale with canvas
}
}
JFIF 上的维基百科页面http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format很好地描述了 JPEG 标头(标头包含作为未压缩光栅图像的缩略图)。这应该让您了解布局以及提取信息所需的代码。
图像标题的十六进制转储(小端显示):
sdk@AndroidDev:~$ head -c 48 stfu.jpg |hexdump
0000000 d8ff e0ff 1000 464a 4649 0100 0101 4800
0000010 4800 0000 e1ff 1600 7845 6669 0000 4d4d
0000020 2a00 0000 0800 0000 0000 0000 feff 1700
Image Magic (bytes 1,0), App0 Segment header Magic(bytes 3,2), Header Length (5,4) Header Type signature ("JFIF\0"||"JFXX\0")(bytes 6-10) , Version (bytes 11,12) Density units (byte 13), X Density (bytes 15,14), Y Density (bytes 17,16), Thumbnail width (byte 19), Thumbnail height (byte 18), 最后是rest最多“标题长度”是缩略图数据。
从上面的例子中可以看出,header 长度为 16 字节(字节 6,5),版本为 01.01(字节 12,13)。此外,由于缩略图宽度和缩略图高度均为 0x00,因此图像不包含缩略图。