# 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
        PIL.Image in mode '1'
    """
    logger.debug('Inverting and normalizing input image')
    im = pil2array(im)
    im = np.amax(im)-im
    im = im*1.0/np.amax(im)

    logger.debug('Calculating foreground distance transform')
    fg_dist = distance_transform_cdt(1-im, metric='taxicab')
    logger.debug('Calculating flip to white probability')
    fg_prob = alpha_0 * np.exp(-alpha * (fg_dist**2)) + eta
    fg_prob[im == 1] = 0
    fg_flip = np.random.binomial(1, fg_prob)

    logger.debug('Calculating background distance transform')
    bg_dist = distance_transform_cdt(im, metric='taxicab')
    logger.debug('Calculating flip to black probability')
    bg_prob = beta_0 * np.exp(-beta * (bg_dist**2)) + eta
    bg_prob[im == 0] = 0
    bg_flip = np.random.binomial(1, bg_prob)

    # flip
    logger.debug('Flipping')
    im -= bg_flip
    im += fg_flip

    logger.debug('Binary closing')
    sel = np.array([[1, 1], [1, 1]])
    im = binary_closing(im, sel)
    logger.debug('Converting to 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

        PIL.Image in mode '1'
    """
    logger.debug('Inverting and normalizing input image')
    im = pil2array(im)
    im = np.amax(im)-im
    im = im*1.0/np.amax(im)

    logger.debug('Calculating foreground distance transform')
    fg_dist = distance_transform_cdt(1-im, metric='taxicab')
    logger.debug('Calculating flip to white probability')
    fg_prob = alpha_0 * np.exp(-alpha * (fg_dist**2)) + eta
    fg_prob[im == 1] = 0
    fg_flip = np.random.binomial(1, fg_prob)

    logger.debug('Calculating background distance transform')
    bg_dist = distance_transform_cdt(im, metric='taxicab')
    logger.debug('Calculating flip to black probability')
    bg_prob = beta_0 * np.exp(-beta * (bg_dist**2)) + eta
    bg_prob[im == 0] = 0
    bg_flip = np.random.binomial(1, bg_prob)

    # flip
    logger.debug('Flipping')
    im -= bg_flip
    im += fg_flip

    logger.debug('Binary closing')
    sel = np.array([[1, 1], [1, 1]])
    im = binary_closing(im, sel)
    logger.debug('Converting to image')

    return array2pil(255-im.astype('B')*255)