summaryrefslogtreecommitdiffstats
path: root/pydyf
diff options
context:
space:
mode:
Diffstat (limited to 'pydyf')
-rwxr-xr-xpydyf/__init__.py114
1 files changed, 58 insertions, 56 deletions
diff --git a/pydyf/__init__.py b/pydyf/__init__.py
index d8e1d7b..86d321d 100755
--- a/pydyf/__init__.py
+++ b/pydyf/__init__.py
@@ -9,8 +9,9 @@ import zlib
from codecs import BOM_UTF16_BE
from hashlib import md5
from math import ceil, log
+from warnings import warn
-VERSION = __version__ = '0.9.0'
+VERSION = __version__ = '0.10.0'
def _to_bytes(item):
@@ -203,6 +204,37 @@ class Stream(Object):
"""
self.stream.append(b'b*' if even_odd else b'b')
+ 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.
+
+ """
+ data = zlib.compress(raw_data) if self.compress else raw_data
+ a85_data = base64.a85encode(data) + b'~>'
+ 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' + _to_bytes(color_space),
+ b'/F',
+ b'[/A85 /Fl]' if self.compress else b'/A85',
+ b'/L', _to_bytes(len(a85_data)),
+ b'ID',
+ a85_data,
+ b'EI',
+ )))
+
def line_to(self, x, y):
"""Add line from current point to point ``(x, y)``."""
self.stream.append(b' '.join((_to_bytes(x), _to_bytes(y), b'l')))
@@ -365,44 +397,6 @@ 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)
@@ -450,17 +444,16 @@ class Array(Object, list):
class PDF:
"""PDF document."""
- def __init__(self, version=b'1.7', identifier=None):
- """Create a PDF document.
-
- :param bytes version: PDF version.
- :param bytes identifier: PDF file identifier.
-
- """
- #: PDF version, as :obj:`bytes`.
- self.version = _to_bytes(version)
- #: PDF file identifier.
- self.identifier = identifier
+ def __init__(self, version=None, identifier=None):
+ """Create a PDF document."""
+ if version or identifier: # to be removed in next version
+ warn(
+ "PDF objects don’t take version or identifier during initialization "
+ "anymore. These properties are now stored but ignored, and will be "
+ "removed and rejected in next version of pydyf. Please pass these "
+ "properties to the PDF.write() method instead.", DeprecationWarning)
+ self.version = _to_bytes(version) if version else b'1.7' # to be removed
+ self.identifier = identifier # to be removed
#: Python :obj:`list` containing the PDF’s objects.
self.objects = []
@@ -528,18 +521,23 @@ class PDF:
self.current_position += len(content) + 1
output.write(content + b'\n')
- def write(self, output, version=None, identifier=None, compress=False):
+ def write(self, output, version=b'1.7', identifier=False, compress=False):
"""Write PDF to output.
:param output: Output stream.
:type output: binary :term:`file object`
:param bytes version: PDF version.
- :param bytes identifier: PDF file identifier.
+ :param identifier: PDF file identifier. Default is :obj:`False`
+ to include no identifier, can be set to :obj:`True` to generate an
+ automatic identifier.
+ :type identifier: :obj:`bytes` or :obj:`bool`
:param bool compress: whether the PDF uses a compressed object stream.
"""
- version = self.version if version is None else _to_bytes(version)
- identifier = self.identifier if identifier is None else identifier
+ # Convert version and identifier to bytes
+ version = _to_bytes(version or b'1.7') # Force 1.7 when None
+ if identifier not in (False, True, None):
+ identifier = _to_bytes(identifier)
# Write header
self.write_line(b'%PDF-' + version, output)
@@ -607,10 +605,12 @@ class PDF:
'Root': self.catalog.reference,
'Info': self.info.reference,
}
- if identifier is not None:
+ if identifier:
data = b''.join(
obj.data for obj in self.objects if obj.free != 'f')
data_hash = md5(data).hexdigest().encode()
+ if identifier is True:
+ identifier = data_hash
extra['ID'] = Array((
String(identifier).data, String(data_hash).data))
dict_stream = Stream([xref_stream], extra, compress)
@@ -640,10 +640,12 @@ class PDF:
self.write_line(f'/Size {len(self.objects)}'.encode(), output)
self.write_line(b'/Root ' + self.catalog.reference, output)
self.write_line(b'/Info ' + self.info.reference, output)
- if identifier is not None:
+ if identifier:
data = b''.join(
obj.data for obj in self.objects if obj.free != 'f')
data_hash = md5(data).hexdigest().encode()
+ if identifier is True:
+ identifier = data_hash
self.write_line(
b'/ID [' + String(identifier).data + b' ' +
String(data_hash).data + b']', output)