I'm using sdl2@2.2.0 and sdl2-image@2.0.0. I'd like to draw a SVG image, but sdl2-image doesn't support this format (see https://www.libsdl.org/projects/SDL_image/):
SDL_image is an image file loading library.
It loads images as SDL surfaces and textures, and supports the following formats: BMP, GIF, JPEG, LBM, PCX, PNG, PNM, TGA, TIFF, WEBP, XCF, XPM, XV
How can I load a SVG, scale/resize it and rasterize it to a SDL.Surface
or SDL.Texture
?
Edit:
In C++ you can use nanosvg library:
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)
);
You have to do a static_cast<void *>
on the image data you pass to SDL_CreateRGBSurfaceFrom
. Haskell's SDL.createRGBSurfaceFrom
(sdl2 version 2.2.0) expects Data.Vector.Storable.Mutable.VectorIO Word8
as image data.
I found a promising library rasterific-svg
This package can render SVG to an image or transform it to a PDF.
You can render using drawingOfSvgDocument
or renderSvgDocument
. However, I don't know how to convert either of the results to Data.Vector.Storable.Mutable.VectorIO Word8
.
Edit 2:
I've a running example now. However, the rendering result is not correct yet.
This SVG
is rendered as
{-# 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
I haven't tested this with real code, but hopefully it's on the right track:
renderSvgDocument
gets you an IO (Image PixelRGBA8)
where the result type is from the JuicyPixels image library.
imageData
gets you a (Storable
) Vector (PixelBaseComponent PixelRGBA8)
which I guess is a Vector Word8
after chasing all the types.
thaw
or unsafeThaw
(read the docs for important safety information) get you a mutable copy (or view, for the unsafe variant) of an immutable Vector
.
User contributions licensed under CC BY-SA 3.0