2012-04-27 89 views
10

我想从jpegs中提取缩略图图像,无需任何外部库。我的意思是这并不难,因为我需要知道缩略图的起始位置,并在文件中结束,并简单地剪切它。我研究了许多文档(例如:http://www.media.mit.edu/pia/Research/deepview/exif.html),并尝试分析jpegs,但并非一切都清楚。我试图跟踪字节的一步一步,但在深深的我困惑。是否有任何良好的文档或可读的源代码来提取有关jpeg文件中缩略图开始和结束位置的信息?从jpeg文件中提取缩略图

谢谢!

+1

至少有3个地方,其可以存储缩略图JPEG图像:JFIF/APP0 ,EXIF APP1和ADEOBE APP13。这里http://javagraphics.blogspot.ca/2010/03/images-reading-jpeg-thumbnails.html是一个关于它的博客,你也可以找到这个https://github.com/dragon66/icafe/wiki有用。 – dragon66 2014-10-06 21:04:37

回答

11

对于由电话或数码相机创建的大多数JPEG图像,缩略图图像(如果存在)存储在APP1标记(FFE1)中。该标记段内有一个TIFF文件,其中包含主图像的EXIF信息以及作为JPEG压缩图像存储的可选缩略图图像。 TIFF文件通常包含两个“页面”,其中第一页是EXIF信息,第二页是以“旧”TIFF类型6格式存储的缩略图。类型6格式是当JPEG文件原样存储在TIFF包装器中时。如果您希望最简单的代码将缩略图提取为JFIF,则需要执行以下步骤:

  1. 熟悉JFIF和TIFF标记/标记。 JFIF标记由两个字节组成:0xFF后跟标记类型(APP1的0xE1)。这两个字节之后是以big-endian顺序存储的两字节长度。对于TIFF文件,请参阅Adobe TIFF 6.0参考。
  2. 在您的JPEG文件中搜索APP1(FFE1)EXIF标记。可能有多个APP1标记,APP1之前可能有多个标记。
  3. 您正在查找的APP1标记包含紧跟在长度字段后面的字母“EXIF”。
  4. 查找“II”或“MM”(距离长度6个字节)以指示TIFF文件中使用的字节顺序。 II = Intel =小端,MM =摩托罗拉=大端。
  5. 跳过第一页的标签,找到存储图像的第二个IFD。在第二个“页面”中,查找指向JPEG数据的两个TIFF标签。标记0x201具有JPEG数据的偏移量(相对于II/MM),标记0x202具有以字节为单位的长度。
+2

可能还会指出Exif数据中可能存在多个降低分辨率的图像。例如在Nikon JPEG文件中,有一个缩略图和第二个(较大的)预览图像。唯一的限制是总Exif数据不能超过64,000字节。还有一点 - 如你所说,Exif数据可以是小尾数或大尾数。但是,JPEG标记和数据以及缩略图数据总是大端的。诸如0xFFE1(APP1标记)的标记由JPEG标准ISO DIS 10918-1定义并可在线获得。 – 2012-04-30 19:09:10

+1

谢谢你,我帮你成功地写了代码! – 2012-05-08 14:05:02

+0

谢谢你,这是非常明确的 – 2016-11-10 11:11:36

-1

JFIF上的维基百科页面http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format给出了JPEG Header的一个很好的描述(标题包含缩略图作为未压缩的光栅图像)。这应该给你一个布局的想法,因此需要提取信息的代码。

进制打印图像头(小端显示器):

[email protected]:~$ 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 

图片魔(字节1,0),APP0段头的幻(字节3,2),报头长度(5,4)报头类型签名(“JFIF \ 0”||“JFXX \ 0”)(字节6-10),版本(字节11,12)密度单位(字节13),X密度(字节15,14),Y密度(字节17,16),缩略图宽度(字节19),缩略图高度(字节18)以及最后休息到“标题长度”是缩略图数据。

从以上示例中,可以看到标题长度为16个字节(字节6,5),版本为01.01(字节12,13)。此外,由于缩略图宽度和缩略图高度都是0x00,图像不包含缩略图。

+0

您对JFIF标头的分析不正确。 JPEG文件通常包含JPEG压缩的缩略图图像。缩略图的宽度和高度作为TIFF文件的一部分存储在APP1标记中。您可以在偏移量为0x1E的转储中看到TIFF头“II”的开头,后面跟着版本0x2a和IFD偏移0x0008。 – BitBank 2012-04-27 18:00:15

+0

我的分析是基于http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format上的信息以及jpeg标准http://www.ecma-international.org/publications/files/ECMA-TR/TR -098.pdf第10节(第5页)。请详细说明您的信息来源。您可能在谈论JFIF扩展(JFXX)段格式,而上面的示例是JFIF段格式(字节偏移量0x06-0x10是“JFIF \ 0”) – Samveen 2012-04-27 19:58:21

+1

缩略图信息可能在规范中,但这是而不是如何在现实世界中使用它。我从来没有见过带有APP0头缩略图的JPEG图像。它作为TIFF文件的一部分存储(通常压缩)在EXIF(APP1)头中,其中包含其他EXIF信息作为TIFF标签。发布您在上面引用的文件,然后我会告诉你它里面有什么。 – BitBank 2012-04-27 20:29:29

4

这个问题有一个更简单的解决方案,但我不知道它有多可靠:从第三个字节开始读取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 
    } 
} 
+0

很好的简单代码的概念证明,但这大约有1/20照片我有,因为我不认为你可以保证0xFFD8不会出现在其他地方。 – 2016-03-16 08:57:18

11

Exiftool是非常有能力快速,轻松地这样做的:

exiftool -b -ThumbnailImage my_image.jpg > my_thumbnail.jpg 
+4

您应该使用'exiftool -a -b -W%d%f_%t%-c。%s -preview:all YourFileOrDirectory'来提取每个缩略图变体。 – tricasse 2017-05-18 12:14:24

+2

ExifTool中可用的缩略图类型可以通过'exiftool -list -preview:all'列出。 – tricasse 2017-05-18 13:31:08