diff --git a/README.md b/README.md index 7b8e12f..4a1024e 100644 --- a/README.md +++ b/README.md @@ -103,4 +103,9 @@ var options = new ResvgOptions | `ExportId` | `string?` | `null` | Export specific element by ID | | `ExportAreaPage` | `bool` | `false` | Export page area | | `ExportAreaDrawing` | `bool` | `true` | Export drawing area | -| `ResourcesDir` | `string?` | `null` | Resources directory path | \ No newline at end of file +| `ResourcesDir` | `string?` | `null` | Resources directory path | +| `SerifFamily` | `string?` | `null` | Sets the 'serif' font family | +| `SansSerifFamily` | `string?` | `null` | Sets the 'sans-serif' font family | +| `CursiveFamily` | `string?` | `null` | Sets the 'cursive' font family | +| `FantasyFamily` | `string?` | `null` | Sets the 'fantasy' font family | +| `MonospaceFamily` | `string?` | `null` | Sets the 'monospace' font family | \ No newline at end of file diff --git a/SPEC.md b/SPEC.md index b24c2d6..cadfc6f 100644 --- a/SPEC.md +++ b/SPEC.md @@ -101,6 +101,31 @@ public class ResvgOptions /// Directory used for resolving relative paths in the SVG. /// public string? ResourcesDir { get; set; } + + /// + /// Sets the 'serif' font family. + /// + public string? SerifFamily { get; set; } + + /// + /// Sets the 'sans-serif' font family. + /// + public string? SansSerifFamily { get; set; } + + /// + /// Sets the 'cursive' font family. + /// + public string? CursiveFamily { get; set; } + + /// + /// Sets the 'fantasy' font family. + /// + public string? FantasyFamily { get; set; } + + /// + /// Sets the 'monospace' font family. + /// + public string? MonospaceFamily { get; set; } } ``` @@ -124,6 +149,11 @@ pub struct RenderOptions { pub font_count: usize, // number of fonts pub font_file: *const c_char, // null for unset pub font_dir: *const c_char, // null for unset + pub serif_family: *const c_char, // null for unset + pub sans_serif_family: *const c_char, // null for unset + pub cursive_family: *const c_char, // null for unset + pub fantasy_family: *const c_char, // null for unset + pub monospace_family: *const c_char, // null for unset } #[no_mangle] diff --git a/native/resvg-wrapper/src/lib.rs b/native/resvg-wrapper/src/lib.rs index a39dcf5..f564c5b 100644 --- a/native/resvg-wrapper/src/lib.rs +++ b/native/resvg-wrapper/src/lib.rs @@ -22,6 +22,11 @@ pub struct RenderOptions { pub font_count: usize, pub font_file: *const c_char, pub font_dir: *const c_char, + pub serif_family: *const c_char, + pub sans_serif_family: *const c_char, + pub cursive_family: *const c_char, + pub fantasy_family: *const c_char, + pub monospace_family: *const c_char, } unsafe fn c_str_to_string(ptr: *const c_char) -> Option { @@ -74,7 +79,27 @@ pub extern "C" fn render_svg_to_png_with_options( if let Some(font_dir) = c_str_to_string(opts.font_dir) { fontdb.load_fonts_dir(&font_dir); } - + + if let Some(serif_family) = c_str_to_string(opts.serif_family) { + fontdb.set_serif_family(&serif_family); + } + + if let Some(sans_serif_family) = c_str_to_string(opts.sans_serif_family) { + fontdb.set_sans_serif_family(&sans_serif_family); + } + + if let Some(cursive_family) = c_str_to_string(opts.cursive_family) { + fontdb.set_cursive_family(&cursive_family); + } + + if let Some(fantasy_family) = c_str_to_string(opts.fantasy_family) { + fontdb.set_fantasy_family(&fantasy_family); + } + + if let Some(monospace_family) = c_str_to_string(opts.monospace_family) { + fontdb.set_monospace_family(&monospace_family); + } + let mut usvg_opts = Options::default(); usvg_opts.fontdb = std::sync::Arc::new(fontdb); diff --git a/src/ResvgSharp/Resvg.cs b/src/ResvgSharp/Resvg.cs index dbc824b..c789c38 100644 --- a/src/ResvgSharp/Resvg.cs +++ b/src/ResvgSharp/Resvg.cs @@ -30,6 +30,11 @@ private struct RenderOptions public UIntPtr font_count; public IntPtr font_file; public IntPtr font_dir; + public IntPtr serif_family; + public IntPtr sans_serif_family; + public IntPtr cursive_family; + public IntPtr fantasy_family; + public IntPtr monospace_family; } [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] @@ -68,7 +73,12 @@ public static byte[] RenderToPng(string svg, ResvgOptions? options = null) font_lens = IntPtr.Zero, font_count = UIntPtr.Zero, font_file = IntPtr.Zero, - font_dir = IntPtr.Zero + font_dir = IntPtr.Zero, + serif_family = IntPtr.Zero, + sans_serif_family = IntPtr.Zero, + cursive_family = IntPtr.Zero, + fantasy_family = IntPtr.Zero, + monospace_family = IntPtr.Zero, }; IntPtr backgroundPtr = IntPtr.Zero; @@ -79,6 +89,11 @@ public static byte[] RenderToPng(string svg, ResvgOptions? options = null) IntPtr[] fontPtrs = Array.Empty(); IntPtr fontArrayPtr = IntPtr.Zero; IntPtr fontLensPtr = IntPtr.Zero; + IntPtr serifFamilyPtr = IntPtr.Zero; + IntPtr sansSerifFamilyPtr = IntPtr.Zero; + IntPtr cursiveFamilyPtr = IntPtr.Zero; + IntPtr fantasyFamilyPtr = IntPtr.Zero; + IntPtr monospaceFamilyPtr = IntPtr.Zero; try { @@ -122,6 +137,46 @@ public static byte[] RenderToPng(string svg, ResvgOptions? options = null) nativeOptions.font_dir = fontDirPtr; } + if (!string.IsNullOrEmpty(options.SerifFamily)) + { + var serifFamilyBytes = System.Text.Encoding.UTF8.GetBytes(options.SerifFamily + "\0"); + serifFamilyPtr = Marshal.AllocHGlobal(serifFamilyBytes.Length); + Marshal.Copy(serifFamilyBytes, 0, serifFamilyPtr, serifFamilyBytes.Length); + nativeOptions.serif_family = fontDirPtr; + } + + if (!string.IsNullOrEmpty(options.SansSerifFamily)) + { + var sansSerifFamilyBytes = System.Text.Encoding.UTF8.GetBytes(options.SansSerifFamily + "\0"); + sansSerifFamilyPtr = Marshal.AllocHGlobal(sansSerifFamilyBytes.Length); + Marshal.Copy(sansSerifFamilyBytes, 0, sansSerifFamilyPtr, sansSerifFamilyBytes.Length); + nativeOptions.sans_serif_family = sansSerifFamilyPtr; + } + + if (!string.IsNullOrEmpty(options.CursiveFamily)) + { + var cursiveFamilyBytes = System.Text.Encoding.UTF8.GetBytes(options.CursiveFamily + "\0"); + cursiveFamilyPtr = Marshal.AllocHGlobal(cursiveFamilyBytes.Length); + Marshal.Copy(cursiveFamilyBytes, 0, cursiveFamilyPtr, cursiveFamilyBytes.Length); + nativeOptions.cursive_family = cursiveFamilyPtr; + } + + if (!string.IsNullOrEmpty(options.FantasyFamily)) + { + var fantasyFamilyBytes = System.Text.Encoding.UTF8.GetBytes(options.FantasyFamily + "\0"); + fantasyFamilyPtr = Marshal.AllocHGlobal(fantasyFamilyBytes.Length); + Marshal.Copy(fantasyFamilyBytes, 0, fantasyFamilyPtr, fantasyFamilyBytes.Length); + nativeOptions.fantasy_family = fantasyFamilyPtr; + } + + if (!string.IsNullOrEmpty(options.MonospaceFamily)) + { + var monospaceFamilyBytes = System.Text.Encoding.UTF8.GetBytes(options.MonospaceFamily + "\0"); + monospaceFamilyPtr = Marshal.AllocHGlobal(monospaceFamilyBytes.Length); + Marshal.Copy(monospaceFamilyBytes, 0, monospaceFamilyPtr, monospaceFamilyBytes.Length); + nativeOptions.monospace_family = monospaceFamilyPtr; + } + if (options.UseFonts != null && options.UseFonts.Length > 0) { fontPtrs = new IntPtr[options.UseFonts.Length]; @@ -197,6 +252,11 @@ public static byte[] RenderToPng(string svg, ResvgOptions? options = null) if (resourcesDirPtr != IntPtr.Zero) Marshal.FreeHGlobal(resourcesDirPtr); if (fontFilePtr != IntPtr.Zero) Marshal.FreeHGlobal(fontFilePtr); if (fontDirPtr != IntPtr.Zero) Marshal.FreeHGlobal(fontDirPtr); + if (serifFamilyPtr != IntPtr.Zero) Marshal.FreeHGlobal(serifFamilyPtr); + if (sansSerifFamilyPtr != IntPtr.Zero) Marshal.FreeHGlobal(sansSerifFamilyPtr); + if (cursiveFamilyPtr != IntPtr.Zero) Marshal.FreeHGlobal(cursiveFamilyPtr); + if (fantasyFamilyPtr != IntPtr.Zero) Marshal.FreeHGlobal(fantasyFamilyPtr); + if (monospaceFamilyPtr != IntPtr.Zero) Marshal.FreeHGlobal(monospaceFamilyPtr); foreach (var ptr in fontPtrs) { diff --git a/src/ResvgSharp/ResvgOptions.cs b/src/ResvgSharp/ResvgOptions.cs index 2e8203c..22a5709 100644 --- a/src/ResvgSharp/ResvgOptions.cs +++ b/src/ResvgSharp/ResvgOptions.cs @@ -27,4 +27,14 @@ public class ResvgOptions public bool ExportAreaDrawing { get; set; } = true; public string? ResourcesDir { get; set; } + + public string? SerifFamily { get; set; } + + public string? SansSerifFamily { get; set; } + + public string? CursiveFamily { get; set; } + + public string? FantasyFamily { get; set; } + + public string? MonospaceFamily { get; set; } } \ No newline at end of file