Skip to content

Commit

Permalink
Merge pull request #24 from takis/issue19
Browse files Browse the repository at this point in the history
Add inline PNG support
  • Loading branch information
grewn0uille authored Feb 19, 2024
2 parents cdc7a3b + 4a64076 commit 3552d39
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
50 changes: 50 additions & 0 deletions docs/common_use_cases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,53 @@ Add metadata
# 550 bytes PDF
with open('metadata.pdf', 'wb') as f:
document.write(f)
Display inline QR-code image
----------------------------

.. code-block:: python
import pydyf
import qrcode
# Create a QR code image
image = qrcode.make('Some data here')
raw_data = image.tobytes()
width = image.size[0]
height = image.size[1]
document = pydyf.PDF()
stream = pydyf.Stream(compress=True)
stream.push_state()
x = 0
y = 0
stream.transform(width, 0, 0, height, x, y)
# Add the 1-bit grayscale image inline in the PDF
stream.inline_image(width, height, 'Gray', 1, raw_data)
stream.pop_state()
document.add_object(stream)
# Put the image in the resources of the PDF
document.add_page(
pydyf.Dictionary(
{
"Type": "/Page",
"Parent": document.pages.reference,
"MediaBox": pydyf.Array([0, 0, 400, 400]),
"Resources": pydyf.Dictionary(
{
"ProcSet": pydyf.Array(
["/PDF", "/ImageB", "/ImageC", "/ImageI"]
),
}
),
"Contents": stream.reference,
}
)
)
# 909 bytes PDF
with open("qrcode.pdf", "wb") as f:
document.write(f, compress=True)
39 changes: 39 additions & 0 deletions pydyf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import base64
import re
import zlib
from codecs import BOM_UTF16_BE
Expand Down Expand Up @@ -364,6 +365,44 @@ def transform(self, a, b, c, d, e, f):
_to_bytes(a), _to_bytes(b), _to_bytes(c),
_to_bytes(d), _to_bytes(e), _to_bytes(f), b'cm')))

def inline_image(self, width, height, color_space, bpc, raw_data):
"""Add an inline image.
:param width: The width of the image.
:type width: :obj:`int`
:param height: The height of the image.
:type height: :obj:`int`
:param colorspace: The color space of the image, f.e. RGB, Gray.
:type colorspace: :obj:`str`
:param bpc: The bits per component. 1 for BW, 8 for grayscale.
:type bpc: :obj:`int`
:param raw_data: The raw pixel data.
"""
if self.compress:
data = zlib.compress(raw_data)
else:
data = raw_data
enc_data = base64.a85encode(data)
self.stream.append(
b' '.join(
(
b'BI',
b'/W', _to_bytes(width),
b'/H', _to_bytes(height),
b'/BPC', _to_bytes(bpc),
b'/CS',
b'/Device' + color_space.encode(),
b'/F',
b'[/A85 /Fl]' if self.compress else b'/A85',
b'/L', _to_bytes(len(enc_data) + 2),
b'ID',
enc_data + b'~>',
b'EI',
)
)
)

@property
def data(self):
stream = b'\n'.join(_to_bytes(item) for item in self.stream)
Expand Down

0 comments on commit 3552d39

Please sign in to comment.