如何提取 PDF 提取图像的 rotation/transformation 信息(即查看者如何知道旋转 180 )

How to extract rotation/transformation information for PDF extracted images (i.e. How does viewers know to rotate 180 )

我正在使用生成 PDF-1.3 的 ScanSnap 扫描仪,当在 Adob​​e Reader 中查看 PDF 时,它会自动更正扫描文档的方向(旋转 0 或 180 度)。 OCR 由扫描软件完成,我假设方向已确定并编码到 PDF 中。

请注意,我知道我可以使用 Tesseract 或其他 OCR 工具来确定是否需要旋转,但我不想使用它,因为扫描仪软件似乎已经确定并告诉 PDF 查看器是否需要旋转(或不)。

当我使用图像提取工具(如 xpdf pdfimages、python 库)时,它无法将 jpeg 图像正确旋转 180 度(如果需要)。

NB: pdfimages extracts the raw image data from the PDF file, without performing any additional transforms. Any rotation, clipping, color inversion, etc. done by the PDF content stream is ignored.

我旋转扫描了文档两次(0 度和 180 度)。 我似乎无法对告诉 Adobe/Foxit 在查看时旋转(或不旋转)图像的内容进行逆向工程。我查看了 PDF-1.3 规范文档,并比较了方向校正和未校正的 PDF 二进制数据。我无法确定什么是纠正方向?

在这两种情况下,PDF 二进制文件如下所示(停在 JPEG 流数据处)

更新: PDF 文件链接 rotated-180 rotated-0

%PDF-1.3
%âãÏÓ
1 0 obj
<</Metadata 20 0 R/Pages 2 0 R/Type/Catalog>>
endobj
2 0 obj
<</MediaBox[0.0 0.0 606.6 794.88]/Count 1/Type/Pages/Kids[4 0 R]>>
endobj
4 0 obj
<</Parent 2 0 R/Contents 18 0 R/PieceInfo<</PSL<</Private<</V(3.2.9)>>/LastModified(D:20190201125524-00'00')>>>>/MediaBox[0.0 0.0 606.6 794.88]/Resources<</XObject<</Im0 5 0 R>>/Font<</C0_0 11 0 R/T1_0 16 0 R>>/ProcSet[/PDF/Text/ImageC]>>/Type/Page/LastModified(D:20190201085524-04'00')>>
endobj
5 0 obj
<</Subtype/Image/Length 433576/Filter/DCTDecode/Name/X/BitsPerComponent 8/ColorSpace/DeviceRGB/Width 1685/Height 2208/Type/XObject>>stream

有谁知道 PDF 查看器如何知道将图像旋转 180 度(或不旋转)。它是 PDF 或 JPEG 图像中可以提取的元数据吗? Adob​​e 和其他查看器是否会在打开文档时动态执行某些操作以确定是否需要方向校正?

我不是 PDF 规范方面的专家。但我希望有人可能已经找到了解决这个问题的方法。

"internetfile-180.pdf"中页面资源中的图片im0没有旋转:

但是"internetfile.pdf"中页面资源中的图片im0被旋转了:

在查看器中两者看起来都是直立的,因此在 "internetfile.pdf" 中必须使用旋转图像的技术。

有两种主要技术:

  • 相应地设置页面的旋转 属性,即这里设置为180。
  • 正在对页面内容流中的当前变换矩阵应用旋转变换。

我们先看一下页面字典,印刷得漂亮一点:

4 0 obj
<<
  /Parent 2 0 R
  /Contents 13 0 R
  /PieceInfo
  <<
    /PSL
    <<
      /Private <</V (3.2.9)>>
      /LastModified (D:20190204142537-00'00')
    >>
  >>
  /MediaBox [0.0 0.0 608.64 792.24]
  /Resources
  <<
    /XObject <</Im0 5 0 R>>
    /Font <</T1_0 11 0 R>>
    /ProcSet [/PDF /Text /ImageC]
  >>
  /Type /Page
  /LastModified (D:20190204102537-04'00')
>> 

如我们所见,不存在 旋转 条目。因此,我们必须查看页面内容流。根据页面字典,它在对象 13,第 0 代中。

该对象是一个带有压缩流数据的流对象:

13 0 obj
<<
  /Length 4014
  /Filter /FlateDecode
>>
stream
H‰”WÛŽÛF}Ÿ¯Ð[lÀÓÓ÷˾e½
[...]
ÿüòÛÿ ´ß
endstream
endobj 

对流数据进行膨胀后,它们是这样开始的:

q
-608.3999939 0 0 -792.9600067 608.3999939 792.9600067 cm
/Im0 Do
Q
[...]

这确实是第二种技术的应用,cm指令应用旋转,Do指令用旋转激活!

具体来说,cm指令应用矩阵

表示的仿射变换
-608.3999939    0            0
   0         -792.9600067    0
 608.3999939  792.9600067    1

换句话说:

x' = -608.3999939 * x + 608.3999939
y' = -792.9600067 * y + 792.9600067

这个变换实际上是旋转180°,水平缩放608.3999939,垂直缩放792.9600067,水平平移608.3999939,垂直平移792.9600067的组合。

Do 指令现在绘制图像。这里需要知道的是,该指令首先将图像缩放到原点处的1×1正方形单元,然后应用当前变换矩阵。

因此,图像被旋转180°绘制,有效地填充了整个页面的608.64×792.24 MediaBox

mkl 正确回答了问题,为我完成了所有艰苦的 PDF 解码工作。

我想我会添加我的 python (PyPDF2) 代码来搜索找到的旋转条件,以防它帮助其他人。

input1 = PyPDF2.PdfFileReader(open(filepath, "rb"))
totalPages = input1.getNumPages()
for pgNum in range(0,totalPages):
    page0 = input1.getPage(pgNum)

    # Lets look to see if the page contains a transformation matrix to rotate it 180 degress 
    # (ScanScap iX500 encoded the PDF with a cm transformation matrix to rotate 180 degrees in PDF viewers
    # @see 
    # @see 'PDF 1.3 Reference Manual March 11, 1999' Section 3.10 Transformation matrices which is applied to the scanned image
    #                                          [[a b 0]
    #                                           [c d 0]
    #                                           [e f 1]] 
    isPageRotated180 = False
    pgContent = page0['/Contents'].getData().decode('utf-8')
    FLOAT_REG = '([-+]?\d*\.\d+|\d+)'
    m = re.search( '{} {} {} {} {} {} cm'.format(FLOAT_REG,FLOAT_REG,FLOAT_REG,FLOAT_REG,FLOAT_REG,FLOAT_REG), pgContent )
    if m:
        (a,b,c,d,e,f) = list(map(float,m.groups()))
        isPageRotated180 = (a == -e and d == -f)