Fix ZeroDivisionError on files containing images drawn at scale 0

Fixes #761
This commit is contained in:
James R. Barlow
2021-04-15 23:26:14 -07:00
parent d89a633ba7
commit d673126994
3 changed files with 37 additions and 5 deletions
+5 -1
View File
@@ -15,7 +15,7 @@ from collections.abc import Iterable
from contextlib import suppress
from functools import wraps
from io import StringIO
from math import isclose
from math import isclose, isfinite
from pathlib import Path
from typing import Any, Sequence
@@ -39,6 +39,10 @@ class Resolution(namedtuple('Resolution', ('x', 'y'))):
def is_square(self) -> bool:
return isclose(self.x, self.y, rel_tol=1e-3)
@property
def is_finite(self) -> bool:
return isfinite(self.x) and isfinite(self.y)
def take_max(self, vals, yvals=None):
if yvals is not None:
return Resolution(max(self.x, *vals), max(self.y, *yvals))
+11 -4
View File
@@ -14,7 +14,7 @@ from contextlib import ExitStack
from decimal import Decimal
from enum import Enum
from functools import partial
from math import hypot, isclose
from math import hypot, isclose, ulp
from os import PathLike
from pathlib import Path
from typing import Container, Iterator, Optional, Tuple, Union
@@ -260,8 +260,9 @@ def _get_dpi(ctm_shorthand, image_size) -> Resolution:
image_drawn_height = hypot(c, d)
# The scale of the image is pixels per unit of default user space (1/72")
scale_w = image_size[0] / image_drawn_width
scale_h = image_size[1] / image_drawn_height
# use ulp to turn divide by zero into infinity
scale_w = image_size[0] / (image_drawn_width + ulp(0))
scale_h = image_size[1] / (image_drawn_height + ulp(0))
# DPI = scale * 72
dpi_w = scale_w * 72.0
@@ -365,6 +366,10 @@ class ImageInfo:
def enc(self):
return self._enc
@property
def renderable(self):
return self.dpi.is_finite and self.width >= 0 and self.height >= 0
@property
def dpi(self):
return _get_dpi(self._shorthand, (self._width, self._height))
@@ -734,7 +739,9 @@ class PageInfo:
self._dpi = None
if self._images:
dpi = Resolution(0.0, 0.0).take_max(image.dpi for image in self._images)
dpi = Resolution(0.0, 0.0).take_max(
image.dpi for image in self._images if image.renderable
)
self._dpi = dpi
self._width_pixels = int(round(dpi.x * float(self._width_inches)))
self._height_pixels = int(round(dpi.y * float(self._height_inches)))
+21
View File
@@ -17,6 +17,7 @@ from reportlab.pdfgen.canvas import Canvas
from ocrmypdf import pdfinfo
from ocrmypdf.exceptions import InputFileError
from ocrmypdf.helpers import Resolution
from ocrmypdf.pdfinfo import Colorspace, Encoding
from ocrmypdf.pdfinfo.layout import PDFPage
@@ -194,3 +195,23 @@ def test_pages_issue700(monkeypatch, resources):
progbar=False,
max_workers=1,
)
def test_image_scale0(resources, outpdf):
with pikepdf.open(resources / 'cmyk.pdf') as cmyk:
xobj = pikepdf.Page(cmyk.pages[0]).as_form_xobject()
p = pikepdf.Pdf.new()
p.add_blank_page(page_size=(72, 72))
objname = pikepdf.Page(p.pages[0]).add_resource(
p.copy_foreign(xobj), pikepdf.Name.XObject, pikepdf.Name.Im0
)
print(objname)
p.pages[0].Contents = pikepdf.Stream(
p, b"q 0 0 0 0 0 0 cm %s Do Q" % bytes(objname)
)
p.save(outpdf)
pi = pdfinfo.PdfInfo(outpdf, detailed_analysis=True, progbar=False, max_workers=1)
assert not pi.pages[0]._images[0].dpi.is_finite
assert pi.pages[0].dpi == Resolution(0, 0)