# Path: kraken/lib/exceptions.py
# class KrakenCairoSurfaceException(Exception):
#     """
#     Raised when the Cairo surface couldn't be created.
# 
#     Attributes:
#         message (str): Error message
#         width (int): Width of the surface
#         height (int): Height of the surface
#     """
#     def __init__(self, message: str, width: int, height: int) -> None:
#         self.message = message
#         self.width = width
#         self.height = height
# 
#     def __repr__(self) -> str:
#         return repr(self.message)
# 
# Path: kraken/lib/util.py
# def pil2array(im: Image.Image, alpha: int = 0) -> np.ndarray:
#     if im.mode == '1':
#         return np.array(im.convert('L'))
#     return np.array(im)
# 
# def array2pil(a: np.ndarray) -> Image.Image:
#     if a.dtype == np.dtype("B"):
#         if a.ndim == 2:
#             return Image.frombytes("L", (a.shape[1], a.shape[0]),
#                                    a.tobytes())
#         elif a.ndim == 3:
#             return Image.frombytes("RGB", (a.shape[1], a.shape[0]),
#                                    a.tobytes())
#         else:
#             raise Exception("bad image rank")
#     elif a.dtype == np.dtype('float32'):
#         return Image.frombytes("F", (a.shape[1], a.shape[0]), a.tobytes())
#     else:
#         raise Exception("unknown image type")


from scipy.ndimage.filters import gaussian_filter
from scipy.ndimage.measurements import find_objects
from scipy.ndimage.morphology import distance_transform_cdt, binary_closing
from scipy.ndimage.interpolation import affine_transform, geometric_transform
from PIL import Image, ImageOps
from typing import AnyStr
from kraken.lib.exceptions import KrakenCairoSurfaceException
from kraken.lib.util import pil2array, array2pil
import logging
import ctypes
import ctypes.util
import numpy as np
        ws = gaussian_filter(ws, dsigma)
        hs *= distort / np.amax(hs)
        ws *= distort / np.amax(ws)

        def _f(p):
            return (p[0] + hs[p[0], p[1]], p[1] + ws[p[0], p[1]])

        a = geometric_transform(a, _f, output_shape=(h, w), order=1, mode='constant', cval=np.amax(a))
    im = array2pil(a).convert('L')
    return im


def degrade_line(im, eta=0.0, alpha=1.5, beta=1.5, alpha_0=1.0, beta_0=1.0):
    """
    Degrades a line image by adding noise.

    For parameter meanings consult [1].

    Args:
        im (PIL.Image): Input image
        eta (float):
        alpha (float):
        beta (float):
        alpha_0 (float):
        beta_0 (float):

    Returns:
        PIL.Image in mode '1'
    """
    logger.debug('Inverting and normalizing input image')

# Path: kraken/lib/exceptions.py
# class KrakenCairoSurfaceException(Exception):
#     """
#     Raised when the Cairo surface couldn't be created.
# 
#     Attributes:
#         message (str): Error message
#         width (int): Width of the surface
#         height (int): Height of the surface
#     """
#     def __init__(self, message: str, width: int, height: int) -> None:
#         self.message = message
#         self.width = width
#         self.height = height
# 
#     def __repr__(self) -> str:
#         return repr(self.message)
# 
# Path: kraken/lib/util.py
# def pil2array(im: Image.Image, alpha: int = 0) -> np.ndarray:
#     if im.mode == '1':
#         return np.array(im.convert('L'))
#     return np.array(im)
# 
# def array2pil(a: np.ndarray) -> Image.Image:
#     if a.dtype == np.dtype("B"):
#         if a.ndim == 2:
#             return Image.frombytes("L", (a.shape[1], a.shape[0]),
#                                    a.tobytes())
#         elif a.ndim == 3:
#             return Image.frombytes("RGB", (a.shape[1], a.shape[0]),
#                                    a.tobytes())
#         else:
#             raise Exception("bad image rank")
#     elif a.dtype == np.dtype('float32'):
#         return Image.frombytes("F", (a.shape[1], a.shape[0]), a.tobytes())
#     else:
#         raise Exception("unknown image type")


# Path: kraken/linegen.py
from scipy.ndimage.filters import gaussian_filter
from scipy.ndimage.measurements import find_objects
from scipy.ndimage.morphology import distance_transform_cdt, binary_closing
from scipy.ndimage.interpolation import affine_transform, geometric_transform
from PIL import Image, ImageOps
from typing import AnyStr
from kraken.lib.exceptions import KrakenCairoSurfaceException
from kraken.lib.util import pil2array, array2pil
import logging
import ctypes
import ctypes.util
import numpy as np

        ws = gaussian_filter(ws, dsigma)
        hs *= distort / np.amax(hs)
        ws *= distort / np.amax(ws)

        def _f(p):
            return (p[0] + hs[p[0], p[1]], p[1] + ws[p[0], p[1]])

        a = geometric_transform(a, _f, output_shape=(h, w), order=1, mode='constant', cval=np.amax(a))
    im = array2pil(a).convert('L')
    return im


def degrade_line(im, eta=0.0, alpha=1.5, beta=1.5, alpha_0=1.0, beta_0=1.0):
    """
    Degrades a line image by adding noise.

    For parameter meanings consult [1].

    Args:
        im (PIL.Image): Input image
        eta (float):
        alpha (float):
        beta (float):
        alpha_0 (float):
        beta_0 (float):

    Returns:
        PIL.Image in mode '1'
    """
    logger.debug('Inverting and normalizing input image')

    im = pil2array(im)