module Graphics.GD.ByteString (
                    -- * 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.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 :: B.ByteString -> IO Image
loadJpegByteString :: ByteString -> IO Image
loadJpegByteString = (Int -> Ptr Any -> IO Image) -> ByteString -> IO Image
forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
onByteStringData Int -> Ptr Any -> 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 :: B.ByteString -> IO Image
loadPngByteString :: ByteString -> IO Image
loadPngByteString = (Int -> Ptr Any -> IO Image) -> ByteString -> IO Image
forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
onByteStringData Int -> Ptr Any -> 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 :: B.ByteString -> IO Image
loadGifByteString :: ByteString -> IO Image
loadGifByteString = (Int -> Ptr Any -> IO Image) -> ByteString -> IO Image
forall a b. (Int -> Ptr a -> IO b) -> ByteString -> IO b
onByteStringData Int -> Ptr Any -> 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
  Ptr GDImage
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
  Ptr GDImage -> IO Image
GD.mkImage Ptr GDImage
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 Ptr GDImage
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
       Ptr GDImage -> IO Image
GD.mkImage Ptr GDImage
p

onByteStringData :: (Int -> Ptr a -> IO b) -> B.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
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)

--
-- * 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 B.ByteString
saveJpegByteString :: Int -> Image -> IO ByteString
saveJpegByteString Int
q =
  (Ptr GDImage -> Ptr CInt -> IO (Ptr Any)) -> 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 Any)
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 B.ByteString
savePngByteString :: Image -> IO ByteString
savePngByteString = (Ptr GDImage -> Ptr CInt -> IO (Ptr Any)) -> Image -> IO ByteString
forall a.
(Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
saveImageByteString Ptr GDImage -> Ptr CInt -> IO (Ptr Any)
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 B.ByteString
saveGifByteString :: Image -> IO ByteString
saveGifByteString = (Ptr GDImage -> Ptr CInt -> IO (Ptr Any)) -> Image -> IO ByteString
forall a.
(Ptr GDImage -> Ptr CInt -> IO (Ptr a)) -> Image -> IO ByteString
saveImageByteString Ptr GDImage -> Ptr CInt -> IO (Ptr Any)
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 (B.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 B.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
  ForeignPtr Word8
datPtr <- Ptr CInt -> IO (Ptr a)
f Ptr CInt
szPtr IO (Ptr a)
-> (Ptr a -> IO (ForeignPtr Word8)) -> IO (ForeignPtr Word8)
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
  (CInt -> ByteString) -> IO CInt -> IO ByteString
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (ForeignPtr Word8 -> Int -> Int -> ByteString
BI.fromForeignPtr ForeignPtr Word8
datPtr Int
0 (Int -> ByteString) -> (CInt -> Int) -> CInt -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral) (Ptr CInt -> IO CInt
forall a. Storable a => Ptr a -> IO a
peek Ptr CInt
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 CString
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 CString
res CString -> CString -> Bool
forall a. Eq a => a -> a -> Bool
== CString
forall a. Ptr a
F.nullPtr
                     then Int -> Ptr CInt -> IO [CInt]
forall a. Storable a => Int -> Ptr a -> IO [a]
F.peekArray Int
8 Ptr CInt
bboxPtr IO [CInt]
-> ([CInt] -> IO (Point, Point, Point, Point))
-> IO (Point, Point, Point, Point)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [CInt] -> IO (Point, Point, Point, Point)
forall {a} {b}.
(Integral a, Show a, Num b) =>
[a] -> IO ((b, b), (b, b), (b, b), (b, b))
parseBBox
                     else CString -> IO FilePath
peekCAString CString
res IO FilePath
-> (FilePath -> IO (Point, Point, Point, Point))
-> IO (Point, Point, Point, Point)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IOError -> IO (Point, Point, Point, Point)
forall a. IOError -> IO a
ioError (IOError -> IO (Point, Point, Point, Point))
-> (FilePath -> IOError)
-> FilePath
-> IO (Point, Point, Point, Point)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> 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 (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
        CString
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                    
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (CString
res CString -> CString -> Bool
forall a. Eq a => a -> a -> Bool
== CString
forall a. Ptr a
F.nullPtr) (CString -> IO FilePath
peekCAString CString
res IO FilePath -> (FilePath -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IOError -> IO ()
forall a. IOError -> IO a
ioError (IOError -> IO ()) -> (FilePath -> IOError) -> FilePath -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IOError
userError)