Haskell Threepenny Gui:在特定点从 Canvas 读取颜色?
Haskell Threepenny Gui: Reading Color from Canvas at specific Point?
有没有办法读取 Canvas 的特定点的颜色?
类似于:
getColor :: Canvas -> Point -> Color
我查看了 Graphics.UI.Threepenny.Canvas 上的文档,但找不到任何相关功能。也许我只是没有看到它,因为我使用 Haskell.
的时间不长
如果您对我有任何提示,请告诉我。
非常感谢,
克莱姆
编辑:感谢 Heinrich Apfelmus 的回答,我能够编写一个可行的解决方案并希望分享它以防有人需要相同的功能。当然,如果您使用它并进行了调整,请随时分享它:)
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
import Codec.Picture.Types
-- to UI (PixelRGB8) is also possible just change from fst to snd after the return
getCanvCol :: UI.Canvas -> UI.Point -> UI (UI.Color)
getCanvCol canvas (x,y) = do
-- str returns a string with comma separated values i.e. "255,0,255"
str <- callFunction $ ffi ("(%1.getContext('2d').getImageData(%2,%3,1,1).data[0])+\
\",\"+(%1.getContext('2d').getImageData(%2,%3,1,1).data[1])+\
\",\"+(%1.getContext('2d').getImageData(%2,%3,1,1).data[2])")
canvas x y
return $ fst $ tripleToCol $ lsToRGB $ wordsWhen (==',') str
where
-- could also use splitOn
wordsWhen :: (Char -> Bool) -> String -> [String]
wordsWhen p s = case dropWhile p s of
"" -> []
s' -> w : wordsWhen p s''
where (w, s'') = break p s'
-- take a list of strings and make a triple of ints
lsToRGB :: [String] -> (Int,Int,Int)
lsToRGB (a:b:c:xs) = (read a, read b, read c)
lsToRGB _ = (0,0,0)
-- make a triple of Int to Color needed
tripleToCol :: (Int,Int,Int) -> (UI.Color, PixelRGB8)
tripleToCol (r,g,b) = ((UI.RGB r g b),(PixelRGB8 r' g' b'))
where (r',g',b') = (fromIntegral r,fromIntegral g,fromIntegral b)
(作者在此)
从 threepenny-gui-0.5.0.0 开始,目前没有可以执行此操作的预定义函数。但是,您可以使用包含的 JavaScript FFI 调用 JavaScript 函数,该函数 return 是您需要的值。例如,这里是 drawImage
函数的源代码:
drawImage :: Element -> Vector -> Canvas -> UI ()
drawImage image (x,y) canvas =
runFunction $ ffi "%1.getContext('2d').drawImage(%2,%3,%4)" canvas image x y
ffi
函数允许您调用任意 JavaScript 函数。唯一的麻烦是您必须将结果编组为 Color
类型;目前,仅支持 Int
或 String
等几种类型作为 return 值。查看示例的源代码。
有没有办法读取 Canvas 的特定点的颜色?
类似于:
getColor :: Canvas -> Point -> Color
我查看了 Graphics.UI.Threepenny.Canvas 上的文档,但找不到任何相关功能。也许我只是没有看到它,因为我使用 Haskell.
的时间不长如果您对我有任何提示,请告诉我。
非常感谢, 克莱姆
编辑:感谢 Heinrich Apfelmus 的回答,我能够编写一个可行的解决方案并希望分享它以防有人需要相同的功能。当然,如果您使用它并进行了调整,请随时分享它:)
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
import Codec.Picture.Types
-- to UI (PixelRGB8) is also possible just change from fst to snd after the return
getCanvCol :: UI.Canvas -> UI.Point -> UI (UI.Color)
getCanvCol canvas (x,y) = do
-- str returns a string with comma separated values i.e. "255,0,255"
str <- callFunction $ ffi ("(%1.getContext('2d').getImageData(%2,%3,1,1).data[0])+\
\",\"+(%1.getContext('2d').getImageData(%2,%3,1,1).data[1])+\
\",\"+(%1.getContext('2d').getImageData(%2,%3,1,1).data[2])")
canvas x y
return $ fst $ tripleToCol $ lsToRGB $ wordsWhen (==',') str
where
-- could also use splitOn
wordsWhen :: (Char -> Bool) -> String -> [String]
wordsWhen p s = case dropWhile p s of
"" -> []
s' -> w : wordsWhen p s''
where (w, s'') = break p s'
-- take a list of strings and make a triple of ints
lsToRGB :: [String] -> (Int,Int,Int)
lsToRGB (a:b:c:xs) = (read a, read b, read c)
lsToRGB _ = (0,0,0)
-- make a triple of Int to Color needed
tripleToCol :: (Int,Int,Int) -> (UI.Color, PixelRGB8)
tripleToCol (r,g,b) = ((UI.RGB r g b),(PixelRGB8 r' g' b'))
where (r',g',b') = (fromIntegral r,fromIntegral g,fromIntegral b)
(作者在此)
从 threepenny-gui-0.5.0.0 开始,目前没有可以执行此操作的预定义函数。但是,您可以使用包含的 JavaScript FFI 调用 JavaScript 函数,该函数 return 是您需要的值。例如,这里是 drawImage
函数的源代码:
drawImage :: Element -> Vector -> Canvas -> UI ()
drawImage image (x,y) canvas =
runFunction $ ffi "%1.getContext('2d').drawImage(%2,%3,%4)" canvas image x y
ffi
函数允许您调用任意 JavaScript 函数。唯一的麻烦是您必须将结果编组为 Color
类型;目前,仅支持 Int
或 String
等几种类型作为 return 值。查看示例的源代码。