我想渲染到我的应用程序的statusicon。
我知道我可以通过设置statusIconPixbuf来使statusicon显示为pixbuf。
我可以通过pixbufNew创建一个空的pixbuf并执行填充单色的操作。
但是如何使用cairo渲染到pixbuf?
或者pixbuf不适合使用?有没有更好的方法呈现到statusicon?
答案 0 :(得分:0)
使用Pixbuf
我需要一种渲染方式。
以下解决方案需要一个cairo渲染render :: Render a
和(正方形)Pixbuf
所需的X和Y维度(如果需要创建非方形Pixbuf,可以改变它。)
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中,它变为低级别:它获取imageSurfaceGetData返回的ByteString并将其转换为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的ByteString拆分成行,然后将这些行拆分为每个由4个字节组成的像素:红色,绿色,蓝色,alpha通道各占一个字节。最内层是实际的交换:
swapRBforPixel [b,g,r,a] = [r,g,b,a]