blank-canvas-0.6: Graphics/Blank/Utils.hs
{-# LANGUAGE OverloadedStrings #-}
module Graphics.Blank.Utils where
import Data.ByteString.Base64 -- Not sure why to use this, vs this *.URL version. This one works, though.
import qualified Data.ByteString as B
import Data.Monoid
import Data.Text(Text)
import qualified Data.Text as Text
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Graphics.Blank.Canvas
import Graphics.Blank.Generated
import Graphics.Blank.JavaScript
-- | Clear the screen. Restores the default transformation matrix.
clearCanvas :: Canvas ()
clearCanvas = do
setTransform (1, 0, 0, 1, 0, 0)
me <- myCanvasContext
clearRect (0,0,width me,height me)
-- | Wrap a canvas computation in 'save' / 'restore'.
saveRestore :: Canvas a -> Canvas a
saveRestore m = do
save ()
r <- m
restore ()
return r
infixr 0 #
-- | The @#@-operator is the Haskell analog to the @.@-operator
-- in JavaScript. Example:
--
-- > grd # addColorStop(0, "#8ED6FF");
--
-- This can be seen as equivalent of @grd.addColorStop(0, "#8ED6FF")@.
(#) :: a -> (a -> b) -> b
(#) obj act = act obj
-- | Read a file, and generate a data URL.
--
-- > url <- readDataURL "image/png" "image/foo.png"
--
readDataURL :: Text -> FilePath -> IO Text
readDataURL mime_type filePath = do
dat <- B.readFile filePath
return $ "data:" <> mime_type <> ";base64," <> decodeUtf8 (encode dat)
-- | Find the MIME type for a data URL.
--
-- > > dataURLMimeType "data:image/png;base64,iVBORw..."
-- > "image/png"
dataURLMimeType :: Text -> Text
dataURLMimeType txt
| dat /= "data" = error "dataURLMimeType: no 'data:'"
| not (Text.null rest0) && not (Text.null rest2) = mime_type
| otherwise = error "dataURLMimeType: bad parse"
where
(dat,rest0) = Text.span (/= ':') txt
Just (_,rest1) = Text.uncons rest0
(mime_type,rest2) = Text.span (/= ';') rest1
-- | Write a data URL to a given file.
writeDataURL :: FilePath -> Text -> IO ()
writeDataURL fileName
= B.writeFile fileName
. decodeLenient
. encodeUtf8
. Text.tail
. Text.dropWhile (/= ',')
-- | Draws an image onto the canvas at the given x- and y-coordinates.
drawImageAt :: Image image => (image, Double, Double) -> Canvas ()
drawImageAt (img, dx, dy) = Method $ DrawImage (img, [dx, dy])
-- | Acts like 'drawImageAt', but with two extra 'Double' arguments. The third and fourth
-- 'Double's specify the width and height of the image, respectively.
drawImageSize :: Image image => (image, Double, Double, Double, Double) -> Canvas ()
drawImageSize (img, dx, dy, dw, dh) = Method $ DrawImage (img, [dx, dy, dw, dh])
-- | Acts like 'drawImageSize', but with four extra 'Double' arguments before the arguments
-- of 'drawImageSize'. The first and second 'Double's specify the x- and y-coordinates at
-- which the image begins to crop. The third and fourth 'Double's specify the width and
-- height of the cropped image.
--
-- @
-- 'drawImageCrop' img 0 0 dw dh dx dy dw dh = 'drawImageSize' = dx dy dw dh
-- @
drawImageCrop :: Image image => (image, Double, Double, Double, Double, Double, Double, Double, Double) -> Canvas ()
drawImageCrop (img, sx, sy, sw, sh, dx, dy, dw, dh)
= Method $ DrawImage (img, [sx, sy, sw, sh, dx, dy, dw, dh])
-- | Writes 'ImageData' to the canvas at the given x- and y-coordinates.
putImageDataAt :: (ImageData, Double, Double) -> Canvas ()
putImageDataAt (imgData, dx, dy) = Method $ PutImageData (imgData, [dx, dy])
-- | Acts like 'putImageDataAt', but with four extra 'Double' arguments that specify
-- which region of the 'ImageData' (the dirty rectangle) should be drawn. The third
-- and fourth 'Double's specify the dirty rectangle's x- and y- coordinates, and the
-- fifth and sixth 'Double's specify the dirty rectangle's width and height.
--
-- @
-- 'putImageDataDirty' imgData dx dy 0 0 w h = 'putImageDataAt' imgData dx dy
-- where (w, h) = case imgData of ImageData w' h' _ -> (w', h')
-- @
putImageDataDirty :: (ImageData, Double, Double, Double, Double, Double, Double) -> Canvas ()
putImageDataDirty (imgData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
= Method $ PutImageData (imgData, [dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight])