Haskell中的PNG到BMP(用于光泽)
Posted
技术标签:
【中文标题】Haskell中的PNG到BMP(用于光泽)【英文标题】:PNG to BMP in Haskell (for Gloss) 【发布时间】:2012-08-31 21:33:26 【问题描述】:我有 PNG 文件,the Gloss library 有一个用于 Picture
的 Bitmap
构造函数。由于文件类型,我不能使用loadBMP :: FilePath -> IO Picture
,所以我正在搜索如何加载PNG文件,将其转换为BMP,并将其提供给bitmapOfBMP :: BMP -> Picture
、bitmapOfForeignPtr :: Int -> Int -> ForeignPtr Word8 -> Bool -> Picture
或bitmapOfByteString :: Int -> Int -> ByteString -> Bool -> Picture
。
使用 JuicyPixels 进行测试
import Data.ByteString as B
import System.IO as A
import Codec.Picture.Png
import Graphics.Gloss.Interface.Pure.Game
main = do
png <- B.readFile "samus.png"
let img = decodePng png
case img of
Left x -> A.putStrLn x
Right x -> do
let bmp = encodeDynamicPng x
case bmp of
Left x -> A.putStrLn x
Right x -> do
let pic = bitmapOfByteString 29 52 x True
game pic
game pic
= play
(InWindow "Test" (700, 500) (10, 10))
white
30
pic
draw
(const id)
(const id)
draw bmp
= bmp
一切都成功了,但图像完全不一样。
【问题讨论】:
另外,作为文体观点,请注意\_ -> id
与const id
相同。
为了它的价值,我为此写了gloss-juicy。
太好了,看起来更完整了;我会试试你的包裹!对于大多数严肃的 Gloss 项目来说,这绝对是必须的。
【参考方案1】:
这就是我制作 JuicyPixel-repa 的原因。您将图像作为 Repa 数组读取,然后像我在 gloss-osm 中所做的那样将其转换为 Picture
:
repaToPicture :: Bool -> Array F.F DIM3 Word8 -> (Int, Int, Picture)
repaToPicture b arr =
let fptr = F.toForeignPtr arr
bs = BI.fromForeignPtr fptr 0 len
in (col, row, bitmapOfByteString row col bs b)
where
len = row * col * depth
(Z :. row :. col :. depth) = extent arr
或者,您可以直接使用 JuicyPixels,覆盖DynamicImage
类型,并从包含的Image
中获取底层imgData
。
【讨论】:
谢谢,我尝试了第二种解决方案。我没有使用imgData
,因为我不知道如何使用,而是转换为 BMP ByteString
,它不会显示我的图像,而是散布蓝色和粉红色像素。我将代码添加到问题中。
我设法使用了你的repaToPicture
。我把代码放在问题中。 Bool
参数是干什么用的?为什么它返回(Int, Int, Picture)
而不是Picture
?生成的Picture
是“错误的”,所以我做了:let (w, h, pic) = repaToPicture True repa; Bitmap _ _ bmp _ = pic in Bitmap w h bmp True
。现在,图像显示了,但它逆时针旋转了 180 度。
对不起,我一直很忙,但如果到那时你还需要的话,我会尽力在这个周末帮助你。布尔值确定图片是否会被您的 OpenGL 系统缓存。至于轮换,就用repa的backpermute吧。
感谢您的帮助!该教程非常有帮助:它对我的解释足以让我破解代码并让它工作并提供一个现成的功能。我在表示方面遇到了一些麻烦,但computeS
成功了。还有,我说的是图片旋转了180度,其实是垂直翻转的,所以我把y - j - 1
改成j
就可以了。【参考方案2】:
尽管我没有单独给出答案,但感谢 Thomas 的回答,我会将其发布在这里而不是问题中。
提醒一下,目标是将 BMP 文件转换为 Gloss 图片,因此我编写了一个名为 bmpToPic
的函数。我把它放在一个模块中,因为它使用了另外两个函数,并且需要很多导入。
此外,Thomas 的回答中的repaToPicture
在这里略有不同。
module PngToPic
(pngToPic)
where
import Data.ByteString as B
import Data.Word
import Codec.Picture.Png
import Codec.Picture.Repa
import qualified Data.ByteString.Internal as BI
import Data.Array.Repa ((:.)(..), Z, Z(..), extent, DIM3, Array)
import qualified Data.Array.Repa as R
import qualified Data.Array.Repa.Repr.ForeignPtr as F
import Graphics.Gloss.Data.Picture
pngToPic :: ByteString -> Picture
pngToPic png
= let
Right img -- unsafe
= decodePng png
repa
= imgData (convertImage img :: Img RGBA)
in repaToPicture True repa
repaToPicture :: Bool -> Array F.F DIM3 Word8 -> Picture
repaToPicture b arr
= bitmapOfByteString row col bs b
where
bs
= BI.fromForeignPtr fptr 0 (R.size sh)
fptr
= F.toForeignPtr arr'
sh@(Z :. col :. row :. depth)
= extent arr'
arr'
= flipVert arr
flipVert :: Array F.F DIM3 Word8 -> Array F.F DIM3 Word8
flipVert g
= R.computeS $ R.backpermute e flop g
where
e@(Z :. x :. y :. _)
= extent g
flop (Z :. i :. j :. k)
= Z :. x - i - 1 :. j :. k
你这样使用它:
import Data.ByteString as B
import Graphics.Gloss.Interface.Pure.Game
import PngToPic
main = do
png <- B.readFile "someImage.png"
game $ pngToPic png
game pic
= play
(InWindow "Test" (700, 500) (10, 10))
white
30
pic
id
(const id)
(const id)
并且图像将显示在窗口中间。
【讨论】:
感谢您的帮助和赞美。我想制作一个更通用的函数,例如 fileFormatToGlossPicture,因为它很简单并且涵盖了所有情况,并将其做成一个包。【参考方案3】:对于任何在 2017 年偶然发现此问题的人来说,这变得容易多了!我花了一段时间才弄清楚,因为上面的示例代码似乎不再起作用。这是我将 PNG 读入图片的函数:
import Codec.Picture.Repa (readImageRGBA, toByteString, reverseColorChannel)
import Graphics.Gloss
readPng :: FilePath -> Int -> Int -> IO Picture
readPng path w h = do
(Right img) <- readImageRGBA path
let bs = toByteString $ reverseColorChannel img
return $ bitmapOfByteString w h (BitmapFormat TopToBottom PxRGBA) bs True
【讨论】:
这是否适用于 Graphics.Gloss.Interface.Pure.Game 中的 Play?我在这里试过,但我得到“无法匹配预期的类型Picture' with actual type
Int -> Int -> IO Picture'”。也许我做错了什么......有没有办法将 IO 图片转换为图片?
@alitalvez 这是一个IO
类型,因为它需要从文件系统中读取。在haskell 中,您不能只在纯函数中将IO Picture
转换为Picture
,因为它与文件系统交互。因此,我为您看到的选项是在您初始化游戏之前 运行此代码(如thePicture <- readPng "/mypath.png"
),或者您可以切换到Graphics.Gloss.Interface.IO.Game
以在您的游戏中使用它。我会先从前者开始!以上是关于Haskell中的PNG到BMP(用于光泽)的主要内容,如果未能解决你的问题,请参考以下文章