Skip to content

Commit

Permalink
release 2.1.16
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisschellekens committed Jul 30, 2023
1 parent 4ad675f commit 8e92db0
Show file tree
Hide file tree
Showing 2,335 changed files with 2,610 additions and 1,619 deletions.
Empty file modified .gitignore
100755 → 100644
Empty file.
Empty file modified BORB_CONTRIBUTOR_LICENSE_AGREEMENT.md
100755 → 100644
Empty file.
Empty file modified CODE_OF_CONDUCT.md
100755 → 100644
Empty file.
Empty file modified CONTRIBUTING.md
100755 → 100644
Empty file.
Empty file modified LICENSE.md
100755 → 100644
Empty file.
Empty file modified MANIFEST.in
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion README.md
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Corpus Coverage : 100.0%](https://img.shields.io/badge/corpus%20coverage-100.0%25-green)]()
[![Text Extraction : 93.1%](https://img.shields.io/badge/text%20extraction-93.1%25-green)]()
[![Public Method Documentation : 100%](https://img.shields.io/badge/public%20method%20documentation-100%25-green)]()
[![Number of Tests : 615](https://img.shields.io/badge/number%20of%20tests-615-green)]()
[![Number of Tests : 633](https://img.shields.io/badge/number%20of%20tests-633-green)]()
[![Python : 3.8 | 3.9 | 3.10 ](https://img.shields.io/badge/python-3.8%20|%203.9%20|%203.10-green)]()

[![Downloads](https://pepy.tech/badge/borb)](https://pepy.tech/project/borb)
Expand Down
Empty file modified borb/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/datastructure/__init__.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/datastructure/cache_by_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def cached_by_hash(func):
"""

def _inner(*args, **kwargs):

# add attribute to store cached value
field_name_for_cached_val: str = "_cache_for_" + func.__name__
field_name_for_cache_hit_rate: str = "_cache_for_" + func.__name__ + "_hit_rate"
Expand Down
Empty file modified borb/datastructure/disjoint_set.py
100755 → 100644
Empty file.
Empty file modified borb/datastructure/str_trie.py
100755 → 100644
Empty file.
Empty file modified borb/io/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/filter/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/filter/ascii85_decode.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/filter/flate_decode.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ def decode(
bytes_after_predictor = []
pos = 0
while pos + bytes_per_row <= len(bytes_after_zlib):

# Read the filter type byte and a row of data
filter_type = bytes_after_zlib[pos]
pos += 1
Expand Down
Empty file modified borb/io/filter/lzw_decode.py
100755 → 100644
Empty file.
Empty file modified borb/io/filter/run_length_decode.py
100755 → 100644
Empty file.
Empty file modified borb/io/filter/stream_decode_util.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/any_object_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/encryption/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/encryption/rc4.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/read/encryption/standard_security_handler.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def __init__(
owner_password: typing.Optional[str] = None,
user_password: typing.Optional[str] = None,
):

# (Optional) A code specifying the algorithm to be used in encrypting and
# decrypting the document:
# 0 An algorithm that is undocumented. This value shall not be used.
Expand Down
Empty file modified borb/io/read/font/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/font/font_dictionary_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/function/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/function/function_dictionary_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/ccitt_fax_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/compressed_jpeg_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/grayscale_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/jbig2_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/jpeg_2000_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/image/jpeg_image_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/metadata/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/metadata/xmp_metadata_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/object/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/object/array_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/object/dictionary_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/object/stream_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/page/__init__.py
100755 → 100644
Empty file.
1 change: 1 addition & 0 deletions borb/io/read/page/page_dictionary_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def transform(
return object_to_transform

# convert dictionary like structure
print("reading page")
page_out = Page()
page_out.set_parent(parent_object)

Expand Down
1 change: 0 additions & 1 deletion borb/io/read/page/root_dictionary_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class RootDictionaryTransformer(Transformer):
#

def _re_order_pages(self, root_dictionary: dict) -> None:

# list to hold Page objects (in order)
pages_in_order: typing.List[Page] = []

Expand Down
1 change: 0 additions & 1 deletion borb/io/read/pdf_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def __init__(self):

@staticmethod
def _to_json(self, memo_dict={}) -> typing.Any:

# bool
if isinstance(self, bool):
return self
Expand Down
Empty file modified borb/io/read/postfix/__init__.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/read/postfix/postfix_eval.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def evaluate(s: str, args: typing.List[Decimal]) -> typing.List[Decimal]:

i: int = 0
while i < len(s):

# whitespace
if s[i] in " \n\t":
i += 1
Expand Down
Empty file modified borb/io/read/primitive/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/primitive/number_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/primitive/string_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/reference/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/reference/reference_transformer.py
100755 → 100644
Empty file.
3 changes: 1 addition & 2 deletions borb/io/read/reference/xref_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def _read_xref(
most_recent_xref = StreamXREF()
assert most_recent_xref is not None
most_recent_xref.set_parent(doc) # type: ignore [attr-defined]
print("reading another xref")
most_recent_xref.read(src, tok, initial_offset)
if "XRef" in doc:
doc[Name("XRef")] = doc["XRef"].merge(most_recent_xref)
Expand Down Expand Up @@ -157,7 +158,6 @@ def _read_xref(

@staticmethod
def _remove_prefix(context: ReadTransformerState) -> None:

assert context is not None
assert context.source is not None
assert context.tokenizer is not None
Expand Down Expand Up @@ -249,7 +249,6 @@ def transform(

# check for password protected PDF
if "Trailer" in xref and "Encrypt" in xref["Trailer"]:

# transform /Encrypt dictionary
# fmt: off
xref["Trailer"][Name("Encrypt")] = self.get_root_transformer().transform(xref["Trailer"]["Encrypt"], xref["Trailer"], context, event_listeners)
Expand Down
Empty file modified borb/io/read/tokenize/__init__.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/read/tokenize/high_level_tokenizer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def read_dictionary(self) -> Dictionary:

out_dict = Dictionary()
while True:

# attempt to read name token
token = self.next_non_comment_token()
assert token is not None
Expand Down
Empty file modified borb/io/read/tokenize/low_level_tokenizer.py
100755 → 100644
Empty file.
Empty file modified borb/io/read/transformer.py
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion borb/io/read/types.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ def evaluate(self, xs: typing.List[oDecimal]) -> typing.List[oDecimal]:
# Each output value rj, for 0 £ j < n, shall then be decoded:
rs_prime: typing.List[oDecimal] = [
Function._interpolate(
rs[j], oDecimal(0), 2**bps - 1, decode[2 * j], decode[2 * j + 1]
rs[j], oDecimal(0), 2 ** bps - 1, decode[2 * j], decode[2 * j + 1]
)
for j in range(0, len(rs))
]
Expand Down
Empty file modified borb/io/write/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/any_object_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/conformance_level.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/document/__init__.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/write/document/catalog_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class CatalogTransformer(DictionaryTransformer):
#

def _build_rgb_outputintent_dictionary(self, root_dictionary: Dictionary) -> None:

# TODO check if exists already

# read color profile bytes
Expand Down
2 changes: 1 addition & 1 deletion borb/io/write/document/document_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def transform(
DocumentTransformer._invalidate_all_references(object_to_transform)

# set /ID
random_id = HexadecimalString("%032x" % random.randrange(16**32))
random_id = HexadecimalString("%032x" % random.randrange(16 ** 32))
if "ID" not in object_to_transform["XRef"]["Trailer"]:
# fmt: off
object_to_transform["XRef"]["Trailer"][Name("ID")] = List()
Expand Down
2 changes: 0 additions & 2 deletions borb/io/write/document/information_dictionary_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ def _now_as_iso_8824_date_format() -> str:
return timestamp_str

def _update_info_dictionary(self, info_dictionary: Dictionary) -> Dictionary:

# set CreationDate
# fmt: off
if "CreationDate" not in info_dictionary:
Expand Down Expand Up @@ -288,7 +287,6 @@ def transform(
# fmt: on

if needs_xmp_metadata:

# write XMP /Metadata
xmp_metadata_stream: Stream = self._write_xmp_metadata_stream(
new_info_dictionary,
Expand Down
Empty file modified borb/io/write/document/resources/sRGB_CS_profile.icm
100755 → 100644
Empty file.
Empty file modified borb/io/write/font/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/font/character_set_listener.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/font/copy_command_operator.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/font/subset_show_text_with_glyph_positioning.py
100755 → 100644
Empty file.
2 changes: 0 additions & 2 deletions borb/io/write/font/subsetter.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def _extract_text_per_font(page: "Page") -> typing.Dict[Font, typing.Set[str]]:
def _modify_page_content_stream(
page: Page, old_fonts: typing.List[Font], new_fonts: typing.List[Font]
):

# build CanvasStreamProcessor
csp = CanvasStreamProcessor(page, Canvas(), [])

Expand Down Expand Up @@ -122,7 +121,6 @@ def apply(page: Page) -> Page:

subset_fonts: typing.List[Font] = []
for old_font in fonts_to_be_subset:

# get DecodedBytes
font_file_bytes_001 = old_font["DescendantFonts"][0]["FontDescriptor"][
"FontFile2"
Expand Down
Empty file modified borb/io/write/image/__init__.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/io/write/image/image_transformer.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class ImageTransformer(Transformer):
#

def _convert_to_rgb_mode(self, image: PILImage.Image) -> PILImage.Image:

# build image_out
image_out: PILImage.Image = image

Expand Down
33 changes: 16 additions & 17 deletions borb/io/write/image/rgba_image_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,8 @@ class RGBAImageTransformer(Transformer):
# PRIVATE
#

#
# PUBLIC
#

def can_be_transformed(self, any: AnyPDFType):
"""
This function returns True if the object to be converted represents an Image object
"""
return isinstance(any, PILImage.Image) and any.mode == "RGBA"

@staticmethod
def _rgb_array(image: PILImage.Image) -> bytes:
s0 = [(r, g, b) for r, g, b, a in image.getdata()]
s1 = [x for x in itertools.chain(*s0)]
return bytes(s1)

@staticmethod
def _construct_smask_stream(image: PILImage.Image) -> Stream:

# get raw <alpha> bytes
w: int = image.width
h: int = image.height
Expand All @@ -72,6 +55,22 @@ def _construct_smask_stream(image: PILImage.Image) -> Stream:
out[Name("Width")] = bDecimal(w)
return out

@staticmethod
def _rgb_array(image: PILImage.Image) -> bytes:
s0 = [(r, g, b) for r, g, b, a in image.getdata()]
s1 = [x for x in itertools.chain(*s0)]
return bytes(s1)

#
# PUBLIC
#

def can_be_transformed(self, any: AnyPDFType):
"""
This function returns True if the object to be converted represents an Image object
"""
return isinstance(any, PILImage.Image) and any.mode == "RGBA"

def transform(
self,
object_to_transform: AnyPDFType,
Expand Down
Empty file modified borb/io/write/object/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/object/array_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/object/dictionary_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/object/stream_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/page/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/page/page_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/page/pages_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/primitive/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/primitive/boolean_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/primitive/name_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/primitive/number_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/primitive/string_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/reference/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/reference/reference_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/reference/xref_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/version/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/version/version_as_comment_transformer.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/xmp/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/io/write/xmp/xmp_transformer.py
100755 → 100644
Empty file.
5 changes: 1 addition & 4 deletions borb/license/license.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

from borb.license.uuid import UUID

logger = logging.getLogger(__file__)
logger = logging.getLogger(__name__)


class License:
Expand Down Expand Up @@ -61,7 +61,6 @@ def _create_key_pair(
private_key_file: Path = Path(__file__).parent / "private_key.pem",
public_key_file: Path = Path(__file__).parent / "public_key.pem",
):

# Generate a new RSA private key
private_key = rsa.generate_private_key(
public_exponent=65537,
Expand Down Expand Up @@ -98,7 +97,6 @@ def _create_license(
valid_until_in_ms: int = int(datetime.datetime.now().timestamp() * 1000)
+ 7 * 24 * 60 * 60 * 1000,
) -> None:

# set up dictionary
# fmt: off
license_dict: typing.Dict[str, str] = {
Expand Down Expand Up @@ -219,7 +217,6 @@ def register(path_to_license_file: Path) -> bool:
assert key_dir.exists()
assert key_dir.is_dir()
for public_key_file in [key_dir / "public_key_001.pem"]:

# read key
with open(public_key_file, "rb") as f:
public_key = serialization.load_pem_public_key(f.read())
Expand Down
63 changes: 62 additions & 1 deletion borb/license/usage_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import json
import sys
import threading
import time
import typing
from datetime import datetime
from datetime import timezone
Expand All @@ -31,6 +32,9 @@ class UsageStatistics:
# fmt: off
_ENABLED: bool = True
_ENDPOINT_URL: str = "https://cztmincfqq4fobtt6c7ect7gli0isbwx.lambda-url.us-east-1.on.aws/"
_FAIR_USE_LAST_INVOCATION_NUMBER_OF_DOCUMENTS: int = 0
_FAIR_USE_LAST_INVOCATION_TIMESTAMP_IN_MS: int = 0
_FAIR_USE_MAXIMUM_NUMBER_OF_DOCUMENTS_PER_MINUTE: int = 100
# fmt: on

#
Expand All @@ -41,6 +45,37 @@ class UsageStatistics:
# PRIVATE
#

@staticmethod
def _display_fair_use_warning() -> None:

# never display this warning to a licensed user
if License.get_user_id() is not None:
return

# fmt: off
UsageStatistics._FAIR_USE_LAST_INVOCATION_NUMBER_OF_DOCUMENTS = 0
print("\u001b[48;2;241;205;48mDear user,\n\n"
"We noticed that you have exceeded the threshold of 100 documents per minute\n"
"while using our Python PDF library. We're thrilled that our library is\n"
"proving to be useful in your application!\n\n"
"However, we want to bring to your attention the licensing terms of our\n"
"library. It is dual licensed under AGPLv3 (GNU Affero General Public License,\n"
"version 3) and a commercial license.\n\n"
"If you are using our library for personal or non-commercial projects, you can\n"
"continue to do so under the terms of the AGPLv3 license. We appreciate your\n"
"support of open-source software.\n\n"
"However, if you are using our library in a commercial setting, offering\n"
"services or products to third parties, or if your usage does not abide by the\n"
"AGPLv3 conditions, you are required to obtain a commercial license from us.\n"
"This commercial license ensures compliance with the legal requirements and\n"
"supports the ongoing development and maintenance of the library.\n\n"
"To obtain a commercial license or discuss your licensing options, please \n"
"contact our sales team at https://borb-pdf.com. We value your \n"
"support and contributions to our library, and we hope to continue providing \n"
"you with excellent features and support.\n\n"
"Thank you for your attention and understanding.\n\u001b[0m")
# fmt: on

@staticmethod
def _get_machine_id() -> typing.Optional[str]:
return MachineID.get()
Expand All @@ -51,7 +86,6 @@ def _get_user_id() -> str:

@staticmethod
def _send_usage_statistics_in_thread(event: str, document: typing.Optional["Document"] = None) -> None: # type: ignore[name-defined]

# get number_of_pages
number_of_pages: int = 0
try:
Expand Down Expand Up @@ -116,8 +150,35 @@ def send_usage_statistics(event: str = "", document: typing.Optional["Document"]
:param document the Document being processed
:return: None
"""

# easy exit
if not UsageStatistics._ENABLED:
return

# update FAIR_USE counters
now_in_ms: int = int(time.time() * 1000)
delta_in_ms: int = (
now_in_ms - UsageStatistics._FAIR_USE_LAST_INVOCATION_TIMESTAMP_IN_MS
)
if (
delta_in_ms
> (1000 * 60)
/ UsageStatistics._FAIR_USE_MAXIMUM_NUMBER_OF_DOCUMENTS_PER_MINUTE
):
UsageStatistics._FAIR_USE_LAST_INVOCATION_TIMESTAMP_IN_MS = now_in_ms
UsageStatistics._FAIR_USE_LAST_INVOCATION_NUMBER_OF_DOCUMENTS = 1
else:
UsageStatistics._FAIR_USE_LAST_INVOCATION_TIMESTAMP_IN_MS = now_in_ms
UsageStatistics._FAIR_USE_LAST_INVOCATION_NUMBER_OF_DOCUMENTS += 1

# notification
if (
UsageStatistics._FAIR_USE_LAST_INVOCATION_NUMBER_OF_DOCUMENTS
>= UsageStatistics._FAIR_USE_MAXIMUM_NUMBER_OF_DOCUMENTS_PER_MINUTE
):
UsageStatistics._display_fair_use_warning()

# send in Thread
try:
threading.Thread(
target=UsageStatistics._send_usage_statistics_in_thread,
Expand Down
2 changes: 1 addition & 1 deletion borb/license/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ def get_version() -> str:
This function returns the current borb version
:return: the current borb version
"""
return "2.1.14"
return "2.1.16"
1 change: 1 addition & 0 deletions borb/pdf/__init__.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
from .canvas.layout.image.barcode import BarcodeType
from .canvas.layout.image.chart import Chart
from .canvas.layout.image.image import Image
from .canvas.layout.image.watermark import Watermark
from .canvas.layout.layout_element import Alignment

# List
Expand Down
Empty file modified borb/pdf/canvas/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/pdf/canvas/canvas.py
100755 → 100644
Empty file.
Empty file modified borb/pdf/canvas/canvas_graphics_state.py
100755 → 100644
Empty file.
1 change: 0 additions & 1 deletion borb/pdf/canvas/canvas_stream_processor.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@ def read(
time_per_operator: typing.Dict[str, float] = {}
calls_per_operator: typing.Dict[str, int] = {}
while canvas_tokenizer.tell() != length:

# attempt to read object
tell_before: int = canvas_tokenizer.tell()
obj = canvas_tokenizer.read_object()
Expand Down
Empty file modified borb/pdf/canvas/color/__init__.py
100755 → 100644
Empty file.
Empty file modified borb/pdf/canvas/color/color.py
100755 → 100644
Empty file.
Loading

0 comments on commit 8e92db0

Please sign in to comment.