2016-11-18 47 views

回答

0

使用Pixbuf我需要一种方法来渲染它。

以下解决方案需要开罗渲染render :: Render a 和(平方)的所需的X和Y尺寸Pixbuf(如果你需要创建非方形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创建一个表面供cairo渲染,然后调用renderWith来执行由render指定的实际渲染。

接下来的两行提取图像跨度,即一行中的字节数和实际图像数据作为ByteString。

swapRB是一个函数,它转换ByteString,因为不知何故红色和蓝色通道的顺序是错误的。请参阅下文了解如何完成此操作。

B.useAsCStringLen它得到的低级别:它TAKS由imageSurfaceGetData返回的字节字符串,并将其转换为Ptr CUChar使用pixbufNewFromData创建一个新的pixbuf。

就是这样。

swapRB定义如下:

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 

它分裂PixelData取出的字节串为行,然后拆分线到像素的每个包括4个字节:一个字节的每个所述信道的红色,绿色,蓝色, α。最内侧是实际交换:

swapRBforPixel [b,g,r,a] = [r,g,b,a]