Adding upstream version 0.9.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
3bcef22498
commit
d4a07804fe
6 changed files with 215 additions and 12 deletions
2
.github/workflows/doconfly.yml
vendored
2
.github/workflows/doconfly.yml
vendored
|
@ -2,7 +2,7 @@ name: doconfly
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
|
|
8
.github/workflows/tests.yml
vendored
8
.github/workflows/tests.yml
vendored
|
@ -8,15 +8,15 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
python-version: ['3.11']
|
||||
python-version: ['3.12']
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
python-version: '3.7'
|
||||
python-version: '3.8'
|
||||
- os: ubuntu-latest
|
||||
python-version: 'pypy-3.8'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install Ghostscript (Ubuntu)
|
||||
|
|
|
@ -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
|
||||
-------------
|
||||
|
||||
|
|
|
@ -179,3 +179,87 @@ Display text
|
|||
|
||||
with open('document.pdf', 'wb') as 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)
|
||||
|
||||
|
|
|
@ -3,28 +3,27 @@ A low-level PDF generator.
|
|||
|
||||
"""
|
||||
|
||||
import base64
|
||||
import re
|
||||
import zlib
|
||||
from codecs import BOM_UTF16_BE
|
||||
from hashlib import md5
|
||||
from math import ceil, log
|
||||
|
||||
VERSION = __version__ = '0.7.0'
|
||||
VERSION = __version__ = '0.9.0'
|
||||
|
||||
|
||||
def _to_bytes(item):
|
||||
"""Convert item to bytes."""
|
||||
if isinstance(item, bytes):
|
||||
return item
|
||||
elif isinstance(item, Object):
|
||||
return item.data
|
||||
elif isinstance(item, float):
|
||||
if item.is_integer():
|
||||
return f'{int(item):d}'.encode('ascii')
|
||||
return str(int(item)).encode('ascii')
|
||||
else:
|
||||
return f'{item:f}'.rstrip('0').encode('ascii')
|
||||
elif isinstance(item, int):
|
||||
return f'{item:d}'.encode('ascii')
|
||||
elif isinstance(item, Object):
|
||||
return item.data
|
||||
return str(item).encode('ascii')
|
||||
|
||||
|
||||
|
@ -366,6 +365,44 @@ class Stream(Object):
|
|||
_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)
|
||||
|
|
|
@ -19,11 +19,11 @@ classifiers = [
|
|||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
]
|
||||
|
|
Loading…
Add table
Reference in a new issue