예제 #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;
        }
예제 #2
0
        public static Task WriteSvgAsync(CanvasSvgDocument document, IStorageFile file)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("<!-- Exported by Character Map UWP -->");
            sb.Append(document.GetXml());
            return(FileIO.WriteTextAsync(file, sb.ToString()).AsTask());
        }
예제 #3
0
 public static Task WriteSvgAsync(CanvasSvgDocument document, IStorageFile file)
 {
     return(WriteSvgAsync(document.GetXml(), file));
 }
예제 #4
0
        public static string GetSVG(
            ExportStyle style,
            CharacterRenderingOptions options,
            Character selectedChar)
        {
            // We want to prepare geometry at 1024px, so force this
            options = options with {
                FontSize = 1024
            };
            using var typography = options.CreateCanvasTypography();

            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 && options.Analysis.HasColorGlyphs && !options.Analysis.GlyphFormats.Contains(GlyphImageFormat.Svg))
            {
                NativeInterop interop = Utils.GetInterop();
                List <string> paths   = new List <string>();
                Rect          bounds  = Rect.Empty;

                // Try to find the bounding box of all glyph layers combined
                foreach (var thing in options.Analysis.Indicies)
                {
                    var path = interop.GetPathDatas(options.Variant.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, options.Analysis.Colors, invertBounds: false);
                return(document.GetXml());
            }

            var data = GetGeometry(selectedChar, options);

            string GetMonochrome()
            {
                using CanvasSvgDocument document = string.IsNullOrWhiteSpace(data.Path)
                    ? new CanvasSvgDocument(Utils.CanvasDevice)
                    : Utils.GenerateSvgDocument(device, data.Bounds, data.Path, textColor);
                return(document.GetXml());
            }

            // If the font uses SVG glyphs, we can extract the raw SVG from the font file
            if (options.Analysis.GlyphFormats.Contains(GlyphImageFormat.Svg))
            {
                string  str = null;
                IBuffer b   = GetGlyphBuffer(options.Variant.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));
                        }

                        return(document.GetXml());
                    }
                }
                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
                    return(GetMonochrome());
                }
            }
            else
            {
                return(GetMonochrome());
            }
        }