如何在haskell应用程序中使用cairo渲染到gtk3 statusicon?

时间:2016-11-18 08:48:28

标签: haskell gtk3 cairo gtk2hs

我想渲染到我的应用程序的statusicon

我知道我可以通过设置statusIconPixbuf来使statusicon显示为pixbuf。

我可以通过pixbufNew创建一个空的pixbuf并执行填充单色的操作。

但是如何使用cairo渲染到pixbuf?

或者pixbuf不适合使用?有没有更好的方法呈现到statusicon?

1 个答案:

答案 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]