Example #1
0
        private void canvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
        //Yet more boilerplate code, this runs before canvas_Draw and is meant to be used to load any assets that need to be loaded from files
        {
            Board       = LoadAsset(sender, "Chess Board"); //These are all basically identical; they set the value of each variable to whatever LoadAsset returns given the file name.
            PawnBlack   = LoadAsset(sender, "PawnBlack");
            PawnWhite   = LoadAsset(sender, "PawnWhite");
            KnightBlack = LoadAsset(sender, "KnightBlack");
            KnightWhite = LoadAsset(sender, "KnightWhite");
            BishopBlack = LoadAsset(sender, "BishopBlack");
            BishopWhite = LoadAsset(sender, "BishopWhite");
            RookBlack   = LoadAsset(sender, "RookBlack");
            RookWhite   = LoadAsset(sender, "RookWhite");
            QueenBlack  = LoadAsset(sender, "QueenBlack");
            QueenWhite  = LoadAsset(sender, "QueenWhite");
            KingBlack   = LoadAsset(sender, "KingBlack");
            KingWhite   = LoadAsset(sender, "KingWhite");

            PlaceholderBlack = CanvasSvgDocument.LoadFromXml(sender, PawnBlack.GetXml().Replace("opacity=\"1\"", "opacity=\"0.5\""));
            PlaceholderWhite = CanvasSvgDocument.LoadFromXml(sender, PawnWhite.GetXml().Replace("opacity=\"1\"", "opacity=\"0.5\""));

            translator = new RenderTranslator(PawnBlack, PawnWhite, KnightBlack, KnightWhite, BishopBlack, BishopWhite, RookBlack, RookWhite, QueenBlack, QueenWhite, KingBlack, KingWhite, PlaceholderBlack, PlaceholderWhite);
            pieceSize  = new Size(sender.Size.Width / 16, sender.Size.Height / 16);

            pawn            = new Pawn(new Position(3, 3), true);
            MoveHighlight   = new Color();
            MoveHighlight.A = 100;
            MoveHighlight.R = 255;
            MoveHighlight.G = 255;
            MoveHighlight.B = 255;
        }
Example #2
0
        public static CanvasSvgDocument GenerateSvgDocument(
            ICanvasResourceCreator device,
            Rect rect,
            IList <string> paths,
            IList <Color> colors,
            bool invertBounds = true)
        {
            var           right  = Math.Ceiling(rect.Width);
            var           bottom = Math.Ceiling(rect.Height);
            StringBuilder sb     = new StringBuilder();

            sb.AppendFormat(
                CultureInfo.InvariantCulture,
                "<svg width=\"100%\" height=\"100%\" viewBox=\"{2} {3} {0} {1}\" xmlns=\"http://www.w3.org/2000/svg\">",
                right,
                bottom,
                invertBounds ? -Math.Floor(rect.Left) : Math.Floor(rect.Left),
                invertBounds ? -Math.Floor(rect.Top) : Math.Floor(rect.Top));

            foreach (var path in paths)
            {
                string p = path;
                if (path.StartsWith("F1 "))
                {
                    p = path.Remove(0, 3);
                }

                if (string.IsNullOrWhiteSpace(p))
                {
                    continue;
                }

                sb.AppendFormat("<path d=\"{0}\" style=\"fill: {1}; fill-opacity: {2}\" />",
                                p,
                                AsHex(colors[paths.IndexOf(path)]),
                                (double)colors[paths.IndexOf(path)].A / 255d);
            }
            sb.Append("</svg>");

            CanvasSvgDocument doc = CanvasSvgDocument.LoadFromXml(device, sb.ToString());

            // TODO : When we export colour SVGs we'll need to set all the correct path fills here

            return(doc);
        }
Example #3
0
        public async Task <WriteableBitmap> ToWriteableBitmap()
        {
            WriteableBitmap result = null;

            if (IsValid)
            {
                if (Source is WriteableBitmap)
                {
                    result = Source as WriteableBitmap;
                }
                else if (Source is BitmapSource)
                {
                    var bmp = Source as BitmapImage;
                    result = await bmp.ToWriteableBitmap();
                }
                else if (Source is SvgImageSource)
                {
                    var svg = Source as SvgImageSource;

                    if (Bytes is byte[])
                    {
                        CanvasDevice device      = CanvasDevice.GetSharedDevice();
                        var          svgDocument = new CanvasSvgDocument(device);
                        svgDocument = CanvasSvgDocument.LoadFromXml(device, Encoding.UTF8.GetString(Bytes));

                        using (var offscreen = new CanvasRenderTarget(device, (float)svg.RasterizePixelWidth, (float)svg.RasterizePixelHeight, 96))
                        {
                            var session = offscreen.CreateDrawingSession();
                            session.DrawSvg(svgDocument, new Size(Size, Size), 0, 0);
                            using (var imras = new InMemoryRandomAccessStream())
                            {
                                await offscreen.SaveAsync(imras, CanvasBitmapFileFormat.Png);

                                result = await imras.ToWriteableBitmap();
                            }
                        }
                    }
                }
            }
            return(result);
        }
Example #4
0
        public static CanvasSvgDocument GenerateSvgDocument(
            ICanvasResourceCreator device,
            double width,
            double height,
            IList <SVGPathReciever> paths)
        {
            width  = Math.Ceiling(width);
            height = Math.Ceiling(height);
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("<svg width=\"100%\" height=\"100%\" viewBox=\"0 0 {0} {1}\" xmlns=\"http://www.w3.org/2000/svg\">", width, height);
            foreach (var receiver in paths)
            {
                sb.AppendFormat("<path d=\"{0}\" />", receiver.GetPathData());
            }
            sb.Append("</svg>");

            CanvasSvgDocument doc = CanvasSvgDocument.LoadFromXml(device, sb.ToString());

            // TODO : When we export colour SVGs we'll need to set all the correct path fills here

            return(doc);
        }
        public static async Task <ExportResult> ExportSvgAsync(
            ExportStyle style,
            InstalledFont selectedFont,
            FontVariant selectedVariant,
            Character selectedChar,
            CanvasTextLayoutAnalysis analysis,
            CanvasTypography typography)
        {
            try
            {
                string name = GetFileName(selectedFont, selectedVariant, selectedChar, "svg");
                if (await PickFileAsync(name, "SVG", new[] { ".svg" }) is StorageFile file)
                {
                    CachedFileManager.DeferUpdates(file);

                    CanvasDevice device    = Utils.CanvasDevice;
                    Color        textColor = style == ExportStyle.Black ? Colors.Black : Colors.White;


                    // If COLR format (e.g. Segoe UI Emoji), we have special export path.
                    if (style == ExportStyle.ColorGlyph && analysis.HasColorGlyphs && !analysis.GlyphFormats.Contains(GlyphImageFormat.Svg))
                    {
                        NativeInterop interop = Utils.GetInterop();
                        List <string> paths   = new List <string>();
                        Rect          bounds  = Rect.Empty;

                        foreach (var thing in analysis.Indicies)
                        {
                            var path = interop.GetPathDatas(selectedVariant.FontFace, thing.ToArray()).First();
                            paths.Add(path.Path);

                            if (!path.Bounds.IsEmpty)
                            {
                                var left   = Math.Min(bounds.Left, path.Bounds.Left);
                                var top    = Math.Min(bounds.Top, path.Bounds.Top);
                                var right  = Math.Max(bounds.Right, path.Bounds.Right);
                                var bottom = Math.Max(bounds.Bottom, path.Bounds.Bottom);
                                bounds = new Rect(
                                    left,
                                    top,
                                    right - left,
                                    bottom - top);
                            }
                        }

                        using (CanvasSvgDocument document = Utils.GenerateSvgDocument(device, bounds, paths, analysis.Colors, invertBounds: false))
                        {
                            await Utils.WriteSvgAsync(document, file);
                        }

                        return(new ExportResult(true, file));
                    }



                    var data = GetGeometry(1024, selectedVariant, selectedChar, analysis, typography);
                    async Task SaveMonochromeAsync()
                    {
                        using CanvasSvgDocument document = Utils.GenerateSvgDocument(device, data.Bounds, data.Path, textColor);
                        await Utils.WriteSvgAsync(document, file);
                    }

                    // If the font uses SVG glyphs, we can extract the raw SVG from the font file
                    if (analysis.GlyphFormats.Contains(GlyphImageFormat.Svg))
                    {
                        string  str = null;
                        IBuffer b   = GetGlyphBuffer(selectedVariant.FontFace, selectedChar.UnicodeIndex, GlyphImageFormat.Svg);
                        if (b.Length > 2 && b.GetByte(0) == 31 && b.GetByte(1) == 139)
                        {
                            using var stream = b.AsStream();
                            using var gzip   = new GZipStream(stream, CompressionMode.Decompress);
                            using var reader = new StreamReader(gzip);
                            str = reader.ReadToEnd();
                        }
                        else
                        {
                            using var dataReader       = DataReader.FromBuffer(b);
                            dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                            str = dataReader.ReadString(b.Length);
                        }

                        if (str.StartsWith("<?xml"))
                        {
                            str = str.Remove(0, str.IndexOf(">") + 1);
                        }

                        str = str.TrimStart();

                        try
                        {
                            using (CanvasSvgDocument document = CanvasSvgDocument.LoadFromXml(Utils.CanvasDevice, str))
                            {
                                // We need to transform the SVG to fit within the default document bounds, as characters
                                // are based *above* the base origin of (0,0) as (0,0) is the Baseline (bottom left) position for a character,
                                // so by default a will appear out of bounds of the default SVG viewport (towards top left).

                                //if (!document.Root.IsAttributeSpecified("viewBox")) // Specified viewbox requires baseline transform?
                                {
                                    // We'll regroup all the elements inside a "g" / group tag,
                                    // and apply a transform to the "g" tag to try and put in
                                    // in the correct place. There's probably a more accurate way
                                    // to do this by directly setting the root viewBox, if anyone
                                    // can find the correct calculation...

                                    List <ICanvasSvgElement> elements = new List <ICanvasSvgElement>();

                                    double minTop    = 0;
                                    double minLeft   = double.MaxValue;
                                    double maxWidth  = double.MinValue;
                                    double maxHeight = double.MinValue;

                                    void ProcessChildren(CanvasSvgNamedElement root)
                                    {
                                        CanvasSvgNamedElement ele = root.FirstChild as CanvasSvgNamedElement;

                                        while (true)
                                        {
                                            CanvasSvgNamedElement next = root.GetNextSibling(ele) as CanvasSvgNamedElement;
                                            if (ele.Tag == "g")
                                            {
                                                ProcessChildren(ele);
                                            }
                                            else if (ele.Tag == "path")
                                            {
                                                // Create a XAML geometry to try and find the bounds of each character
                                                // Probably more efficient to do in Win2D, but far less code to do with XAML.
                                                Geometry gm = XamlBindingHelper.ConvertValue(typeof(Geometry), ele.GetStringAttribute("d")) as Geometry;
                                                minTop    = Math.Min(minTop, gm.Bounds.Top);
                                                minLeft   = Math.Min(minLeft, gm.Bounds.Left);
                                                maxWidth  = Math.Max(maxWidth, gm.Bounds.Width);
                                                maxHeight = Math.Max(maxHeight, gm.Bounds.Height);
                                            }
                                            ele = next;
                                            if (ele == null)
                                            {
                                                break;
                                            }
                                        }
                                    }

                                    ProcessChildren(document.Root);

                                    double top  = minTop < 0 ? minTop : 0;
                                    double left = minLeft;
                                    document.Root.SetRectangleAttribute("viewBox", new Rect(left, top, data.Bounds.Width, data.Bounds.Height));
                                }

                                await Utils.WriteSvgAsync(document, file);
                            }
                        }
                        catch
                        {
                            // Certain fonts seem to have their SVG glyphs encoded with... I don't even know what encoding.
                            // for example: https://github.com/adobe-fonts/emojione-color
                            // In these cases, fallback to monochrome black
                            await SaveMonochromeAsync();
                        }
                    }
                    else
                    {
                        await SaveMonochromeAsync();
                    }

                    await CachedFileManager.CompleteUpdatesAsync(file);

                    return(new ExportResult(true, file));
                }
            }
            catch (Exception ex)
            {
                await SimpleIoc.Default.GetInstance <IDialogService>()
                .ShowMessageBox(ex.Message, Localization.Get("SaveImageError"));
            }

            return(new ExportResult(false, null));
        }
Example #6
0
        public static CanvasSvgDocument LoadAsset(CanvasControl sender, string fileName) //I wrote this one to clean up the previously very messy code in canvas_CreatResources; it deals with the file handling so I don't need to worry about that for each individual asset
        {
            var file = File.ReadAllText($"Assets/{fileName}.svg");                       //File.ReadAllText simply reads the whole file as a string, the $ strings work exactly like python f-strings, and Assets/ is the path where the assets are kept

            return(CanvasSvgDocument.LoadFromXml(sender, file));                         //CanvasSvgDocument.LoadFromXml takes in a string which is a valid Svg file and loads it into whatever form Win2D needs
        }