Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c96823a648 | ||
|
|
3807b7d655 | ||
|
|
a45505cf1d | ||
|
|
b4a734fc0d | ||
|
|
bbd02926e1 | ||
|
|
5022ded276 | ||
|
|
c7612152ef | ||
|
|
af91642cd1 | ||
|
|
9c66334c38 | ||
|
|
8d79b94b84 | ||
|
|
d7f60b96c1 | ||
|
|
b964999427 | ||
|
|
3473345ea6 | ||
|
|
349ec5c81f |
@@ -18,9 +18,3 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----
|
||||
|
||||
sRGB_IEC61966-2-1_black_scaled.icc
|
||||
|
||||
To anyone who acknowledges that the file "sRGB_IEC61966-2-1_black scaled.icc" is provided "AS IS" WITH NO EXPRESS OR IMPLIED WARRANTY, permission to use, copy and distribute these file for any purpose is hereby granted without fee, provided that the file is not changed including the ICC copyright notice tag, and that the name of ICC shall not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. ICC makes no representations about the suitability of this software for any purpose.
|
||||
+7
-1
@@ -187,7 +187,13 @@ Ubuntu 14.04 only installs ``unpaper`` version 0.4.2, which is not supported by
|
||||
Installing on Windows
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Direct installation on Windows is not possible. Install the Docker container as described above.
|
||||
Direct installation on Windows is not possible. Install the Docker container as described above. Ensure that your command prompt can run the docker "hello world" container.
|
||||
|
||||
The command line syntax to run ocrmypdf from a command prompt will resemble::
|
||||
|
||||
docker run -v /c/Users/sampleuser:/home/docker ocrmypdf --skip-text test.pdf output.pdf
|
||||
|
||||
where /c/Users/sampleuser is a Unix representation of the Windows path C:\Users\sampleuser, assuming a user named "sampleuser" is running ocrmypdf on a file in their home directory, and the files "test.pdf" and "output.pdf" are in the sampleuser folder. The Windows user must have read and write permissions.
|
||||
|
||||
|
||||
Installing HEAD revision from sources
|
||||
|
||||
@@ -6,6 +6,22 @@ Please always read this file before installing the package
|
||||
Download software here: https://github.com/jbarlow83/OCRmyPDF/tags
|
||||
|
||||
|
||||
v4.1.3:
|
||||
=======
|
||||
|
||||
- More helpful error message for PDFs with version 4 security handler
|
||||
- Update usage instructions for Windows/Docker users
|
||||
- Fix order of operations for matrix multiplication (no effect on most users)
|
||||
- Add a few leptonica wrapper functions (no effect on most users)
|
||||
|
||||
|
||||
v4.1.2:
|
||||
=======
|
||||
|
||||
- Replace IEC sRGB ICC profile with Debian's sRGB (from icc-profiles-free) which is more compatible with the MIT license
|
||||
- More helpful error message for an error related to certain types of malformed PDFs
|
||||
|
||||
|
||||
v4.1:
|
||||
=====
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class ExitCode(IntEnum):
|
||||
file_access_error = 5
|
||||
already_done_ocr = 6
|
||||
child_process_error = 7
|
||||
encrypted_pdf = 8
|
||||
other_error = 15
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+200
-25
@@ -17,6 +17,7 @@ from tempfile import TemporaryFile
|
||||
from ctypes.util import find_library
|
||||
from .lib._leptonica import ffi
|
||||
from functools import lru_cache
|
||||
from enum import Enum
|
||||
|
||||
lept = ffi.dlopen(find_library('lept'))
|
||||
|
||||
@@ -83,6 +84,13 @@ class LeptonicaIOError(LeptonicaError):
|
||||
pass
|
||||
|
||||
|
||||
class RemoveColormap(Enum):
|
||||
to_binary = 0
|
||||
to_grayscale = 1
|
||||
to_full_color = 2
|
||||
based_on_src = 3
|
||||
|
||||
|
||||
class Pix:
|
||||
"""Wrapper around leptonica's PIX object.
|
||||
|
||||
@@ -98,14 +106,14 @@ class Pix:
|
||||
in a threadsafe manner if a Python threading.Lock protects the data.
|
||||
"""
|
||||
|
||||
def __init__(self, cpix):
|
||||
self.cpix = ffi.gc(cpix, Pix._pix_destroy)
|
||||
def __init__(self, pix):
|
||||
self._pix = ffi.gc(pix, Pix._pix_destroy)
|
||||
|
||||
def __repr__(self):
|
||||
if self.cpix:
|
||||
if self._pix:
|
||||
s = "<leptonica.Pix image size={0}x{1} depth={2} at 0x{3:x}>"
|
||||
return s.format(self.cpix.w, self.cpix.h, self.cpix.d,
|
||||
int(ffi.cast("intptr_t", self.cpix)))
|
||||
return s.format(self._pix.w, self._pix.h, self._pix.d,
|
||||
int(ffi.cast("intptr_t", self._pix)))
|
||||
else:
|
||||
return "<leptonica.Pix image NULL>"
|
||||
|
||||
@@ -113,12 +121,16 @@ class Pix:
|
||||
data = ffi.new('l_uint32 **')
|
||||
size = ffi.new('size_t *')
|
||||
|
||||
err = lept.pixSerializeToMemory(self.cpix, data, size)
|
||||
err = lept.pixSerializeToMemory(self._pix, data, size)
|
||||
if err != 0:
|
||||
raise LeptonicaIOError("pixSerializeToMemory")
|
||||
|
||||
char_data = ffi.cast('char *', data[0])
|
||||
|
||||
# Copy from C bytes to python bytes()
|
||||
data_bytes = ffi.buffer(char_data, size[0])[:]
|
||||
|
||||
# Can now free C bytes
|
||||
lept.lept_free(char_data)
|
||||
return dict(data=data_bytes)
|
||||
|
||||
@@ -126,16 +138,41 @@ class Pix:
|
||||
cdata_bytes = ffi.new('char[]', state['data'])
|
||||
cdata_uint32 = ffi.cast('l_uint32 *', cdata_bytes)
|
||||
|
||||
self.cpix = lept.pixDeserializeFromMemory(
|
||||
pix = lept.pixDeserializeFromMemory(
|
||||
cdata_uint32, len(state['data']))
|
||||
Pix.__init__(self, pix)
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.cpix.w
|
||||
return self._pix.w
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.cpix.h
|
||||
return self._pix.h
|
||||
|
||||
@property
|
||||
def depth(self):
|
||||
return self._pix.d
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return (self._pix.w, self._pix.h)
|
||||
|
||||
@property
|
||||
def info(self):
|
||||
return {'dpi': (self._pix.xres, self._pix.yres)}
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
"Return mode like PIL.Image"
|
||||
if self.depth == 1:
|
||||
return '1'
|
||||
elif self.depth >= 16:
|
||||
return 'RGB'
|
||||
elif not self._pix.colormap:
|
||||
return 'L'
|
||||
else:
|
||||
return 'P'
|
||||
|
||||
@classmethod
|
||||
def read(cls, filename):
|
||||
@@ -158,7 +195,29 @@ class Pix:
|
||||
with LeptonicaErrorTrap():
|
||||
lept.pixWriteImpliedFormat(
|
||||
filename.encode(sys.getfilesystemencoding()),
|
||||
self.cpix, jpeg_quality, jpeg_progressive)
|
||||
self._pix, jpeg_quality, jpeg_progressive)
|
||||
|
||||
def topil(self):
|
||||
"Returns a PIL.Image version of this Pix"
|
||||
from PIL import Image
|
||||
|
||||
with LeptonicaErrorTrap():
|
||||
pix_swapped = Pix(lept.pixEndianByteSwapNew(self._pix))
|
||||
|
||||
size = (pix_swapped._pix.wpl * 4, pix_swapped._pix.h)
|
||||
buf = ffi.buffer(pix_swapped._pix.data, size[0] * size[1])
|
||||
|
||||
im_raw = Image.frombytes(self.mode, size, buf, 'raw')
|
||||
|
||||
# Leptonica stores images in 32-bit words
|
||||
# Need to crop the any trailing amount
|
||||
box = (0, 0, self.width, self.height)
|
||||
im = im_raw.crop(box)
|
||||
|
||||
return im
|
||||
|
||||
def show(self):
|
||||
return self.topil().show()
|
||||
|
||||
def deskew(self, reduction_factor=0):
|
||||
"""Returns the deskewed pix object.
|
||||
@@ -170,16 +229,21 @@ class Pix:
|
||||
for skew angle
|
||||
"""
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixDeskew(self.cpix, reduction_factor))
|
||||
return Pix(lept.pixDeskew(self._pix, reduction_factor))
|
||||
|
||||
def scale(self, scalex, scaley):
|
||||
"Returns the pix object rescaled according to the proportions given."
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixScale(self.cpix, scalex, scaley))
|
||||
return Pix(lept.pixScale(self._pix, scalex, scaley))
|
||||
|
||||
def rotate180(self):
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixRotate180(ffi.NULL, self.cpix))
|
||||
return Pix(lept.pixRotate180(ffi.NULL, self._pix))
|
||||
|
||||
def rotate_orth(self, quads):
|
||||
"Orthographic rotation, quads: 0-3, number of clockwise rotations"
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixRotateOrth(self._pix, quads))
|
||||
|
||||
def find_skew(self):
|
||||
"""Returns a tuple (deskew angle in degrees, confidence value).
|
||||
@@ -189,31 +253,105 @@ class Pix:
|
||||
with LeptonicaErrorTrap():
|
||||
angle = ffi.new('float *', 0.0)
|
||||
confidence = ffi.new('float *', 0.0)
|
||||
result = lept.pixFindSkew(self.cpix, angle, confidence)
|
||||
result = lept.pixFindSkew(self._pix, angle, confidence)
|
||||
if result == 0:
|
||||
return (angle[0], confidence[0])
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
def convert_rgb_to_luminance(self):
|
||||
with LeptonicaErrorTrap():
|
||||
gray_pix = lept.pixConvertRGBToLuminance(self._pix)
|
||||
if gray_pix:
|
||||
return Pix(gray_pix)
|
||||
return None
|
||||
|
||||
def remove_colormap(self, removal_type):
|
||||
"""Remove a palette
|
||||
|
||||
removal_type - RemovalColormap()
|
||||
"""
|
||||
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixRemoveColormap(self._pix, removal_type))
|
||||
|
||||
def otsu_adaptive_threshold(
|
||||
self, tile_size=(300, 300), kernel_size=(4, 4), scorefract=0.1):
|
||||
with LeptonicaErrorTrap():
|
||||
sx, sy = tile_size
|
||||
smoothx, smoothy = kernel_size
|
||||
p_cpix = ffi.new('PIX **')
|
||||
p_pix = ffi.new('PIX **')
|
||||
|
||||
result = lept.pixOtsuAdaptiveThreshold(
|
||||
self.cpix,
|
||||
self._pix,
|
||||
sx, sy,
|
||||
smoothx, smoothy,
|
||||
scorefract,
|
||||
ffi.NULL,
|
||||
p_cpix)
|
||||
p_pix)
|
||||
if result == 0:
|
||||
return Pix(p_cpix[0])
|
||||
return Pix(p_pix[0])
|
||||
else:
|
||||
return None
|
||||
|
||||
def otsu_threshold_on_background_norm(
|
||||
self, mask=None, tile_size=(10, 15), thresh=100, mincount=50,
|
||||
bgval=255, kernel_size=(2, 2), scorefract=0.1):
|
||||
with LeptonicaErrorTrap():
|
||||
sx, sy = tile_size
|
||||
smoothx, smoothy = kernel_size
|
||||
if mask is None:
|
||||
mask = ffi.NULL
|
||||
if isinstance(mask, Pix):
|
||||
mask = mask._pix
|
||||
|
||||
thresh_pix = lept.pixOtsuThreshOnBackgroundNorm(
|
||||
self._pix,
|
||||
mask,
|
||||
sx, sy,
|
||||
thresh, mincount, bgval,
|
||||
smoothx, smoothy,
|
||||
scorefract,
|
||||
ffi.NULL
|
||||
)
|
||||
if thresh_pix == ffi.NULL:
|
||||
return None
|
||||
return Pix(thresh_pix)
|
||||
|
||||
def crop_to_foreground(
|
||||
self, threshold=128, mindist=70, erasedist=30, pagenum=0,
|
||||
showmorph=0, display=0, pdfdir=ffi.NULL):
|
||||
with LeptonicaErrorTrap():
|
||||
cropbox = Box(lept.pixFindPageForeground(
|
||||
self._pix,
|
||||
threshold,
|
||||
mindist,
|
||||
erasedist,
|
||||
pagenum,
|
||||
showmorph,
|
||||
display,
|
||||
pdfdir))
|
||||
|
||||
print(repr(cropbox))
|
||||
|
||||
cropped_pix = lept.pixClipRectangle(
|
||||
self._pix,
|
||||
cropbox._box,
|
||||
ffi.NULL)
|
||||
|
||||
return Pix(cropped_pix)
|
||||
|
||||
def clean_background_to_white(
|
||||
self, mask=None, grayscale=None, gamma=1.0, black=0, white=255):
|
||||
with LeptonicaErrorTrap():
|
||||
return Pix(lept.pixCleanBackgroundToWhite(
|
||||
self._pix,
|
||||
mask or ffi.NULL,
|
||||
grayscale or ffi.NULL,
|
||||
gamma,
|
||||
black,
|
||||
white))
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=1)
|
||||
def make_pixel_sum_tab8():
|
||||
@@ -230,10 +368,10 @@ class Pix:
|
||||
pixn_count = ffi.new('l_int32 *')
|
||||
tab8 = Pix.make_pixel_sum_tab8()
|
||||
|
||||
lept.pixCountPixels(pix1.cpix, pix1_count, tab8)
|
||||
lept.pixCountPixels(pix2.cpix, pix2_count, tab8)
|
||||
pixn = Pix(lept.pixAnd(ffi.NULL, pix1.cpix, pix2.cpix))
|
||||
lept.pixCountPixels(pixn.cpix, pixn_count, tab8)
|
||||
lept.pixCountPixels(pix1._pix, pix1_count, tab8)
|
||||
lept.pixCountPixels(pix2._pix, pix2_count, tab8)
|
||||
pixn = Pix(lept.pixAnd(ffi.NULL, pix1._pix, pix2._pix))
|
||||
lept.pixCountPixels(pixn._pix, pixn_count, tab8)
|
||||
|
||||
# Python converts these int32s to larger units as needed
|
||||
# to avoid overflow. Overflow happens easily here.
|
||||
@@ -244,7 +382,7 @@ class Pix:
|
||||
return correlation
|
||||
else:
|
||||
correlation = ffi.new('float *', 0.0)
|
||||
result = lept.pixCorrelationBinary(pix1.cpix, pix2.cpix,
|
||||
result = lept.pixCorrelationBinary(pix1._pix, pix2._pix,
|
||||
correlation)
|
||||
if result != 0:
|
||||
raise LeptonicaError("Correlation failed")
|
||||
@@ -252,11 +390,48 @@ class Pix:
|
||||
|
||||
@staticmethod
|
||||
def _pix_destroy(pix):
|
||||
ptr_to_pix = ffi.new('PIX **', pix)
|
||||
lept.pixDestroy(ptr_to_pix)
|
||||
p_pix = ffi.new('PIX **', pix)
|
||||
lept.pixDestroy(p_pix)
|
||||
# print('pix destroy ' + repr(pix))
|
||||
|
||||
|
||||
class Box:
|
||||
"""Wrapper around Leptonica's BOX objects.
|
||||
|
||||
See class Pix for notes about reference counting.
|
||||
"""
|
||||
|
||||
def __init__(self, box):
|
||||
self._box = ffi.gc(box, Box._box_destroy)
|
||||
|
||||
def __repr__(self):
|
||||
if self._box:
|
||||
return '<leptonica.Box x={0} y={1} w={2} h={3}>'.format(
|
||||
self.x, self.y, self.w, self.h)
|
||||
return '<leptonica.Box NULL>'
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._box.x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._box.y
|
||||
|
||||
@property
|
||||
def w(self):
|
||||
return self._box.w
|
||||
|
||||
@property
|
||||
def h(self):
|
||||
return self._box.h
|
||||
|
||||
@staticmethod
|
||||
def _box_destroy(box):
|
||||
p_box = ffi.new('BOX **', box)
|
||||
lept.boxDestroy(p_box)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_leptonica_version():
|
||||
"""Get Leptonica version string.
|
||||
|
||||
@@ -42,6 +42,18 @@ struct PixColormap
|
||||
l_int32 n; /* number of color entries used */
|
||||
};
|
||||
typedef struct PixColormap PIXCMAP;
|
||||
|
||||
struct Box
|
||||
{
|
||||
l_int32 x;
|
||||
l_int32 y;
|
||||
l_int32 w;
|
||||
l_int32 h;
|
||||
l_uint32 refcount; /* reference count (1 if no clones) */
|
||||
|
||||
};
|
||||
typedef struct Box BOX;
|
||||
|
||||
""")
|
||||
|
||||
ffi.cdef("""
|
||||
@@ -50,10 +62,17 @@ PIX * pixScale ( PIX *pixs, l_float32 scalex, l_float32 scaley );
|
||||
l_int32 pixFindSkew ( PIX *pixs, l_float32 *pangle, l_float32 *pconf );
|
||||
l_int32 pixWriteImpliedFormat ( const char *filename, PIX *pix, l_int32 quality, l_int32 progressive );
|
||||
void pixDestroy ( PIX **ppix );
|
||||
|
||||
PIX *
|
||||
pixEndianByteSwapNew(PIX *pixs);
|
||||
|
||||
PIX * pixDeskew ( PIX *pixs, l_int32 redsearch );
|
||||
char * getLeptonicaVersion ( );
|
||||
l_int32 pixCorrelationBinary(PIX *pix1, PIX *pix2, l_float32 *pval);
|
||||
PIX *pixRotate180(PIX *pixd, PIX *pixs);
|
||||
PIX *
|
||||
pixRotateOrth(PIX *pixs,
|
||||
l_int32 quads);
|
||||
|
||||
l_int32 pixCountPixels ( PIX *pix, l_int32 *pcount, l_int32 *tab8 );
|
||||
PIX * pixAnd ( PIX *pixd, PIX *pixs1, PIX *pixs2 );
|
||||
@@ -62,6 +81,10 @@ l_int32 * makePixelSumTab8 ( void );
|
||||
PIX * pixDeserializeFromMemory ( const l_uint32 *data, size_t nbytes );
|
||||
l_int32 pixSerializeToMemory ( PIX *pixs, l_uint32 **pdata, size_t *pnbytes );
|
||||
|
||||
PIX * pixConvertRGBToLuminance(PIX *pixs);
|
||||
|
||||
PIX * pixRemoveColormap(PIX *pixs, l_int32 type);
|
||||
|
||||
l_int32
|
||||
pixOtsuAdaptiveThreshold(PIX *pixs,
|
||||
l_int32 sx,
|
||||
@@ -72,6 +95,45 @@ pixOtsuAdaptiveThreshold(PIX *pixs,
|
||||
PIX **ppixth,
|
||||
PIX **ppixd);
|
||||
|
||||
PIX *
|
||||
pixOtsuThreshOnBackgroundNorm(PIX *pixs,
|
||||
PIX *pixim,
|
||||
l_int32 sx,
|
||||
l_int32 sy,
|
||||
l_int32 thresh,
|
||||
l_int32 mincount,
|
||||
l_int32 bgval,
|
||||
l_int32 smoothx,
|
||||
l_int32 smoothy,
|
||||
l_float32 scorefract,
|
||||
l_int32 *pthresh);
|
||||
|
||||
PIX *
|
||||
pixCleanBackgroundToWhite(PIX *pixs,
|
||||
PIX *pixim,
|
||||
PIX *pixg,
|
||||
l_float32 gamma,
|
||||
l_int32 blackval,
|
||||
l_int32 whiteval);
|
||||
|
||||
BOX *
|
||||
pixFindPageForeground(PIX *pixs,
|
||||
l_int32 threshold,
|
||||
l_int32 mindist,
|
||||
l_int32 erasedist,
|
||||
l_int32 pagenum,
|
||||
l_int32 showmorph,
|
||||
l_int32 display,
|
||||
const char *pdfdir);
|
||||
|
||||
PIX *
|
||||
pixClipRectangle(PIX *pixs,
|
||||
BOX *box,
|
||||
BOX **pboxc);
|
||||
|
||||
void
|
||||
boxDestroy(BOX **pbox);
|
||||
|
||||
void lept_free(void *ptr);
|
||||
""")
|
||||
|
||||
|
||||
+35
-2
@@ -797,6 +797,10 @@ def render_hocr_debug_page(
|
||||
showBoundingboxes=True, invisibleText=False)
|
||||
|
||||
|
||||
class PdfMergeFailedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@active_if(options.pdf_renderer == 'hocr')
|
||||
@collate(
|
||||
input=[render_hocr_page, select_image_layer],
|
||||
@@ -855,8 +859,13 @@ def add_text_layer(
|
||||
log.info("{0:4d}: rotating image layer {1} degrees".format(
|
||||
page_number(image), rotation, tx, ty))
|
||||
|
||||
page_text.mergeRotatedScaledTranslatedPage(
|
||||
page_image, rotation, 1.0, tx, ty, expand=False)
|
||||
try:
|
||||
page_text.mergeRotatedScaledTranslatedPage(
|
||||
page_image, rotation, 1.0, tx, ty, expand=False)
|
||||
except (AttributeError, ValueError) as e:
|
||||
if 'writeToStream' in str(e) or 'invalid literal' in str(e):
|
||||
raise PdfMergeFailedError() from e
|
||||
|
||||
|
||||
pdf_output = pypdf.PdfFileWriter()
|
||||
pdf_output.addPage(page_text)
|
||||
@@ -1058,6 +1067,30 @@ def do_ruffus_exception(ruffus_five_tuple):
|
||||
msg = "Error occurred while running this command:"
|
||||
_log.error(msg + '\n' + exc_value)
|
||||
return ExitCode.child_process_error
|
||||
elif exc_name == 'ocrmypdf.main.PdfMergeFailedError':
|
||||
_log.error(textwrap.dedent("""\
|
||||
Failed to merge PDF image layer with OCR layer
|
||||
|
||||
Usually this happens because the input PDF file is mal-formed and
|
||||
ocrmypdf cannot automatically correct the problem on its own.
|
||||
|
||||
Try using
|
||||
ocrmypdf --pdf-renderer tesseract [..other args..]
|
||||
"""))
|
||||
return ExitCode.input_file
|
||||
elif exc_name == 'PyPDF2.utils.PdfReadError' and \
|
||||
'not been decrypted' in exc_value:
|
||||
_log.error(textwrap.dedent("""\
|
||||
Input PDF uses either an encryption algorithm or a PDF security
|
||||
handler that is not supported by ocrmypdf.
|
||||
|
||||
For information about this PDF's security use
|
||||
qpdf --show-encryption [...input PDF...]
|
||||
|
||||
(Only algorithms "R = 1" and "R = 2" are supported.)
|
||||
|
||||
"""))
|
||||
return ExitCode.encrypted_pdf
|
||||
elif not options.verbose:
|
||||
_log.error(exc_stack)
|
||||
return ExitCode.other_error
|
||||
|
||||
@@ -93,7 +93,7 @@ def _interpret_contents(contentstream):
|
||||
ctm = stack.pop()
|
||||
elif command == b'cm':
|
||||
ctm = matrix_mult(
|
||||
ctm, _matrix_from_shorthand(operands))
|
||||
_matrix_from_shorthand(operands), ctm)
|
||||
elif command == b'Do':
|
||||
image_name = operands[0]
|
||||
image_raster_settings.append(
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ from string import Template
|
||||
import codecs
|
||||
import pkg_resources
|
||||
|
||||
ICC_PROFILE_RELPATH = 'data/sRGB_IEC61966-2-1_black_scaled.icc'
|
||||
ICC_PROFILE_RELPATH = 'data/sRGB.icc'
|
||||
|
||||
SRGB_ICC_PROFILE = pkg_resources.resource_filename(
|
||||
'ocrmypdf', ICC_PROFILE_RELPATH)
|
||||
|
||||
@@ -230,6 +230,6 @@ setup(
|
||||
'ocrmypdf = ocrmypdf.main:run_pipeline'
|
||||
],
|
||||
},
|
||||
package_data={'ocrmypdf': ['data/sRGB_IEC61966-2-1_black_scaled.icc']},
|
||||
package_data={'ocrmypdf': ['data/sRGB.icc']},
|
||||
include_package_data=True,
|
||||
zip_safe=False)
|
||||
|
||||
Binary file not shown.
@@ -547,3 +547,7 @@ def test_old_unpaper():
|
||||
'c02-22.pdf', 'wont_be_created.pdf', '--clean', env=env)
|
||||
assert sh.returncode == ExitCode.missing_dependency
|
||||
|
||||
|
||||
def test_algo4():
|
||||
sh, _, _ = run_ocrmypdf_env('encrypted_algo4.pdf', 'wontwork.pdf')
|
||||
assert sh.returncode == ExitCode.encrypted_pdf
|
||||
|
||||
Reference in New Issue
Block a user