#c_sharp #wpf #svg
Иногда требуется отображать в textBlock картинку, с .png всё отлично, а тут попалось .svg и они игнорируются, собственно MSDN это подтвердил. Как всё таки отобразить SVG по url ? Желательно объяснить действия шаг за шагом. Image image = new Image(); image.Height = 50; image.Source = new BitmapImage(new Uri(src)); textBlock.Inlines.Add(image);
Ответы
Ответ 1
Можно просто преобразовать SVG в растровое изображение и отобразить его. Это можно сделать с помощью сторонних библиотек, или, при наличии Internet Explorer 11, стандартными средствами. Добавим ссылки на System.Drawing и COM -> Microsoft HTML Object Library. Создадим вспомогательный класс для преобразования SVG в BMP: using System; using System.Collections.Generic; using System.Drawing; using System.Text; using System.Runtime.InteropServices; using System.ComponentModel; //Reference: System.Drawing //Reference: Microsoft HTML Object Library namespace WpfApplication1 { public class SvgConvert { //преобразует SVG, заданный строкой svgcontent, в Bitmap заданных размеров и записывает его в поток output public static void ToBitmap(string svgcontent, int w_image,int h_image,System.IO.Stream output) { RECTL rcClient = new RECTL(); bool b = SystemParametersInfo(SPI_GETWORKAREA, 0, ref rcClient, 0); if (b == false) { rcClient.bottom = 480; rcClient.right = 640; } int width = (int)(rcClient.right - rcClient.left); int height = (int)(rcClient.bottom - rcClient.top); IntPtr screendc = GetDC(IntPtr.Zero); string svghtml = "" + svgcontent + ""; mshtml.HTMLDocument doc = null; mshtml.IHTMLDocument2 d2 = null; IOleObject pObj = null; IViewObject pView = null; try { doc = new mshtml.HTMLDocument(); //создание документа d2 = (mshtml.IHTMLDocument2)doc; int hr; //установка размера документа pObj = (IOleObject)d2; SIZEL sz = new SIZEL(); sz.x = (uint)MulDiv(width, HIMETRIC_INCH, GetDeviceCaps(screendc, LOGPIXELSX)); sz.y = (uint)MulDiv(height, HIMETRIC_INCH, GetDeviceCaps(screendc, LOGPIXELSY)); hr = pObj.SetExtent((int)System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT, ref sz); if (hr != 0) throw Marshal.GetExceptionForHR(hr); //запись SVG в документ d2.write(svghtml); d2.close(); //преобразование в Bitmap pView = (IViewObject)d2; Bitmap bmp = new Bitmap(w_image, h_image); Graphics g = Graphics.FromImage(bmp); using (g) { IntPtr hdc = g.GetHdc(); hr = pView.Draw((int)System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, hdc, ref rcClient, IntPtr.Zero, IntPtr.Zero, 0); if (hr != 0) throw Marshal.GetExceptionForHR(hr); g.ReleaseHdc(hdc); } //сохранение bmp.Save(output, System.Drawing.Imaging.ImageFormat.Bmp); } finally { //освобождение ресурсов if (d2 != null) Marshal.ReleaseComObject(d2); if (pObj != null) Marshal.ReleaseComObject(pObj); if (pView != null) Marshal.ReleaseComObject(pView); if (doc != null) Marshal.ReleaseComObject(doc); } } [DllImport("gdi32.dll")] static extern int GetDeviceCaps(IntPtr hdc, int nIndex); [DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll")] static extern bool SystemParametersInfo(int nAction, int nParam, ref RECTL rc, int nUpdate); public static int MulDiv(int number, int numerator, int denominator) { return (int)(((long)number * numerator) / denominator); } const int LOGPIXELSX = 88; const int LOGPIXELSY = 90; const int HIMETRIC_INCH = 2540; const int SPI_GETWORKAREA = 48; } [ComImport()] [GuidAttribute("0000010d-0000-0000-C000-000000000046")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface IViewObject { int Draw([MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, ref RECTL lprcBounds, IntPtr lprcWBounds, IntPtr pfnContinue, int dwContinue); int a(); int b(); int c(); int d(); int e(); } [ComImport()] [Guid("00000112-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IOleObject { void f(); void g(); void SetHostNames(object szContainerApp, object szContainerObj); void Close(uint dwSaveOption); void SetMoniker(uint dwWhichMoniker, object pmk); void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk); void x(); void y(); void DoVerb(uint iVerb, uint lpmsg, object pActiveSite, uint lindex, uint hwndParent, uint lprcPosRect); void EnumVerbs(ref object ppEnumOleVerb); void Update(); void IsUpToDate(); void GetUserClassID(uint pClsid); void GetUserType(uint dwFormOfType, uint pszUserType); int SetExtent(uint dwDrawAspect, ref SIZEL psizel); void GetExtent(uint dwDrawAspect, uint psizel); void Advise(object pAdvSink, uint pdwConnection); void Unadvise(uint dwConnection); void EnumAdvise(ref object ppenumAdvise); void GetMiscStatus(uint dwAspect, uint pdwStatus); void SetColorScheme(object pLogpal); }; public struct RECTL { public uint left; public uint top; public uint right; public uint bottom; } public struct SIZEL { public uint x; public uint y; } } Тогда отобразить по URL можно так: string svgcontent=""; if (uri.IsFile) { svgcontent = File.ReadAllText(uri.LocalPath); } else { var client = new System.Net.WebClient(); using (client) { svgcontent = client.DownloadString(uri); } } MemoryStream ms = new MemoryStream(); SvgConvert.ToBitmap(svgcontent, 500,500, ms); BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.CacheOption = BitmapCacheOption.OnLoad; bi.StreamSource = ms; bi.EndInit(); Image image = new Image(); image.Source = bi; textblock.Inlines.Add(image);Ответ 2
В WPF есть класс Path - он использует мини-язык описания геометрии, фактически он очень похож на svg. Наследуется от класса Geometry, так что может быть использован везде, где может быть использован класс Geometry (например, как содержимое кнопки). Чтобы его использовать надо открыть svg в текстовом редакторе, найти там тэг path а в нем атрибут d скопировать все содержимое в поле Path.Data. Возьмем флажок - https://iconmonstr.com/flag-thin-svg/ Открываем в Sublime: Условно говоря в ресурсах контрола объявляем ресурс:M16 7.553l6 7.447h-19v9h-1v-23h20l-6 6.553zm-13-5.553v12h16.91l-5.228-6.489 5.046-5.511h-16.728z в самом контроле: Со сложными иконками с несколькими цветами, возможно, придется повозиться вкладывая Geometry в GeometryGroup.
Комментариев нет:
Отправить комментарий