#lang racket/gui
(require ffi/unsafe
ffi/unsafe/define
racket/draw
racket/draw/unsafe/cairo
(rename-in racket/contract
[-> c:->]))
(provide (contract-out
[load-svg-bitmap
(c:-> input-port? (is-a?/c bitmap%))]
[load-svg-from-file
(c:-> path-string? (is-a?/c bitmap%))]))
(define-ffi-definer define-rsvg (ffi-lib "librsvg-2" '("2" #f)))
(define-cpointer-type _RsvgHandle)
(define-cstruct _GError
([domain _int32] [code _int] [message _string/latin-1]))
(define-cstruct _RsvgDimensionData
([width _int] [height _int] [em _double] [ex _double]))
(define-rsvg rsvg_set_default_dpi (_fun _double -> _void))
(define-rsvg rsvg_set_default_dpi_x_y (_fun _double _double -> _void))
(define-rsvg rsvg_handle_set_dpi (_fun _RsvgHandle _double -> _void))
(define-rsvg rsvg_handle_set_dpi_x_y
(_fun _RsvgHandle _double _double -> _void))
(define-rsvg rsvg_handle_get_dimensions
(_fun _RsvgHandle
(dim : _RsvgDimensionData-pointer = (make-RsvgDimensionData 0 0 0.0 0.0))
-> _void
-> (values (RsvgDimensionData-width dim)
(RsvgDimensionData-height dim)
(RsvgDimensionData-em dim)
(RsvgDimensionData-ex dim))))
(define-rsvg rsvg_handle_new_from_data
(_fun (input : _bytes)
(input-length : _uint = (bytes-length input))
(error : _pointer = (make-GError 0 0 ""))
->
(handle : _RsvgHandle/null)
->
(values handle (ptr-ref error _GError-pointer/null))))
(define-rsvg rsvg_handle_render_cairo
(_fun _RsvgHandle _pointer -> _bool))
(define-rsvg rsvg_handle_free (_fun _RsvgHandle -> _void))
(define (load-svg-bitmap port)
(define input-bytes (port->bytes port))
(define-values (svg-handle error-obj)
(rsvg_handle_new_from_data input-bytes))
(unless svg-handle
(error (GError-message error-obj)))
(define-values (width height _1 _2)
(rsvg_handle_get_dimensions svg-handle))
(define bitmap (make-bitmap width height))
(define bitmap-handle (send bitmap get-handle))
(rsvg_handle_render_cairo svg-handle (cairo_create bitmap-handle))
(rsvg_handle_free svg-handle)
bitmap)
(define (load-svg-from-file file-path)
(with-input-from-file file-path
(λ () (load-svg-bitmap (current-input-port)))))