For Leptonica 1.79+ use leptSetStderrHandler
Lock free and considerably less dangerous to stderr messages.
This commit is contained in:
@@ -24,7 +24,9 @@ import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import warnings
|
||||
from collections import deque
|
||||
from collections.abc import Sequence
|
||||
from contextlib import suppress
|
||||
from ctypes.util import find_library
|
||||
@@ -75,7 +77,7 @@ except ffi.error as e:
|
||||
) from e
|
||||
|
||||
|
||||
class _LeptonicaErrorTrap:
|
||||
class _LeptonicaErrorTrap_Redirect:
|
||||
"""
|
||||
Context manager to trap errors reported by Leptonica.
|
||||
|
||||
@@ -155,6 +157,62 @@ class _LeptonicaErrorTrap:
|
||||
return False
|
||||
|
||||
|
||||
tls = threading.local()
|
||||
tls.trap = None
|
||||
|
||||
|
||||
@ffi.callback("void(char *)")
|
||||
def _stderr_handler(cstr):
|
||||
msg = ffi.string(cstr).decode(errors='replace')
|
||||
if msg.startswith("Error"):
|
||||
logger.error(msg)
|
||||
elif msg.startswith("Warning"):
|
||||
logger.warning(msg)
|
||||
else:
|
||||
logger.debug(msg)
|
||||
if tls.trap is not None:
|
||||
tls.trap.append(msg)
|
||||
return
|
||||
|
||||
|
||||
class _LeptonicaErrorTrap_Queue:
|
||||
def __init__(self):
|
||||
self.queue = deque()
|
||||
|
||||
def __enter__(self):
|
||||
self.queue.clear()
|
||||
tls.trap = self.queue
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
tls.trap = None
|
||||
output = ''.join(self.queue)
|
||||
self.queue.clear()
|
||||
|
||||
# If there are Python errors, record them
|
||||
if exc_type:
|
||||
logger.warning(output)
|
||||
|
||||
if 'Error' in output:
|
||||
if 'image file not found' in output:
|
||||
raise FileNotFoundError()
|
||||
if 'pixWrite: stream not opened' in output:
|
||||
raise LeptonicaIOError()
|
||||
if 'index not valid' in output:
|
||||
raise IndexError()
|
||||
raise LeptonicaError(output)
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
lept.leptSetStderrHandler(_stderr_handler)
|
||||
except ffi.error:
|
||||
# Pre-1.79 Leptonica does not have leptSetStderrHandler
|
||||
_LeptonicaErrorTrap = _LeptonicaErrorTrap_Redirect
|
||||
else:
|
||||
# 1.79 have this new symbol
|
||||
_LeptonicaErrorTrap = _LeptonicaErrorTrap_Queue
|
||||
|
||||
|
||||
class LeptonicaError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -509,6 +509,8 @@ void selDestroy ( SEL **psel );
|
||||
l_int32
|
||||
setMsgSeverity(l_int32 newsev);
|
||||
|
||||
void
|
||||
leptSetStderrHandler(void (*handler)(const char *));
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
+15
-9
@@ -16,27 +16,25 @@
|
||||
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import os
|
||||
from os import fspath
|
||||
from pickle import dumps, loads
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageChops
|
||||
|
||||
import ocrmypdf.leptonica as lept
|
||||
from ocrmypdf import leptonica as lp
|
||||
|
||||
|
||||
def test_colormap_backgroundnorm(resources):
|
||||
# Issue #262 - unclear how to reproduce exactly, so just ensure leptonica
|
||||
# can handle that case
|
||||
pix = lept.Pix.open(resources / 'baiona_colormapped.png')
|
||||
pix = lp.Pix.open(resources / 'baiona_colormapped.png')
|
||||
pix.background_norm()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def crom_pix(resources):
|
||||
pix = lept.Pix.open(resources / 'crom.png')
|
||||
pix = lp.Pix.open(resources / 'crom.png')
|
||||
im = Image.open(resources / 'crom.png')
|
||||
yield pix, im
|
||||
im.close()
|
||||
@@ -64,17 +62,17 @@ def test_pix_otsu(crom_pix):
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
lept.get_leptonica_version() < 'leptonica-1.76',
|
||||
lp.get_leptonica_version() < 'leptonica-1.76',
|
||||
reason="needs new leptonica for API change",
|
||||
)
|
||||
def test_crop(resources):
|
||||
pix = lept.Pix.open(resources / 'linn.png')
|
||||
pix = lp.Pix.open(resources / 'linn.png')
|
||||
foreground = pix.crop_to_foreground()
|
||||
assert foreground.width < pix.width
|
||||
|
||||
|
||||
def test_clean_bg(resources):
|
||||
pix = lept.Pix.open(resources / 'congress.jpg')
|
||||
pix = lp.Pix.open(resources / 'congress.jpg')
|
||||
imbg = pix.clean_background_to_white()
|
||||
|
||||
|
||||
@@ -96,4 +94,12 @@ def test_leptonica_compile(tmp_path):
|
||||
|
||||
def test_file_not_found():
|
||||
with pytest.raises(FileNotFoundError):
|
||||
lept.Pix.open("does_not_exist1")
|
||||
lp.Pix.open("does_not_exist1")
|
||||
|
||||
|
||||
def test_error_trap():
|
||||
with pytest.raises(lp.LeptonicaError, match=r"Error in pixReadMem"):
|
||||
with lp._LeptonicaErrorTrap():
|
||||
lp.Pix(lp.lept.pixReadMem(lp.ffi.NULL, 0))
|
||||
with lp._LeptonicaErrorTrap_Redirect():
|
||||
lp.Pix(lp.lept.pixReadMem(lp.ffi.NULL, 0))
|
||||
|
||||
Reference in New Issue
Block a user