2017-08-29 63 views
1

我使用[email protected][email protected]。我想畫一個SVG圖像,但SDL2圖像不支持此格式(見https://www.libsdl.org/projects/SDL_image/):如何將SVG柵格化爲Haskell中的SDL.Surface?

SDL_image是圖像文件加載庫。
它加載圖像作爲SDL表面和紋理,並支持以下格式:BMP,GIF,JPEG,LBM,PCX,PNG,PNM,TGA,TIFF,WEBP,XCF,XPM,XV

如何我加載一個SVG,縮放/調整它的大小並將其光柵化爲SDL.SurfaceSDL.Texture

編輯:

在C++中,你可以使用nanosvg庫:

NSVGimage * svg_image = nsvgParseFromFile(filepath.c_str(), "px", 96.0); 
std::vector<Uint8> img_data; 
img_data.resize(width * height * 4); 

NSVGrasterizer * rasterizer = nsvgCreateRasterizer() 
nsvgRasterize(rasterizer, 
       svg_image, 0,0,1, 
       img_data.data(), 
       width, height, 
       width * 4); 

SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(
          static_cast<void *>(img_data.data()), 
          width, height, 
          32,   // depth 
          4 * width, // pitch 
          0x000000FF, // red mask 
          0x0000FF00, // green mask 
          0x00FF0000, // blue mask 
          0xFF000000 // alpha mask (alpha in this format) 
         ); 

您必須對您傳遞給SDL_CreateRGBSurfaceFrom圖像數據做了static_cast<void *>。 Haskell的SDL.createRGBSurfaceFrom(sdl2版本2.2.0)預計Data.Vector.Storable.Mutable.VectorIO Word8作爲圖像數據。

我找到了一個有希望的庫rasterific-svg

該軟件包可以使SVG圖像或將其轉換爲PDF。

您可以使用drawingOfSvgDocumentrenderSvgDocument進行渲染。但是,我不知道如何將結果轉換爲Data.Vector.Storable.Mutable.VectorIO Word8

編輯2:

我已經運行example現在。但是,渲染結果還不正確。

SVG

SVG image

呈現爲

rendering result

{-# LANGUAGE OverloadedStrings #-} 

module Main where 

import Codec.Picture 
import Codec.Picture.Types 
import Data.Vector.Storable.Mutable (IOVector) 
import Data.Vector.Generic (thaw) 
import Graphics.Rasterific.Svg 
     (loadCreateFontCache, renderSvgDocument) 
import Graphics.Svg (loadSvgFile) 

import Data.Function (fix) 
import Data.Word (Word8) 

import Control.Monad as CM 
import qualified Data.Vector.Generic.Mutable as GM 
import Data.Vector.Storable (Vector) 
import qualified Data.Vector.Storable as V 

import Foreign.C.Types (CInt) 
import qualified SDL 
import SDL.Vect (Point(P), V2(V2), V4(V4)) 

import Control.Concurrent (threadDelay) 
import SDL (($=)) 

import Paths_render_svg_in_sdl2_haskell (getDataFileName) 

screenWidth, screenHeight :: CInt 
(screenWidth, screenHeight) = (1280, 720) 

-- SDL dependency: sudo apt-get install libsdl2-dev 
main :: IO() 
main = do 
    SDL.initialize [SDL.InitVideo, SDL.InitTimer, SDL.InitEvents] 
    -- ensure render quality 
    SDL.HintRenderScaleQuality $= SDL.ScaleLinear 
    do renderQuality <- SDL.get SDL.HintRenderScaleQuality 
    CM.when (renderQuality /= SDL.ScaleLinear) $ 
     putStrLn "Warning: Linear texture filtering not enabled!" 
    window <- 
    SDL.createWindow 
     "Load and render SVG" 
     SDL.defaultWindow 
     { SDL.windowPosition = SDL.Centered 
     , SDL.windowInitialSize = V2 screenWidth screenHeight 
     } 
    SDL.showWindow window 
    renderer <- 
    SDL.createRenderer 
     window 
     (-1) 
     SDL.RendererConfig 
     { SDL.rendererType = SDL.AcceleratedVSyncRenderer 
     , SDL.rendererTargetTexture = True 
     } 
    SDL.rendererDrawColor renderer $= V4 maxBound maxBound maxBound maxBound 
    SDL.clear renderer 
    renderSvgExample renderer 
    SDL.present renderer 
    threadDelay 2000000 
    SDL.destroyRenderer renderer 
    SDL.destroyWindow window 
    SDL.quit 

renderSvgExample :: SDL.Renderer -> IO() 
renderSvgExample renderer = do 
    mimage <- getDataFileName "thumbs-up.svg" >>= loadSVGImage 
    case mimage of 
    Nothing -> putStrLn "Image convertion failed." 
    (Just image) -> do 
     let surfaceSize :: V2 CInt 
      surfaceSize = V2 screenWidth screenHeight 
     surface <- createSurfaceFromSVG image surfaceSize 
     texture <- SDL.createTextureFromSurface renderer surface 
     SDL.freeSurface surface 
     let source = SDL.Rectangle (P $ V2 0 0) surfaceSize 
      dest = SDL.Rectangle (P $ V2 0 0) surfaceSize 
      angle = 0.0 
      center = Nothing 
      flipNone = V2 False False 
     SDL.copyEx 
     renderer 
     texture 
     (Just source) 
     (Just dest) 
     angle 
     center 
     flipNone 
     SDL.destroyTexture texture 

createSurfaceFromSVG :: Image PixelRGBA8 -> V2 CInt -> IO SDL.Surface 
createSurfaceFromSVG image surfaceSize = do 
    let rawImageData :: Vector Word8 
     rawImageData = imageData image 
     imWidth :: Int 
     imWidth = imageWidth image 
     pitch :: CInt 
     pitch = fromIntegral imWidth 
    mutableVector <- convertToMutableVector rawImageData 
    SDL.createRGBSurfaceFrom mutableVector surfaceSize pitch SDL.RGBA8888 

convertToMutableVector :: Vector Word8 -> IO (IOVector Word8) 
convertToMutableVector= thaw 

loadSVGImage :: FilePath -> IO (Maybe (Image PixelRGBA8)) 
loadSVGImage filepath = do 
    mdoc <- loadSvgFile filepath 
    case mdoc of 
    Nothing -> return Nothing 
    Just doc -> do 
     cache <- loadCreateFontCache "fonty-texture-cache" 
     (finalImage, _) <- renderSvgDocument cache Nothing 96 doc 
     return $ Just finalImage 
+0

你有什麼試過? 「sdl2-image不支持這種格式」是什麼意思?如果你認爲應該可以使用這些庫,我猜你可以編寫相應的C程序 - 如果有的話,可以隨意包含該程序。 – user2407038

+0

我已經添加了一個使用nanosvg的C++解決方案,並引用了SDL2 Image支持的圖像格式。 – maiermic

+0

因爲這是一個圖書館推薦問題而關閉的原因,這是SO的主題。只需谷歌「Haskell SVG渲染器」,你應該找到一些選擇。 – Cubic

回答

1

我還沒有真正的代碼測試這一點,但希望這是在正確的軌道上:

renderSvgDocument爲您提供IO (Image PixelRGBA8),其中結果類型來自JuicyPixels圖像庫。

imageData讓你我的猜測是追逐所有類型後Vector Word8一(StorableVector (PixelBaseComponent PixelRGBA8)

thawunsafeThaw(請閱讀重要安全信息的文檔)爲您提供不可變的Vector的可變副本(或查看不安全變體)。

+0

我已經根據您的建議在我的問題中添加了一個運行示例。但是,它沒有呈現正確的結果。我想我必須以某種方式轉換像素數據。 – maiermic

+1

@maiermic我認爲你可能只需要將寬度設置爲寬度的4倍,就像在你的C++示例中一樣 – Claude

+0

你是對的。我忽略了這一點。我也忽略了使用'ABGR8888'而不是'RGBA8888' – maiermic