Compare commits
4 commits
3b117e674b
...
fb4b96452a
Author | SHA1 | Date | |
---|---|---|---|
fb4b96452a | |||
c553e169a4 | |||
d9345ac767 | |||
1d52530229 |
1 changed files with 68 additions and 23 deletions
|
@ -22,7 +22,17 @@ import sys
|
||||||
import os
|
import os
|
||||||
import zlib
|
import zlib
|
||||||
import argparse
|
import argparse
|
||||||
from PIL import Image, TiffImagePlugin
|
from PIL import Image, TiffImagePlugin, GifImagePlugin
|
||||||
|
|
||||||
|
if hasattr(GifImagePlugin, "LoadingStrategy"):
|
||||||
|
# Pillow 9.0.0 started emitting all frames but the first as RGB instead of
|
||||||
|
# P to make sure that more than 256 colors can be represented. But palette
|
||||||
|
# images compress far better than RGB images in PDF so we instruct Pillow
|
||||||
|
# to only emit RGB frames if the palette differs and return P otherwise.
|
||||||
|
# This works since Pillow 9.1.0.
|
||||||
|
GifImagePlugin.LOADING_STRATEGY = (
|
||||||
|
GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY
|
||||||
|
)
|
||||||
|
|
||||||
# TiffImagePlugin.DEBUG = True
|
# TiffImagePlugin.DEBUG = True
|
||||||
from PIL.ExifTags import TAGS
|
from PIL.ExifTags import TAGS
|
||||||
|
@ -91,7 +101,10 @@ ImageFormat = Enum("ImageFormat", "JPEG JPEG2000 CCITTGroup4 PNG GIF TIFF MPO ot
|
||||||
|
|
||||||
PageMode = Enum("PageMode", "none outlines thumbs")
|
PageMode = Enum("PageMode", "none outlines thumbs")
|
||||||
|
|
||||||
PageLayout = Enum("PageLayout", "single onecolumn twocolumnright twocolumnleft twopageright twopageleft")
|
PageLayout = Enum(
|
||||||
|
"PageLayout",
|
||||||
|
"single onecolumn twocolumnright twocolumnleft twopageright twopageleft",
|
||||||
|
)
|
||||||
|
|
||||||
Magnification = Enum("Magnification", "fit fith fitbh")
|
Magnification = Enum("Magnification", "fit fith fitbh")
|
||||||
|
|
||||||
|
@ -389,6 +402,28 @@ class ExifOrientationError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# temporary change the attribute of an object using a context manager
|
||||||
|
class temp_attr:
|
||||||
|
def __init__(self, obj, field, value):
|
||||||
|
self.obj = obj
|
||||||
|
self.field = field
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.exists = False
|
||||||
|
if hasattr(self.obj, self.field):
|
||||||
|
self.exists = True
|
||||||
|
self.old_value = getattr(self.obj, self.field)
|
||||||
|
print(f"setting {self.obj}.{self.field} = {self.value}")
|
||||||
|
setattr(self.obj, self.field, self.value)
|
||||||
|
|
||||||
|
def __exit__(self, exctype, excinst, exctb):
|
||||||
|
if self.exists:
|
||||||
|
setattr(self.obj, self.field, self.old_value)
|
||||||
|
else:
|
||||||
|
delattr(self.obj, self.field)
|
||||||
|
|
||||||
|
|
||||||
# without pdfrw this function is a no-op
|
# without pdfrw this function is a no-op
|
||||||
def my_convert_load(string):
|
def my_convert_load(string):
|
||||||
return string
|
return string
|
||||||
|
@ -1106,9 +1141,17 @@ class pdfdoc(object):
|
||||||
[initial_page, PdfName.XYZ, NullObject, NullObject, 0]
|
[initial_page, PdfName.XYZ, NullObject, NullObject, 0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# the /OpenAction array must contain the page as an indirect object
|
# The /OpenAction array must contain the page as an indirect object.
|
||||||
|
# This changed some time after 4.2.0 and on or before 5.0.0 and current
|
||||||
|
# versions require to use .obj or otherwise we get:
|
||||||
|
# TypeError: Can't convert ObjectHelper (or subclass) to Object
|
||||||
|
# implicitly. Use .obj to get access the underlying object.
|
||||||
|
# See https://github.com/pikepdf/pikepdf/issues/313 for details.
|
||||||
if self.engine == Engine.pikepdf:
|
if self.engine == Engine.pikepdf:
|
||||||
initial_page = self.writer.make_indirect(initial_page)
|
if isinstance(initial_page, pikepdf.Page):
|
||||||
|
initial_page = self.writer.make_indirect(initial_page.obj)
|
||||||
|
else:
|
||||||
|
initial_page = self.writer.make_indirect(initial_page)
|
||||||
|
|
||||||
if self.magnification == Magnification.fit:
|
if self.magnification == Magnification.fit:
|
||||||
catalog[PdfName.OpenAction] = PdfArray([initial_page, PdfName.Fit])
|
catalog[PdfName.OpenAction] = PdfArray([initial_page, PdfName.Fit])
|
||||||
|
@ -1410,27 +1453,29 @@ def transcode_monochrome(imgdata):
|
||||||
# into putting everything into a single strip. Thanks to Andrew Murray for
|
# into putting everything into a single strip. Thanks to Andrew Murray for
|
||||||
# the hack.
|
# the hack.
|
||||||
#
|
#
|
||||||
# This can be dropped once this gets merged:
|
# Since version 8.4.0 Pillow allows us to modify the strip size explicitly
|
||||||
# https://github.com/python-pillow/Pillow/pull/5744
|
tmp_strip_size = (imgdata.size[0] + 7) // 8 * imgdata.size[1]
|
||||||
pillow__getitem__ = TiffImagePlugin.ImageFileDirectory_v2.__getitem__
|
if hasattr(TiffImagePlugin, "STRIP_SIZE"):
|
||||||
|
# we are using Pillow 8.4.0 or later
|
||||||
|
with temp_attr(TiffImagePlugin, "STRIP_SIZE", tmp_strip_size):
|
||||||
|
im.save(newimgio, format="TIFF", compression="group4")
|
||||||
|
else:
|
||||||
|
# only needed for Pillow 8.3.x but works for versions before that as
|
||||||
|
# well
|
||||||
|
pillow__getitem__ = TiffImagePlugin.ImageFileDirectory_v2.__getitem__
|
||||||
|
|
||||||
def __getitem__(self, tag):
|
def __getitem__(self, tag):
|
||||||
overrides = {
|
overrides = {
|
||||||
TiffImagePlugin.ROWSPERSTRIP: imgdata.size[1],
|
TiffImagePlugin.ROWSPERSTRIP: imgdata.size[1],
|
||||||
TiffImagePlugin.STRIPBYTECOUNTS: [
|
TiffImagePlugin.STRIPBYTECOUNTS: [tmp_strip_size],
|
||||||
(imgdata.size[0] + 7) // 8 * imgdata.size[1]
|
TiffImagePlugin.STRIPOFFSETS: [0],
|
||||||
],
|
}
|
||||||
TiffImagePlugin.STRIPOFFSETS: [0],
|
return overrides.get(tag, pillow__getitem__(self, tag))
|
||||||
}
|
|
||||||
return overrides.get(tag, pillow__getitem__(self, tag))
|
|
||||||
|
|
||||||
# use try/finally to make sure that __getitem__ is reset even if save()
|
with temp_attr(
|
||||||
# raises an exception
|
TiffImagePlugin.ImageFileDirectory_v2, "__getitem__", __getitem__
|
||||||
try:
|
):
|
||||||
TiffImagePlugin.ImageFileDirectory_v2.__getitem__ = __getitem__
|
im.save(newimgio, format="TIFF", compression="group4")
|
||||||
im.save(newimgio, format="TIFF", compression="group4")
|
|
||||||
finally:
|
|
||||||
TiffImagePlugin.ImageFileDirectory_v2.__getitem__ = pillow__getitem__
|
|
||||||
|
|
||||||
# Open new image in memory
|
# Open new image in memory
|
||||||
newimgio.seek(0)
|
newimgio.seek(0)
|
||||||
|
|
Loading…
Reference in a new issue