1
0
Fork 0

Adding upstream version 0.9.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-08 08:01:00 +01:00
parent 3bcef22498
commit d4a07804fe
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
6 changed files with 215 additions and 12 deletions

View file

@ -2,7 +2,7 @@ name: doconfly
on: on:
push: push:
branches: branches:
- master - main
tags: tags:
- "*" - "*"

View file

@ -8,15 +8,15 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.11'] python-version: ['3.12']
include: include:
- os: ubuntu-latest - os: ubuntu-latest
python-version: '3.7' python-version: '3.8'
- os: ubuntu-latest - os: ubuntu-latest
python-version: 'pypy-3.8' python-version: 'pypy-3.8'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-python@v2 - uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install Ghostscript (Ubuntu) - name: Install Ghostscript (Ubuntu)

View file

@ -2,6 +2,88 @@ Changelog
========= =========
Version 0.9.0
-------------
Released on 2024-02-26.
Dependencies:
* Python 3.12 is supported and tested
* Python 3.8+ is now needed, Python 3.7 is not supported anymore
New features:
* Add inline images support
Performance:
* Simplify `_to_bytes()`
Documentation:
* Add sample to create a PDF with metadata
Contributors:
* Panagiotis H.M. Issaris
* Guillaume Ayoub
* Lucie Anglade
Backers and sponsors:
* Spacinov
* Kobalt
* Grip Angebotssoftware
* Manuel Barkhau
* SimonSoft
* Menutech
* KontextWork
* René Fritz
* Simon Sapin
* Arcanite
* TrainingSparkle
* Healthchecks.io
* Hammerbacher
* Docraptor
* Yanal-Yvez Fargialla
* Morntag
* NBCO
Version 0.8.0
-------------
Released on 2023-09-25.
New features:
* Add text rise operator
Backers and sponsors:
* Spacinov
* Kobalt
* Grip Angebotssoftware
* Manuel Barkhau
* SimonSoft
* Menutech
* KontextWork
* NCC Group
* René Fritz
* Nicola Auchmuty
* Syslifters
* Hammerbacher
* TrainingSparkle
* Daniel Kucharski
* Healthchecks.io
* Yanal-Yvez Fargialla
* WakaTime
* Paheko
* Synapsium
* DocRaptor
Version 0.7.0 Version 0.7.0
------------- -------------

View file

@ -179,3 +179,87 @@ Display text
with open('document.pdf', 'wb') as f: with open('document.pdf', 'wb') as f:
document.write(f) document.write(f)
Add metadata
------------
.. code-block:: python
import datetime
import pydyf
document = pydyf.PDF()
document.info['Author'] = pydyf.String('Jane Doe')
document.info['Creator'] = pydyf.String('pydyf')
document.info['Keywords'] = pydyf.String('some keywords')
document.info['Producer'] = pydyf.String('The producer')
document.info['Subject'] = pydyf.String('An example PDF')
document.info['Title'] = pydyf.String('A PDF containing metadata')
now = datetime.datetime.now()
document.info['CreationDate'] = pydyf.String(now.strftime('D:%Y%m%d%H%M%S'))
document.add_page(
pydyf.Dictionary(
{
'Type': '/Page',
'Parent': document.pages.reference,
'MediaBox': pydyf.Array([0, 0, 200, 200]),
}
)
)
# 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)

View file

@ -3,28 +3,27 @@ A low-level PDF generator.
""" """
import base64
import re import re
import zlib import zlib
from codecs import BOM_UTF16_BE from codecs import BOM_UTF16_BE
from hashlib import md5 from hashlib import md5
from math import ceil, log from math import ceil, log
VERSION = __version__ = '0.7.0' VERSION = __version__ = '0.9.0'
def _to_bytes(item): def _to_bytes(item):
"""Convert item to bytes.""" """Convert item to bytes."""
if isinstance(item, bytes): if isinstance(item, bytes):
return item return item
elif isinstance(item, Object):
return item.data
elif isinstance(item, float): elif isinstance(item, float):
if item.is_integer(): if item.is_integer():
return f'{int(item):d}'.encode('ascii') return str(int(item)).encode('ascii')
else: else:
return f'{item:f}'.rstrip('0').encode('ascii') return f'{item:f}'.rstrip('0').encode('ascii')
elif isinstance(item, int): elif isinstance(item, Object):
return f'{item:d}'.encode('ascii') return item.data
return str(item).encode('ascii') return str(item).encode('ascii')
@ -366,6 +365,44 @@ class Stream(Object):
_to_bytes(a), _to_bytes(b), _to_bytes(c), _to_bytes(a), _to_bytes(b), _to_bytes(c),
_to_bytes(d), _to_bytes(e), _to_bytes(f), b'cm'))) _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 @property
def data(self): def data(self):
stream = b'\n'.join(_to_bytes(item) for item in self.stream) stream = b'\n'.join(_to_bytes(item) for item in self.stream)

View file

@ -19,11 +19,11 @@ classifiers = [
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy', 'Programming Language :: Python :: Implementation :: PyPy',
] ]