Pixbuf
を使用すると、レンダリングする方法が必要です。
次のソリューションは、render :: Render a
レンダリングカイロ(四角)Pixbuf
の所望のXとYの寸法を取る(あなたは非正方形Pixbufsを作成する必要がある場合は、これを変更することができます。)
import qualified Foreign.Ptr as Pointer
import qualified ByteString as B
renderPixbuf :: Int -> Render a -> IO Pixbuf
renderPixbuf size render = withImageSurface FormatARGB32 size size $ \surface -> do
renderWith surface render
stride <- imageSurfaceGetStride surface
surfaceData <- swapRB stride <$> imageSurfaceGetData surface
B.useAsCStringLen surfaceData $ \(pointer, _) -> do
let pointer' = Pointer.castPtr pointer
pixbufNewFromData pointer' ColorspaceRgb True 8 size size stride
それは、 withImageSurfaceを使用してレンダリングするカイロのサーフェスを作成し、renderWithを呼び出してrender
で指定された実際のレンダリングを行います。
次の2行は、イメージストライド、つまり行のバイト数と実際のイメージデータをByteStringとして抽出します。
swapRB
は、赤と青のチャンネルの順序が間違っているため、ByteStringを変換する関数です。これがどのように行われているかは以下を参照してください。
B.useAsCStringLenでは、低レベルの取得:それは延ByteString taks imageSurfaceGetDataによって返されたとpixbufNewFromDataを使用して新しいPIXBUFを作成するために、Ptr CUChar
に変換します。
これだけです。次のように
swapRB
が定義される:赤、緑、青のチャンネルのために1バイト毎:
import Data.Word (Word8)
import Data.List (unfoldr)
splitAtIfNotNull :: Int -> B.ByteString -> Maybe (B.ByteString,B.ByteString)
splitAtIfNotNull i string
| B.null string = Nothing
| otherwise = Just $ B.splitAt i string
mapChunks :: (B.ByteString -> B.ByteString) -> Int -> B.ByteString -> B.ByteString
mapChunks mapper chunkSize = B.concat . map mapper . unfoldr (splitAtIfNotNull chunkSize)
swapRB :: Int -> B.ByteString -> B.ByteString
swapRB = mapChunks swapRBforLine
where swapRBforLine :: B.ByteString -> B.ByteString
swapRBforLine = mapChunks (B.pack . swapRBforPixel . B.unpack) 4
swapRBforPixel :: [Word8] -> [Word8]
swapRBforPixel [b,g,r,a] = [r,g,b,a]
swapRBforPixel other = other
次に、各4バイトで構成される画素に行を分割し、行に画素データの延ByteStringを分割しますアルファ。最も内側のものは実際のスワッピングです。
swapRBforPixel [b,g,r,a] = [r,g,b,a]