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 함수를 사용하여 렌더링 할 카이로 서페이스를 만들고 renderWith을 호출하여 render
에 지정된 실제 렌더링을 수행합니다.
다음 두 라인은 이미지 스트라이드, 즉 라인의 바이트 수와 실제 이미지 데이터를 ByteString으로 추출합니다.
swapRB
은 어떻게 든 빨강 및 파랑 채널의 순서가 잘못되어 ByteString을 변환하는 함수입니다. 이것이 어떻게 행해지는지 아래를보십시오. 그것은 낮은 수준을 얻는다 B.useAsCStringLen에서
: imageSurfaceGetData에 의해 반환 된 ByteString TAKS 그것과 Ptr CUChar
로 변환이 pixbufNewFromData을 사용하여 새 Pixbuf을 만들 수 있습니다.
그게 전부입니다. 그것은 라인으로 pixeldata의 ByteString 분할
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 바이트로 이루어진 분할 : 다음
swapRB
정의되어 하나의 바이트 청색, 적색, 녹색 채널 용 각각, 알파. 가장 바깥 쪽은 실제 스와핑입니다.
swapRBforPixel [b,g,r,a] = [r,g,b,a]