    module Graphics.GD.ByteString.Lazy (
                        -- * Types
                        Image, Size, Point, Color,
                        -- * Creating and copying images
                        GD.newImage, GD.copyImage,
                        GD.copyRegion, GD.copyRegionScaled,
                        -- * Memory management
                        GD.withImage,
                        -- * Loading images
                        -- ** JPEG
                        loadJpegFile, loadJpegData, loadJpegByteString,
                        -- ** PNG
                        loadPngFile, loadPngData, loadPngByteString,
                        -- ** GIF
                        loadGifFile, loadGifData, loadGifByteString,
                        -- * Saving images
                        -- ** JPEG
                        saveJpegFile, saveJpegByteString,
                        -- ** PNG
                        savePngFile, savePngByteString,
                        -- ** GIF
                        saveGifFile, saveGifByteString,
                        -- * Getting image information
                        GD.imageSize,
                        -- * Querying
                        GD.getPixel,
                        -- * Manipulating images
                        GD.resizeImage, GD.rotateImage,
                        -- * Drawing
                        GD.fillImage,
                        GD.drawFilledRectangle,
                        GD.drawFilledEllipse,
                        GD.drawLine,
                        GD.drawArc,
                        GD.antiAliased,
                        GD.setPixel,
                        -- * Text
                        GD.useFontConfig,
                        drawString,
                        measureString,
                        drawStringCircle,
                        -- * Colors
                        GD.rgb, GD.rgba, GD.toRGBA
                       ) where

    import           Graphics.GD.Internal     (Point,Color,Image,GDImage,CFILE,Size)
    import qualified Graphics.GD.Internal     as GD

    import qualified Data.ByteString          as B
    import qualified Data.ByteString.Lazy     as L
    import qualified Data.ByteString.Internal as BI

    import           Control.Monad            (liftM,unless)
    import           Foreign                  (Ptr)
    import qualified Foreign                  as F
    import           Foreign                  (peek)
    import           Foreign.C                (CInt)
    import           Foreign.C                (peekCAString,peekCAString)

    --
    -- * Loading images
    --

    -- | Load a JPEG image from a file.
    loadJpegFile :: FilePath -> IO Image
    loadJpegFile :: FilePath -> IO Image
    loadJpegFile = (Ptr CFILE -> IO (Ptr GDImage)) -> FilePath -> IO Image
    loadImageFile Ptr CFILE -> IO (Ptr GDImage)
    GD.gdImageCreateFromJpeg

    -- | Load a JPEG image from a buffer.
    loadJpegData :: Int   -- ^ Buffer size.
                 -> Ptr a -- ^ Buffer with image data.
                 -> IO Image
    loadJpegData :: forall a. Int -> Ptr a -> IO Image
    loadJpegData = (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    forall a.
    (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    loadImageData CInt -> Ptr a -> IO (Ptr GDImage)
    forall a. CInt -> Ptr a -> IO (Ptr GDImage)
    GD.gdImageCreateFromJpegPtr

    -- | Load a JPEG image from a ByteString
    loadJpegByteString :: L.ByteString -> IO Image
    loadJpegByteString :: ByteString -> IO Image
    loadJpegByteString = (Int -> Ptr (ZonkAny 5) -> IO Image) -> ByteString -> IO Image
    forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
    onByteStringData Int -> Ptr (ZonkAny 5) -> IO Image
    forall a. Int -> Ptr a -> IO Image
    loadJpegData

    -- | Load a PNG image from a file.
    loadPngFile :: FilePath -> IO Image
    loadPngFile :: FilePath -> IO Image
    loadPngFile = (Ptr CFILE -> IO (Ptr GDImage)) -> FilePath -> IO Image
    loadImageFile Ptr CFILE -> IO (Ptr GDImage)
    GD.gdImageCreateFromPng

    -- | Load a PNG image from a buffer.
    loadPngData :: Int   -- ^ Buffer size.
                -> Ptr a -- ^ Buffer with image data.
                -> IO Image
    loadPngData :: forall a. Int -> Ptr a -> IO Image
    loadPngData = (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    forall a.
    (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    loadImageData CInt -> Ptr a -> IO (Ptr GDImage)
    forall a. CInt -> Ptr a -> IO (Ptr GDImage)
    GD.gdImageCreateFromPngPtr

    -- | Load a PNG image from a ByteString
    loadPngByteString :: L.ByteString -> IO Image
    loadPngByteString :: ByteString -> IO Image
    loadPngByteString = (Int -> Ptr (ZonkAny 4) -> IO Image) -> ByteString -> IO Image
    forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
    onByteStringData Int -> Ptr (ZonkAny 4) -> IO Image
    forall a. Int -> Ptr a -> IO Image
    loadPngData

    -- | Load a GIF image from a file.
    loadGifFile :: FilePath -> IO Image
    loadGifFile :: FilePath -> IO Image
    loadGifFile = (Ptr CFILE -> IO (Ptr GDImage)) -> FilePath -> IO Image
    loadImageFile Ptr CFILE -> IO (Ptr GDImage)
    GD.gdImageCreateFromGif

    -- | Load a GIF image from a buffer.
    loadGifData :: Int   -- ^ Buffer size.
                -> Ptr a -- ^ Buffer with image data.
                -> IO Image
    loadGifData :: forall a. Int -> Ptr a -> IO Image
    loadGifData = (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    forall a.
    (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    loadImageData CInt -> Ptr a -> IO (Ptr GDImage)
    forall a. CInt -> Ptr a -> IO (Ptr GDImage)
    GD.gdImageCreateFromGifPtr

    -- | Load a GIF image from a ByteString
    loadGifByteString :: L.ByteString -> IO Image
    loadGifByteString :: ByteString -> IO Image
    loadGifByteString = (Int -> Ptr (ZonkAny 3) -> IO Image) -> ByteString -> IO Image
    forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
    onByteStringData Int -> Ptr (ZonkAny 3) -> IO Image
    forall a. Int -> Ptr a -> IO Image
    loadGifData

    loadImageFile :: (Ptr CFILE -> IO (Ptr GDImage)) -> FilePath -> IO Image
    loadImageFile :: (Ptr CFILE -> IO (Ptr GDImage)) -> FilePath -> IO Image
    loadImageFile Ptr CFILE -> IO (Ptr GDImage)
    f FilePath
    file = do
      p <- FilePath -> IO (Ptr GDImage) -> IO (Ptr GDImage)
    forall a. FilePath -> IO (Ptr a) -> IO (Ptr a)
    F.throwIfNull (FilePath
    "Loading image from " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    file) (IO (Ptr GDImage) -> IO (Ptr GDImage))
    -> IO (Ptr GDImage) -> IO (Ptr GDImage)
    forall a b. (a -> b) -> a -> b
    $ FilePath
    -> FilePath -> (Ptr CFILE -> IO (Ptr GDImage)) -> IO (Ptr GDImage)
    forall a. FilePath -> FilePath -> (Ptr CFILE -> IO a) -> IO a
    GD.withCFILE FilePath
    file FilePath
    "rb" Ptr CFILE -> IO (Ptr GDImage)
    f
      GD.mkImage p

    loadImageData :: (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    loadImageData :: forall a.
    (CInt -> Ptr a -> IO (Ptr GDImage)) -> Int -> Ptr a -> IO Image
    loadImageData CInt -> Ptr a -> IO (Ptr GDImage)
    f Int
    sz Ptr a
    buf =
        do p <- FilePath -> IO (Ptr GDImage) -> IO (Ptr GDImage)
    forall a. FilePath -> IO (Ptr a) -> IO (Ptr a)
    F.throwIfNull (FilePath
    "Loading image") (IO (Ptr GDImage) -> IO (Ptr GDImage))
    -> IO (Ptr GDImage) -> IO (Ptr GDImage)
    forall a b. (a -> b) -> a -> b
    $ CInt -> Ptr a -> IO (Ptr GDImage)
    f (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    sz) Ptr a
    buf
           GD.mkImage p

    onByteStringData :: (Int -> Ptr a -> IO b) -> L.ByteString -> IO b
    onByteStringData :: forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
    onByteStringData Int -> Ptr a -> IO b
    f ByteString
    bstr =
      case ByteString -> (ForeignPtr Word8, Int, Int)
    BI.toForeignPtr (ByteString -> ByteString
    lazyToStrict ByteString
    bstr) of
        (ForeignPtr Word8
    fptr, Int
    start, Int
    sz) -> ForeignPtr Word8 -> (Ptr Word8 -> IO b) -> IO b
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    F.withForeignPtr ForeignPtr Word8
    fptr ((Ptr Word8 -> IO b) -> IO b) -> (Ptr Word8 -> IO b) -> IO b
    forall a b. (a -> b) -> a -> b
    $
                               \Ptr Word8
    ptr -> Int -> Ptr a -> IO b
    f Int
    sz (Ptr Word8 -> Int -> Ptr a
    forall a b. Ptr a -> Int -> Ptr b
    F.plusPtr Ptr Word8
    ptr Int
    start)
      where lazyToStrict :: L.ByteString -> B.ByteString
            lazyToStrict :: ByteString -> ByteString
    lazyToStrict = (ByteString -> ByteString -> ByteString)
    -> [ByteString] -> ByteString
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldr1 ByteString -> ByteString -> ByteString
    B.append ([ByteString] -> ByteString)
    -> (ByteString -> [ByteString]) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> [ByteString]
    L.toChunks

    --
    -- * Saving images
    --

    -- | Save an image as a JPEG file.
    saveJpegFile :: Int -- ^ quality: 0-95, or negative for default quality.
                 -> FilePath -> Image -> IO ()
    saveJpegFile :: Int -> FilePath -> Image -> IO ()
    saveJpegFile Int
    q = (Ptr GDImage -> Ptr CFILE -> IO ()) -> FilePath -> Image -> IO ()
    saveImageFile (\Ptr GDImage
    p Ptr CFILE
    h -> Ptr GDImage -> Ptr CFILE -> CInt -> IO ()
    GD.gdImageJpeg Ptr GDImage
    p Ptr CFILE
    h (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    q))

    -- | Write a JPEG format ByteString of an image.
    saveJpegByteString :: Int -> Image -> IO L.ByteString
    saveJpegByteString :: Int -> Image -> IO ByteString
    saveJpegByteString Int
    q =
      (Ptr GDImage -> Ptr CInt -> IO (Ptr (ZonkAny 2)))
    -> Image -> IO ByteString
    forall a.
    (Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
    saveImageByteString (\Ptr GDImage
    p Ptr CInt
    h -> Ptr GDImage -> Ptr CInt -> CInt -> IO (Ptr (ZonkAny 2))
    forall a. Ptr GDImage -> Ptr CInt -> CInt -> IO (Ptr a)
    GD.gdImageJpegPtr Ptr GDImage
    p Ptr CInt
    h (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    q))

    -- | Save an image as a PNG file.
    savePngFile :: FilePath -> Image -> IO ()
    savePngFile :: FilePath -> Image -> IO ()
    savePngFile = (Ptr GDImage -> Ptr CFILE -> IO ()) -> FilePath -> Image -> IO ()
    saveImageFile Ptr GDImage -> Ptr CFILE -> IO ()
    GD.gdImagePng

    -- | Write a PNG format ByteString of an image.
    savePngByteString :: Image -> IO L.ByteString
    savePngByteString :: Image -> IO ByteString
    savePngByteString = (Ptr GDImage -> Ptr CInt -> IO (Ptr (ZonkAny 1)))
    -> Image -> IO ByteString
    forall a.
    (Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
    saveImageByteString Ptr GDImage -> Ptr CInt -> IO (Ptr (ZonkAny 1))
    forall a. Ptr GDImage -> Ptr CInt -> IO (Ptr a)
    GD.gdImagePngPtr

    -- | Save an image as a GIF file.
    saveGifFile :: FilePath -> Image -> IO ()
    saveGifFile :: FilePath -> Image -> IO ()
    saveGifFile = (Ptr GDImage -> Ptr CFILE -> IO ()) -> FilePath -> Image -> IO ()
    saveImageFile Ptr GDImage -> Ptr CFILE -> IO ()
    GD.gdImageGif

    -- | Write a GIF format ByteString of an image.
    saveGifByteString :: Image -> IO L.ByteString
    saveGifByteString :: Image -> IO ByteString
    saveGifByteString = (Ptr GDImage -> Ptr CInt -> IO (Ptr (ZonkAny 0)))
    -> Image -> IO ByteString
    forall a.
    (Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
    saveImageByteString Ptr GDImage -> Ptr CInt -> IO (Ptr (ZonkAny 0))
    forall a. Ptr GDImage -> Ptr CInt -> IO (Ptr a)
    GD.gdImageGifPtr

    saveImageFile :: (Ptr GDImage -> Ptr CFILE -> IO ()) -> FilePath -> Image
                     -> IO ()
    saveImageFile :: (Ptr GDImage -> Ptr CFILE -> IO ()) -> FilePath -> Image -> IO ()
    saveImageFile Ptr GDImage -> Ptr CFILE -> IO ()
    f FilePath
    file Image
    i = Image -> (Ptr GDImage -> IO ()) -> IO ()
    forall a. Image -> (Ptr GDImage -> IO a) -> IO a
    GD.withImagePtr Image
    i (\Ptr GDImage
    p -> FilePath -> FilePath -> (Ptr CFILE -> IO ()) -> IO ()
    forall a. FilePath -> FilePath -> (Ptr CFILE -> IO a) -> IO a
    GD.withCFILE FilePath
    file FilePath
    "wb" (Ptr GDImage -> Ptr CFILE -> IO ()
    f Ptr GDImage
    p))

    saveImageByteString :: (Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image
                           -> IO (L.ByteString)
    saveImageByteString :: forall a.
    (Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
    saveImageByteString Ptr GDImage -> Ptr CInt -> IO (Ptr a)
    f Image
    img = Image -> (Ptr GDImage -> IO ByteString) -> IO ByteString
    forall a. Image -> (Ptr GDImage -> IO a) -> IO a
    GD.withImagePtr Image
    img (\Ptr GDImage
    p -> (Ptr CInt -> IO (Ptr a)) -> IO ByteString
    forall a. (Ptr CInt -> IO (Ptr a)) -> IO ByteString
    dataByteString (Ptr GDImage -> Ptr CInt -> IO (Ptr a)
    f Ptr GDImage
    p))

    dataByteString :: (Ptr CInt -> IO (Ptr a)) -> IO L.ByteString
    dataByteString :: forall a. (Ptr CInt -> IO (Ptr a)) -> IO ByteString
    dataByteString Ptr CInt -> IO (Ptr a)
    f = (Ptr CInt -> IO ByteString) -> IO ByteString
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    F.alloca ((Ptr CInt -> IO ByteString) -> IO ByteString)
    -> (Ptr CInt -> IO ByteString) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr CInt
    szPtr -> do
      datPtr <- Ptr CInt -> IO (Ptr a)
    f Ptr CInt
    szPtr IO (Ptr a)
    -> (Ptr a -> IO (ForeignPtr Word8)) -> IO (ForeignPtr Word8)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= FinalizerPtr Word8 -> Ptr Word8 -> IO (ForeignPtr Word8)
    forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
    F.newForeignPtr FinalizerPtr Word8
    forall a. FunPtr (Ptr a -> IO ())
    GD.gdFree (Ptr Word8 -> IO (ForeignPtr Word8))
    -> (Ptr a -> Ptr Word8) -> Ptr a -> IO (ForeignPtr Word8)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr a -> Ptr Word8
    forall a b. Ptr a -> Ptr b
    F.castPtr
      liftM (L.fromChunks . return . BI.fromForeignPtr datPtr 0 . fromIntegral)
            (peek szPtr)

    --
    -- * Text
    --

    -- | Draw a string using the FreeType 2.x library
    drawString :: B.ByteString -- ^ Font name
               -> Double       -- ^ Font point size
               -> Double       -- ^ Angle in counterclockwise radians
               -> Point        -- ^ Origin
               -> B.ByteString -- ^ Text, including HTML entities
               -> Color -> Image
               -> IO (Point, Point, Point, Point) -- ^ Bounding box
                                                  -- of the drawn
                                                  -- text
    drawString :: ByteString
    -> Double
    -> Double
    -> Point
    -> ByteString
    -> CInt
    -> Image
    -> IO (Point, Point, Point, Point)
    drawString ByteString
    fontName Double
    ptSize Double
    angle (Int
    oriX, Int
    oriY) ByteString
    txt CInt
    color Image
    img =
      Image
    -> (Ptr GDImage -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a. Image -> (Ptr GDImage -> IO a) -> IO a
    GD.withImagePtr Image
    img ((Ptr GDImage -> IO (Point, Point, Point, Point))
     -> IO (Point, Point, Point, Point))
    -> (Ptr GDImage -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a b. (a -> b) -> a -> b
    $ CInt
    -> ByteString
    -> Double
    -> Double
    -> Point
    -> ByteString
    -> Ptr GDImage
    -> IO (Point, Point, Point, Point)
    drawStringImagePtr CInt
    color ByteString
    fontName Double
    ptSize Double
    angle
                                               (Int
    oriX, Int
    oriY) ByteString
    txt

    -- | Measure a string using the FreeType 2.x library.  This computes
    -- the bounding box but does not actually draw the string to any
    -- image.
    measureString :: B.ByteString -- ^ Font name
                  -> Double       -- ^ Font point size
                  -> Double       -- ^ Angle in counterclockwise radians
                  -> Point        -- ^ Origin
                  -> B.ByteString -- ^ Text, including HTML entities
                  -> Color
                  -> IO (Point, Point, Point, Point) -- ^ Bounding
                                                     -- box of the
                                                     -- drawn text
    measureString :: ByteString
    -> Double
    -> Double
    -> Point
    -> ByteString
    -> CInt
    -> IO (Point, Point, Point, Point)
    measureString ByteString
    fontName Double
    ptSize Double
    angle (Int
    oriX, Int
    oriY) ByteString
    txt CInt
    color
        = CInt
    -> ByteString
    -> Double
    -> Double
    -> Point
    -> ByteString
    -> Ptr GDImage
    -> IO (Point, Point, Point, Point)
    drawStringImagePtr CInt
    color ByteString
    fontName Double
    ptSize Double
    angle (Int
    oriX, Int
    oriY) ByteString
    txt Ptr GDImage
    forall a. Ptr a
    F.nullPtr

    drawStringImagePtr :: Color -> B.ByteString -> Double -> Double -> Point
                          -> B.ByteString -> Ptr GDImage
                          -> IO (Point, Point, Point, Point)
    drawStringImagePtr :: CInt
    -> ByteString
    -> Double
    -> Double
    -> Point
    -> ByteString
    -> Ptr GDImage
    -> IO (Point, Point, Point, Point)
    drawStringImagePtr CInt
    color ByteString
    fontName Double
    ptSize Double
    angle (Int
    oriX, Int
    oriY) ByteString
    txt Ptr GDImage
    imgPtr
        = Int
    -> (Ptr CInt -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
    F.allocaArray Int
    8 ((Ptr CInt -> IO (Point, Point, Point, Point))
     -> IO (Point, Point, Point, Point))
    -> (Ptr CInt -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a b. (a -> b) -> a -> b
    $
          \Ptr CInt
    bboxPtr -> ByteString
    -> (CString -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    fontName ((CString -> IO (Point, Point, Point, Point))
     -> IO (Point, Point, Point, Point))
    -> (CString -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a b. (a -> b) -> a -> b
    $
          \CString
    cFontName -> ByteString
    -> (CString -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    txt ((CString -> IO (Point, Point, Point, Point))
     -> IO (Point, Point, Point, Point))
    -> (CString -> IO (Point, Point, Point, Point))
    -> IO (Point, Point, Point, Point)
    forall a b. (a -> b) -> a -> b
    $
          \CString
    cTxt -> do res <- Ptr GDImage
    -> Ptr CInt
    -> CInt
    -> CString
    -> CDouble
    -> CDouble
    -> CInt
    -> CInt
    -> CString
    -> IO CString
    GD.gdImageStringFT Ptr GDImage
    imgPtr Ptr CInt
    bboxPtr CInt
    color CString
    cFontName
                                                (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    ptSize) (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    angle)
                                                (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    GD.int Int
    oriX) (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    GD.int Int
    oriY) CString
    cTxt
                      if res == F.nullPtr
                         then F.peekArray 8 bboxPtr >>= parseBBox
                         else peekCAString res >>= ioError . userError
        where parseBBox :: [a] -> IO ((b, b), (b, b), (b, b), (b, b))
    parseBBox [a]
    l =
                case (a -> b) -> [a] -> [b]
    forall a b. (a -> b) -> [a] -> [b]
    map a -> b
    forall a b. (Integral a, Num b) => a -> b
    GD.int [a]
    l of
                  [b
    llx, b
    lly, b
    lrx, b
    lry, b
    urx, b
    ury, b
    ulx, b
    uly] ->
                    ((b, b), (b, b), (b, b), (b, b))
    -> IO ((b, b), (b, b), (b, b), (b, b))
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ((b
    llx, b
    lly), (b
    lrx, b
    lry), (b
    urx, b
    ury), (b
    ulx, b
    uly))
                  [b]
    _ -> IOError -> IO ((b, b), (b, b), (b, b), (b, b))
    forall a. IOError -> IO a
    ioError (IOError -> IO ((b, b), (b, b), (b, b), (b, b)))
    -> IOError -> IO ((b, b), (b, b), (b, b), (b, b))
    forall a b. (a -> b) -> a -> b
    $ FilePath -> IOError
    userError (FilePath -> IOError) -> FilePath -> IOError
    forall a b. (a -> b) -> a -> b
    $
                         FilePath
    "parseBBox with /= 8 elements: " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ [a] -> FilePath
    forall a. Show a => a -> FilePath
    show [a]
    l

    -- | Draw strings around the top and bottom of a torus
    drawStringCircle :: Point        -- ^ Center of text path circle
                     -> Double       -- ^ Outer radius of text
                     -> Double       -- ^ Fraction of radius occupied by text
                     -> Double       -- ^ Portion of circle arc filled by text
                     -> B.ByteString -- ^ Font name
                     -> Double       -- ^ Font size hint
                     -> B.ByteString -- ^ Text to write on the top of the circle
                     -> B.ByteString -- ^ Text to write on the bottom of the circle
                     -> Color        -- ^ Text color
                     -> Image -> IO ()
    drawStringCircle :: Point
    -> Double
    -> Double
    -> Double
    -> ByteString
    -> Double
    -> ByteString
    -> ByteString
    -> CInt
    -> Image
    -> IO ()
    drawStringCircle (Int
    ctrX, Int
    ctrY) Double
    rad Double
    textRad Double
    textFill ByteString
    fontName Double
    fontSize ByteString
    topTxt
                     ByteString
    bottomTxt CInt
    color Image
    img
        = ByteString -> (CString -> IO ()) -> IO ()
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    fontName ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          \CString
    cFontName -> ByteString -> (CString -> IO ()) -> IO ()
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    topTxt ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          \CString
    cTopTxt -> ByteString -> (CString -> IO ()) -> IO ()
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    bottomTxt ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          \CString
    cBottomTxt -> Image -> (Ptr GDImage -> IO ()) -> IO ()
    forall a. Image -> (Ptr GDImage -> IO a) -> IO a
    GD.withImagePtr Image
    img ((Ptr GDImage -> IO ()) -> IO ())
    -> (Ptr GDImage -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          \Ptr GDImage
    imgPtr -> do
            res <- Ptr GDImage
    -> CInt
    -> CInt
    -> CDouble
    -> CDouble
    -> CDouble
    -> CString
    -> CDouble
    -> CString
    -> CString
    -> CInt
    -> IO CString
    GD.gdImageStringFTCircle Ptr GDImage
    imgPtr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    GD.int Int
    ctrX) (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    GD.int Int
    ctrY)
                                            (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    rad) (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    textRad)
                                            (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    textFill) CString
    cFontName
                                            (Double -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    GD.double Double
    fontSize) CString
    cTopTxt
                                            CString
    cBottomTxt  CInt
    color
            unless (res == F.nullPtr) (peekCAString res >>= ioError . userError)