Skip to content

Commit

Permalink
release v2.0.30
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisschellekens committed Jul 23, 2022
1 parent f5b4964 commit ccc2130
Show file tree
Hide file tree
Showing 358 changed files with 1,405 additions and 89 deletions.
25 changes: 24 additions & 1 deletion borb/io/read/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,28 @@ def get_reference(self) -> typing.Optional["Reference"]:
setattr(self, "_reference", None)
return self._reference

# set_is_inline
# is_uniaue
def set_is_unique(self, a_flag: bool):
"""
This function sets whether or not this Object is unique.
When an object is unique, it is not checked against the cache.
"""
if "_is_unique" not in vars(self):
setattr(self, "_is_unique", None)
self._is_unique = a_flag
return self

# is_uniaue
def get_is_unique(self) -> bool:
"""
This function returns whether or not this Object is unique.
When an object is unique, it is not checked against the cache.
"""
if "_is_unique" not in vars(self):
setattr(self, "_is_unique", False)
return self._is_unique

# is_inline
def set_is_inline(self, a_flag: bool):
"""
This function sets whether or not this Object is written inline.
Expand Down Expand Up @@ -181,6 +202,8 @@ def get_is_inline(self) -> bool:
object.get_reference = types.MethodType(get_reference, object)
object.set_is_inline = types.MethodType(set_is_inline, object)
object.is_inline = types.MethodType(get_is_inline, object)
object.set_is_unique = types.MethodType(set_is_unique, object)
object.is_unique = types.MethodType(get_is_unique, object)
object.to_json_serializable = types.MethodType(to_json_serializable, object)
if isinstance(object, Image):
object.__deepcopy__ = types.MethodType(deepcopy_mod, object)
Expand Down
2 changes: 1 addition & 1 deletion borb/io/write/ascii_art/ascii_logo.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
borb version 2.0.29
borb version 2.0.30
Joris Schellekens
43 changes: 43 additions & 0 deletions borb/io/write/font/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
This file is part of the borb (R) project.
Copyright (c) 2020-2040 borb Group NV
Authors: Joris Schellekens, et al.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation with the addition of the
following permission added to Section 15 as permitted in Section 7(a):
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
BORB GROUP. BORB GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
OF THIRD PARTY RIGHTS
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, see http://www.gnu.org/licenses or write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA, 02110-1301 USA.
The interactive user interfaces in modified source and object code versions
of this program must display Appropriate Legal Notices, as required under
Section 5 of the GNU Affero General Public License.
In accordance with Section 7(b) of the GNU Affero General Public License,
a covered work must retain the producer line in every PDF that is created
or manipulated using borb.
You can be released from the requirements of the license by purchasing
a commercial license. Buying such a license is mandatory as soon as you
develop commercial activities involving the borb software without
disclosing the source code of your own applications.
These activities include: offering paid services to customers as an ASP,
serving PDFs on the fly in a web application, shipping borb with a closed
source product.
For more information, please contact borb Software Corp. at this
address: [email protected]
"""
41 changes: 41 additions & 0 deletions borb/io/write/font/character_set_listener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This implementation of WriteBaseTransformer is responsible for determining which characters (typing.Set[str])
are used by which Font. This is particularly useful when performing Font subsetting.
"""
import typing

from borb.pdf.canvas.event.chunk_of_text_render_event import ChunkOfTextRenderEvent
from borb.pdf.canvas.event.event_listener import EventListener, Event
from borb.pdf.canvas.font.font import Font


class CharacterSetListener(EventListener):
"""
This implementation of WriteBaseTransformer is responsible for determining which characters (typing.Set[str])
are used by which Font. This is particularly useful when performing Font subsetting.
"""

def __init__(self):
super(CharacterSetListener, self).__init__()
self._character_set_per_font: typing.Dict[Font, typing.Set[str]] = {}

def _event_occurred(self, event: Event) -> None:
if isinstance(event, ChunkOfTextRenderEvent):
f: Font = event.get_font()
if f in self._character_set_per_font:
s: typing.Set[str] = self._character_set_per_font[f]
for c in event.get_text():
s.add(c)
self._character_set_per_font[f] = s
else:
self._character_set_per_font[f] = set([x for x in event.get_text()])

def get_character_set_per_font(self) -> typing.Dict[Font, typing.Set[str]]:
"""
This function returns the character set (typing.Set[str]) used by each Font
:return: the character set used by each Font
"""
return self._character_set_per_font
72 changes: 72 additions & 0 deletions borb/io/write/font/copy_command_operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This CanvasOperator copies an existing operator and writes its bytes to a content stream of the canvas.
"""
import typing
from decimal import Decimal

from borb.io.read.types import AnyPDFType, HexadecimalString, String, Name
from borb.pdf.canvas.operator.canvas_operator import CanvasOperator


class CopyCommandOperator(CanvasOperator):
"""
This CanvasOperator copies an existing operator and writes its bytes to a content stream of the canvas.
"""

def __init__(
self, operator_to_copy: CanvasOperator, output_content_stream: bytearray
):
super().__init__("", 0)
self._operator_to_copy = operator_to_copy
self._output_content_stream: bytearray = output_content_stream

def get_text(self) -> str:
"""
Return the str that invokes this CanvasOperator
"""
return self._operator_to_copy.get_text()

def get_number_of_operands(self) -> int:
"""
Return the number of operands for this CanvasOperator
"""
return self._operator_to_copy.get_number_of_operands()

def _operand_to_str(self, op: AnyPDFType) -> str:
if isinstance(op, Decimal):
return str(op)
if isinstance(op, HexadecimalString):
return "<" + op._text + ">"
if isinstance(op, String):
return "(" + op._text + ")"
if isinstance(op, Name):
return "/" + str(op)
if isinstance(op, list):
return "[" + "".join([self._operand_to_str(x) + " " for x in op])[:-1] + "]"
return ""

def invoke(
self,
canvas_stream_processor: "CanvasStreamProcessor", # type: ignore [name-defined]
operands: typing.List[AnyPDFType] = [],
event_listeners: typing.List["EventListener"] = [], # type: ignore [name-defined]
) -> None:
"""
Invokes this CanvasOperator
"""

# execute command
self._operator_to_copy.invoke(canvas_stream_processor, operands)

# copy command in content stream
canvas = canvas_stream_processor.get_canvas()

# copy operand string
self._output_content_stream += b"\n"
self._output_content_stream += b"".join(
[(bytes(self._operand_to_str(s), encoding="utf8") + b" ") for s in operands]
)
self._output_content_stream += bytes(self.get_text(), encoding="utf8")
105 changes: 105 additions & 0 deletions borb/io/write/font/subset_show_text_with_glyph_positioning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Show one or more text strings, allowing individual glyph positioning. Each
element of array shall be either a string or a number.
"""
import typing
from decimal import Decimal
from typing import List

from borb.io.read.types import AnyPDFType, Name, String, HexadecimalString
from borb.io.write.font.copy_command_operator import CopyCommandOperator
from borb.pdf.canvas.font.font import Font
from borb.pdf.canvas.operator.text.show_text_with_glyph_positioning import (
ShowTextWithGlyphPositioning,
)


class SubSetShowTextWithGlyphPositioning(CopyCommandOperator):
"""
Show one or more text strings, allowing individual glyph positioning. Each
element of array shall be either a string or a number. If the element is a
string, this operator shall show the string. If it is a number, the operator
shall adjust the text position by that amount; that is, it shall translate the
text matrix, T . The number shall be expressed in thousandths of a unit
mof text space (see 9.4.4, "Text Space Details"). This amount shall be
subtracted from the current horizontal or vertical coordinate, depending
on the writing mode. In the default coordinate system, a positive
adjustment has the effect of moving the next glyph painted either to the
left or down by the given amount. Figure 46 shows an example of the
effect of passing offsets to TJ.
"""

def __init__(
self, old_fonts: typing.List[Font], new_fonts: typing.List[Font], s: bytearray
):
super(SubSetShowTextWithGlyphPositioning, self).__init__(
ShowTextWithGlyphPositioning(), s
)
self._old_fonts: typing.List[Font] = old_fonts
self._new_fonts: typing.List[Font] = new_fonts
self._s: bytearray = s

def _to_hex(self, i: int) -> str:
s: str = hex(int(i))[2:]
while len(s) < 2:
s = "0" + s
return s

def invoke(
self,
canvas_stream_processor: "CanvasStreamProcessor", # type: ignore [name-defined]
operands: typing.List[AnyPDFType] = [],
event_listeners: typing.List["EventListener"] = [], # type: ignore [name-defined]
) -> None:
"""
Invoke the TJ operator
"""

assert isinstance(operands[0], List), "Operand 0 of TJ must be a List"
canvas = canvas_stream_processor.get_canvas()

# handle Font being a Name (optimization)
assert canvas.graphics_state.font is not None
font_name: typing.Optional[Name] = None
if isinstance(canvas.graphics_state.font, Name):
# fmt: off
font_name = canvas.graphics_state.font
canvas.graphics_state.font = canvas_stream_processor.get_resource("Font", canvas.graphics_state.font)
# fmt: on

# we're only interested in the old_font
if canvas.graphics_state.font not in self._old_fonts:
return super(SubSetShowTextWithGlyphPositioning, self).invoke(
canvas_stream_processor, operands, event_listeners
)

old_font: Font = canvas.graphics_state.font
new_font: Font = self._new_fonts[self._old_fonts.index(old_font)]

# modify the operands
operands_out: typing.List[AnyPDFType] = []
for i in range(0, len(operands[0])):
obj = operands[0][i]

# adjust
if isinstance(obj, Decimal):
operands_out.append(obj)
continue

# display string
if isinstance(obj, String):
old_char: str = old_font.character_identifier_to_unicode(
int(str(obj), 16)
)
new_code: str = self._to_hex(
new_font.unicode_to_character_identifier(old_char)
)
operands_out.append(HexadecimalString(new_code))

# delegate
return super(SubSetShowTextWithGlyphPositioning, self).invoke(
canvas_stream_processor, [operands_out], event_listeners
)
Loading

0 comments on commit ccc2130

Please sign in to comment.