Использование Pixbuf
Мне нужен способ визуализации в него.
следующее решение принимает каирский Rendering 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 для создания поверхности для каира, которую нужно визуализировать, а затем вызывает renderWith для выполнения фактического рендеринга, указанного в render
.
Следующие две строки извлекают шаг изображения, то есть количество байтов в строке и фактические данные изображения как ByteString.
swapRB
- это функция, которая преобразует байтовую строку, потому что как-то красный и синий каналы находятся в неправильном порядке. Ниже описано, как это делается.
В B.useAsCStringLen он получает низкий уровень: It TAKS в байтовой строке, возвращаемой imageSurfaceGetData и преобразует его в Ptr CUChar
создать новую Pixbuf с помощью pixbufNewFromData.
Все.
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-х байтов: один байт для каждого из каналов красного, зеленого, синего, альфа. Innermost является фактическим обменом:
swapRBforPixel [b,g,r,a] = [r,g,b,a]