Skip to content

Commit

Permalink
BUG: Format floats using their intrinsic decimal precision (#1267)
Browse files Browse the repository at this point in the history
Since FloatObject is represented as a decimal, format numbers using their intrinsic precision, instead of reducing the precision to 5 decimal places.

This fixes rendering issues for PDFs that contain coordinates, transformations, etc. with real numbers containing more than 5 decimal places of precision. For example, PDFs exported from Microsoft PowerPoint contain numbers with up to 11 decimal places.

Fixes #1266
  • Loading branch information
programmarchy committed Sep 18, 2022
1 parent 71de6c8 commit 5aeb926
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 7 deletions.
5 changes: 4 additions & 1 deletion PyPDF2/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1921,8 +1921,11 @@ def _create_outline_item(
if color:
if isinstance(color, str):
color = hex_to_rgb(color)
prec = decimal.Decimal('1.00000')
outline_item.update(
{NameObject("/C"): ArrayObject([FloatObject(c) for c in color])}
{NameObject("/C"): ArrayObject([
FloatObject(decimal.Decimal(c).quantize(prec)) for c in color
])}
)
if italic or bold:
format_flag = 0
Expand Down
10 changes: 4 additions & 6 deletions PyPDF2/generic/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,12 @@ def __new__(

def __repr__(self) -> str:
if self == self.to_integral():
# If this is an integer, format it with no decimal place.
return str(self.quantize(decimal.Decimal(1)))
else:
# Standard formatting adds useless extraneous zeros.
o = f"{self:.5f}"
# Remove the zeros.
while o and o[-1] == "0":
o = o[:-1]
return o
# Otherwise, format it with a decimal place, taking care to
# remove any extraneous trailing zeros.
return f"{self:f}".rstrip("0")

def as_numeric(self) -> float:
return float(repr(self).encode("utf8"))
Expand Down
32 changes: 32 additions & 0 deletions tests/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,3 +869,35 @@ def test_create_string_object_force():
assert create_string_object(b"Hello World", []) == "Hello World"
assert create_string_object(b"Hello World", {72: "A"}) == "Aello World"
assert create_string_object(b"Hello World", "utf8") == "Hello World"


@pytest.mark.parametrize(
("value", "expected"),
[
("0.000000", "0"),
("0.0", "0"),
("1.0", "1"),
("0.123000", "0.123"),
("0.000123000", "0.000123"),
("0.0", "0"),
("0", "0"),
("1", "1"),
("1.0", "1"),
("1.01", "1.01"),
("1.010", "1.01"),
("0000.0000", "0"),
("0.10101010", "0.1010101"),
("50000000000", "50000000000"),
("99900000000000000123", "99900000000000000123"),
("99900000000000000123.456000", "99900000000000000123.456"),
("0.00000000000000000000123", "0.00000000000000000000123"),
("0.00000000000000000000123000", "0.00000000000000000000123"),
("50032481330523882508234.00000000000000000000123000", "50032481330523882508234.00000000000000000000123"),
(
"928457298572093487502198745102973402987412908743.75249875981374981237498213740000",
"928457298572093487502198745102973402987412908743.7524987598137498123749821374"
),
]
)
def test_float_object_decimal_to_string(value, expected):
assert repr(FloatObject(value)) == expected

0 comments on commit 5aeb926

Please sign in to comment.