Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for monochromatic images (PIL image.mode == '1') #527

Merged
merged 8 commits into from
Sep 13, 2022
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ in order to get warned about deprecated features used in your code.
This can also be enabled programmatically with `warnings.simplefilter('default', DeprecationWarning)`.

## [2.5.8] - not released yet
### Added
- support for monochromatic images (PIL image.mode == '1')

## [2.5.7] - 2022-09-08
### Changed
Expand Down
15 changes: 11 additions & 4 deletions fpdf/image_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from io import BytesIO
import base64
from urllib.request import urlopen
from math import ceil

try:
from PIL import Image
Expand Down Expand Up @@ -70,12 +71,15 @@ def get_img_info(img, image_filter="AUTO", dims=None):
if img.mode in ("P", "PA") and image_filter != "FlateDecode":
img = img.convert("RGBA")

if img.mode not in ("L", "LA", "RGB", "RGBA", "P", "PA"):
if img.mode not in ("1", "L", "LA", "RGB", "RGBA", "P", "PA"):
img = img.convert("RGBA")

w, h = img.size
info = {}
if img.mode == "L":
if img.mode == "1":
dpn, bpc, colspace = 1, 1, "DeviceGray"
info["data"] = _to_data(img, image_filter)
elif img.mode == "L":
dpn, bpc, colspace = 1, 8, "DeviceGray"
info["data"] = _to_data(img, image_filter)
elif img.mode == "LA":
Expand Down Expand Up @@ -171,8 +175,11 @@ def _to_zdata(img, remove_slice=None, select_slice=None):
if select_slice:
data = data[select_slice]
# Left-padding every row with a single zero:
channels_count = len(data) // (img.size[0] * img.size[1])
loop_incr = img.size[0] * channels_count + 1
if img.mode == "1":
loop_incr = ceil(img.size[0] / 8) + 1
else:
channels_count = len(data) // (img.size[0] * img.size[1])
loop_incr = img.size[0] * channels_count + 1
i = 0
while i < len(data):
data[i:i] = b"\0"
Expand Down
14 changes: 7 additions & 7 deletions test/image/image_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"basi0g01.png": {
"w": 32,
"h": 32,
"cs": "DeviceRGB",
"bpc": 8,
"cs": "DeviceGray",
"bpc": 1,
"f": "FlateDecode",
"dp": "/Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 32",
"dp": "/Predictor 15 /Colors 1 /BitsPerComponent 1 /Columns 32",
"trns": ""
},
"basi0g02.png": {
Expand Down Expand Up @@ -145,10 +145,10 @@
"basn0g01.png": {
"w": 32,
"h": 32,
"cs": "DeviceRGB",
"bpc": 8,
"cs": "DeviceGray",
"bpc": 1,
"f": "FlateDecode",
"dp": "/Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 32",
"dp": "/Predictor 15 /Colors 1 /BitsPerComponent 1 /Columns 32",
"trns": ""
},
"basn0g02.png": {
Expand Down Expand Up @@ -1535,4 +1535,4 @@
"dp": "/Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 32",
"trns": ""
}
}
}
Binary file not shown.
7 changes: 7 additions & 0 deletions test/image/image_types/test_insert_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ def test_insert_png(tmp_path):
assert_pdf_equal(pdf, HERE / "image_types_insert_png.pdf", tmp_path)


def test_insert_png_monochromatic(tmp_path):
pdf = fpdf.FPDF()
pdf.add_page()
pdf.image(HERE / "../png_test_suite/basi0g01.png", x=15, y=15, h=140)
assert_pdf_equal(pdf, HERE / "image_types_insert_png_monochromatic.pdf", tmp_path)


def test_insert_png_alpha(tmp_path):
pdf = fpdf.FPDF()
pdf.compress = False
Expand Down
Binary file modified test/template/flextemplate_elements.pdf
Binary file not shown.
Binary file modified test/template/flextemplate_rotation.pdf
Binary file not shown.
Binary file modified test/template/template_qrcode.pdf
Binary file not shown.