}  // ReadAsync_AbstractStream

        #endregion ReadAsync implementations


        #region WriteAsync implementations

        internal static IAsyncOperationWithProgress <uint, uint> WriteAsync_AbstractStream(Stream stream, IBuffer buffer)
        {
            Debug.Assert(stream != null);
            Debug.Assert(stream.CanWrite);
            Debug.Assert(buffer != null);

            // Choose the optimal writing strategy for the kind of buffer supplied:
            Func <CancellationToken, IProgress <uint>, Task <uint> > writeOperation;

            byte[] data;
            int    offset;

            // If buffer is backed by a managed array:
            if (buffer.TryGetUnderlyingData(out data, out offset))
            {
                writeOperation = async(cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                    {
                        return(0);
                    }

                    Debug.Assert(buffer.Length <= int.MaxValue);

                    int bytesToWrite = (int)buffer.Length;

                    await stream.WriteAsync(data, offset, bytesToWrite, cancelToken).ConfigureAwait(continueOnCapturedContext: false);

                    if (progressListener != null)
                    {
                        progressListener.Report((uint)bytesToWrite);
                    }

                    return((uint)bytesToWrite);
                };
                // Otherwise buffer is of an unknown implementation:
            }
            else
            {
                writeOperation = async(cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                    {
                        return(0);
                    }

                    uint   bytesToWrite = buffer.Length;
                    Stream dataStream   = buffer.AsStream();

                    int buffSize = 0x4000;
                    if (bytesToWrite < buffSize)
                    {
                        buffSize = (int)bytesToWrite;
                    }

                    await dataStream.CopyToAsync(stream, buffSize, cancelToken).ConfigureAwait(continueOnCapturedContext: false);

                    if (progressListener != null)
                    {
                        progressListener.Report((uint)bytesToWrite);
                    }

                    return((uint)bytesToWrite);
                };
            }  // if-else

            // Construct and run the async operation:
            return(AsyncInfo.Run <UInt32, UInt32>(writeOperation));
        }  // WriteAsync_AbstractStream
Пример #2
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());
            }
        }
Пример #3
0
        /// <summary>
        /// Clicking on the save button saves the photo in MainPage.ImageStream
        /// to media library camera roll. Once image has been saved, the
        /// application will navigate back to the main page.
        /// </summary>
        private async void SaveButton_Click(object sender, EventArgs e)
        {
            _progressIndicator.Text      = AppResources.SavingText;
            _progressIndicator.IsVisible = true;
            SystemTray.SetProgressIndicator(this, _progressIndicator);
            int selectedIndex = FilterPreviewPivot.SelectedIndex;

            DataContext dataContext = FilterEffects.DataContext.Instance;

            GC.Collect();

            try
            {
                if (selectedIndex == 0)
                {
                    using (MediaLibrary library = new MediaLibrary())
                    {
                        dataContext.FullResolutionStream.Position = 0;
                        library.SavePictureToCameraRoll(FileNamePrefix
                                                        + DateTime.Now.ToString() + ".jpg",
                                                        dataContext.FullResolutionStream);
                    }
                }
                else
                {
                    AbstractFilter filter = _filters[selectedIndex];

                    IBuffer buffer = await filter.RenderJpegAsync(
                        dataContext.FullResolutionStream.GetWindowsRuntimeBuffer());

                    using (MediaLibrary library = new MediaLibrary())
                    {
                        library.SavePictureToCameraRoll(FileNamePrefix
                                                        + DateTime.Now.ToString() + ".jpg", buffer.AsStream());
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to save the image: " + ex.ToString());
            }

            _progressIndicator.IsVisible = false;
            SystemTray.SetProgressIndicator(this, _progressIndicator);

            NavigationService.GoBack();
        }
        /// <summary>
        /// API for getting installation status.
        /// </summary>
        /// <returns>The status</returns>
#pragma warning disable 1998
        public async Task <ApplicationInstallStatus> GetInstallStatusAsync()
        {
            ApplicationInstallStatus status = ApplicationInstallStatus.None;

            Uri uri = Utilities.BuildEndpoint(
                this.deviceConnection.Connection,
                InstallStateApi);

            HttpBaseProtocolFilter httpFilter = new HttpBaseProtocolFilter();

            httpFilter.AllowUI = false;

            if (this.deviceConnection.Credentials != null)
            {
                httpFilter.ServerCredential          = new PasswordCredential();
                httpFilter.ServerCredential.UserName = this.deviceConnection.Credentials.UserName;
                httpFilter.ServerCredential.Password = this.deviceConnection.Credentials.Password;
            }

            using (HttpClient client = new HttpClient(httpFilter))
            {
                this.ApplyHttpHeaders(client, HttpMethods.Get);

                IAsyncOperationWithProgress <HttpResponseMessage, HttpProgress> responseOperation = client.GetAsync(uri);
                while (responseOperation.Status != AsyncStatus.Completed)
                {
                }

                using (HttpResponseMessage response = responseOperation.GetResults())
                {
                    if (response.IsSuccessStatusCode)
                    {
                        if (response.StatusCode == HttpStatusCode.Ok)
                        {
                            // Status code: 200
                            if (response.Content != null)
                            {
                                Stream dataStream = null;

                                IBuffer dataBuffer = null;
                                using (IHttpContent messageContent = response.Content)
                                {
                                    IAsyncOperationWithProgress <IBuffer, ulong> bufferOperation = messageContent.ReadAsBufferAsync();
                                    while (bufferOperation.Status != AsyncStatus.Completed)
                                    {
                                    }

                                    dataBuffer = bufferOperation.GetResults();

                                    if (dataBuffer != null)
                                    {
                                        dataStream = dataBuffer.AsStream();
                                    }
                                }

                                if (dataStream != null)
                                {
                                    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse));

                                    HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream);

                                    if (errorResponse.Success)
                                    {
                                        status = ApplicationInstallStatus.Completed;
                                    }
                                    else
                                    {
                                        throw new DevicePortalException(response.StatusCode, errorResponse, uri);
                                    }
                                }
                                else
                                {
                                    throw new DevicePortalException(HttpStatusCode.Conflict, "Failed to deserialize GetInstallStatus response.");
                                }
                            }
                        }
                        else if (response.StatusCode == HttpStatusCode.NoContent)
                        {
                            // Status code: 204
                            status = ApplicationInstallStatus.InProgress;
                        }
                    }
                    else
                    {
                        throw new DevicePortalException(response);
                    }
                }
            }

            return(status);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DevicePortalException"/> class.
        /// </summary>
        /// <param name="responseMessage">Http response message.</param>
        /// <param name="message">Optional exception message.</param>
        /// <param name="innerException">Optional inner exception.</param>
        /// <returns>async task</returns>
        public static async Task <DevicePortalException> CreateAsync(
            HttpResponseMessage responseMessage,
            string message           = "",
            Exception innerException = null)
        {
            DevicePortalException error = new DevicePortalException(
                responseMessage.StatusCode,
                responseMessage.ReasonPhrase,
                responseMessage.RequestMessage != null ? responseMessage.RequestMessage.RequestUri : null,
                message,
                innerException);

            try
            {
                if (responseMessage.Content != null)
                {
                    Stream dataStream = null;
#if !WINDOWS_UWP
                    using (HttpContent content = responseMessage.Content)
                    {
                        dataStream = new MemoryStream();

                        await content.CopyToAsync(dataStream).ConfigureAwait(false);

                        // Ensure we point the stream at the origin.
                        dataStream.Position = 0;
                    }
#else // WINDOWS_UWP
                    IBuffer dataBuffer = null;
                    using (IHttpContent messageContent = responseMessage.Content)
                    {
                        dataBuffer = await messageContent.ReadAsBufferAsync();

                        if (dataBuffer != null)
                        {
                            dataStream = dataBuffer.AsStream();
                        }
                    }
#endif  // WINDOWS_UWP

                    if (dataStream != null)
                    {
                        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse));

                        HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream);

                        error.HResult = errorResponse.ErrorCode;
                        error.Reason  = errorResponse.ErrorMessage;

                        // If we didn't get the Hresult and reason from these properties, try the other ones.
                        if (error.HResult == 0)
                        {
                            error.HResult = errorResponse.Code;
                        }

                        if (string.IsNullOrEmpty(error.Reason))
                        {
                            error.Reason = errorResponse.Reason;
                        }

                        dataStream.Dispose();
                    }
                }
            }
            catch (Exception)
            {
                // Do nothing if we fail to get additional error details from the response body.
            }

            return(error);
        }
Пример #6
0
        private async void we_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)//web控件的载入事件,点击内容都会触发这个事件
        {
            zhuangtai2 = true;
            if (zhuangtai == true)
            {
                if (args.Uri != null)
                {
                    if (args.Uri.AbsoluteUri.Contains("img1.") == true)//判断打开的是不是图片
                    {
                        args.Cancel   = true;
                        返回.Visibility = Visibility.Visible;
                        位.Visibility  = Visibility.Visible;
                        保存.Visibility = Visibility.Visible;

                        TPG.Visibility = Visibility.Visible;
                        刷新.Visibility  = Visibility.Collapsed;
                        一页.Visibility  = Visibility.Collapsed;
                        一页.Visibility  = Visibility.Collapsed;
                        评论.Visibility  = Visibility.Collapsed;
                        DM0.Begin();
                        try
                        {
                            if (lsuri != args.Uri.AbsoluteUri)
                            {
                                TPS.Source = null;
                                inStream   = null;
                                HttpClient webClient = new HttpClient();
                                inStream = await webClient.GetBufferAsync(new Uri(args.Uri.AbsoluteUri.Substring(args.Uri.AbsoluteUri.LastIndexOf("http"))));
                            }
                            else
                            {
                                lsuri = args.Uri.AbsoluteUri;
                            }

                            if (inStream.Length < 900000)//判断图片的大小
                            {
                                CT.ScaleX     = CT.ScaleY = 1;
                                CT.TranslateX = CT.TranslateY = 0;
                                zb            = 0;
                                zb2           = 0;
                                zb3           = 1;
                                BitmapImage img = new BitmapImage();
                                await img.SetSourceAsync(inStream.AsStream().AsRandomAccessStream());

                                img.ImageOpened  += new RoutedEventHandler(bi_ImageOpened);
                                img.ImageFailed  += new ExceptionRoutedEventHandler(bi_ImageFailed);
                                img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                                TPS.Source        = img;
                                img           = null;
                                PB.Visibility = Visibility.Collapsed;
                            }
                            else
                            {
                                TPT.Text       = "抱歉!由于WindowsPhone内存限制,不能在一般应用里预览 超高清的大图,但你仍然可以保存到图库,去图库->保存的图片里查看!";
                                TPT.Visibility = Visibility.Visible;
                                PB.Visibility  = Visibility.Collapsed;
                            }
                        }
                        catch (Exception e)
                        {
                            PB.Visibility  = Visibility.Collapsed;
                            TPT.Visibility = Visibility.Visible;
                            TPT.Text       = "图片载入错误:" + e.Message + " 请与作者联系!";
                        }
                        istpdk = true;
                    }
                    else if (args.Uri.AbsoluteUri.Contains("acg.gamersky") == true)//判断打开的是超链接
                    {
                        args.Cancel = true;
                        if (args.Uri.AbsoluteUri.Contains("pic/mm") || args.Uri.AbsoluteUri.Contains("pic/xz") || args.Uri.AbsoluteUri.Contains("pic/cosplay"))
                        {
                            Frame.Navigate(typeof(TPPage));
                            Frame.BackStack.RemoveAt(Frame.BackStackDepth - 1);
                        }
                        else if (args.Uri.AbsoluteUri.Contains("donghua"))
                        {
                            args.Cancel = true;
                            WB(args.Uri.AbsoluteUri);
                        }
                        else
                        {
                            Frame.Navigate(typeof(NewsPage), @"http://wap.gamersky.com/news/Content-" + args.Uri.AbsoluteUri.Substring(args.Uri.AbsoluteUri.LastIndexOf(@"/") + 1, args.Uri.AbsoluteUri.LastIndexOf(@".") - 1 - args.Uri.AbsoluteUri.LastIndexOf(@"/")) + ".html");
                        }
                    }
                    else//其他
                    {
                        args.Cancel = true;
                        WB(args.Uri.AbsoluteUri);
                    }
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DevicePortalException"/> class.
        /// </summary>
        /// <param name="responseMessage">Http response message.</param>
        /// <param name="message">Optional exception message.</param>
        /// <param name="innerException">Optional inner exception.</param>
        public DevicePortalException(
            HttpResponseMessage responseMessage,
            string message           = "",
            Exception innerException = null) : this(
                responseMessage.StatusCode,
                responseMessage.ReasonPhrase,
                responseMessage.RequestMessage != null ? responseMessage.RequestMessage.RequestUri : null,
                message,
                innerException)
        {
            try
            {
                if (responseMessage.Content != null)
                {
                    Stream dataStream = null;
#if !WINDOWS_UWP
                    using (HttpContent content = responseMessage.Content)
                    {
                        dataStream = new MemoryStream();

                        Task copyTask = content.CopyToAsync(dataStream);
                        copyTask.ConfigureAwait(false);
                        copyTask.Wait();

                        // Ensure we point the stream at the origin.
                        dataStream.Position = 0;
                    }
#else // WINDOWS_UWP
                    IBuffer dataBuffer = null;
                    using (IHttpContent messageContent = responseMessage.Content)
                    {
                        IAsyncOperationWithProgress <IBuffer, ulong> bufferOperation = messageContent.ReadAsBufferAsync();
                        while (bufferOperation.Status != AsyncStatus.Completed)
                        {
                        }

                        dataBuffer = bufferOperation.GetResults();

                        if (dataBuffer != null)
                        {
                            dataStream = dataBuffer.AsStream();
                        }
                    }
#endif  // WINDOWS_UWP

                    if (dataStream != null)
                    {
                        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse));

                        HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream);

                        this.HResult = errorResponse.ErrorCode;
                        this.Reason  = errorResponse.ErrorMessage;

                        // If we didn't get the Hresult and reason from these properties, try the other ones.
                        if (this.HResult == 0)
                        {
                            this.HResult = errorResponse.Code;
                        }

                        if (string.IsNullOrEmpty(this.Reason))
                        {
                            this.Reason = errorResponse.Reason;
                        }
                    }
                }
            }
            catch (Exception)
            {
                // Do nothing if we fail to get additional error details from the response body.
            }
        }
Пример #8
0
        /// <summary>
        /// Asynchronously attempts to unlock the document file.
        /// </summary>
        /// <remarks>
        /// Algorithm is as of this writing (11/5/2012):
        /// 0. Use UTF8 encoding with no BOM.
        /// 1. Read header.
        /// 2. Compute SHA256 hash of header.
        /// 3. Decrypt the rest of the viewModel using header parameters.
        ///     Relies on:
        ///         a. MasterSeed.Length == 32
        ///             Write masterseed to stream
        ///         b. GenerateKey32(_transformSeed, KeyEncryptionRounds)
        ///             Create raw32 (CreateRawCompositeKey32)
        ///                 Concatenate all data and Sha256
        ///             TransformKey(raw32, _transformSeed, numRounds)
        ///                 Init Rijndael:
        ///                     128 bit (16 byte) blocks
        ///                     ECB mode
        ///                     k = _transformSeed
        ///                     For numRounds:
        ///                         Transform in place raw32[0:15]
        ///                         Transform in place raw32[16:31]
        ///         c. Write 32 bytes of Key32 to stream
        ///         d. aesKey = Sha256 the stream
        ///         e. DecryptStream with aesKey and _encryptionIV
        /// 4. Verify the first 32 bytes of the decrypted viewModel match up with
        ///     "StreamStartBytes" from the header.
        /// 5. Read from the decrypted viewModel as a "HashedBlockStream"
        ///
        /// File format at the time of this writing (11/5/2012):
        ///
        /// 4 bytes: SIG1
        /// 4 bytes: SIG2
        /// Failure to match these constants results in a parse Result.
        ///
        /// 4 bytes: File version
        ///
        /// Header fields:
        /// 1 byte: Field ID
        /// 2 bytes: Field size (n)
        /// n bytes: Data
        /// </remarks>
        /// <param name="stream">An IRandomAccessStream containing the document to unlock (including the header).</param>
        /// <param name="rawKey">The aggregate raw key to use for decrypting the database.</param>
        /// <param name="token">A token allowing the parse to be cancelled.</param>
        /// <returns>A Task representing the result of the descryiption operation.</returns>
        public async Task <KdbxDecryptionResult> DecryptFile(IRandomAccessStream stream, IBuffer rawKey, CancellationToken token)
        {
            if (HeaderData == null)
            {
                throw new InvalidOperationException("Cannot decrypt database before ReadHeader has been called.");
            }

            // Init a SHA256 hash buffer and append the master seed to it
            HashAlgorithmProvider sha256 = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256);
            CryptographicHash     hash   = sha256.CreateHash();

            hash.Append(HeaderData.MasterSeed);

            this.rawKey = rawKey;
            this.logger.LogEvent("KdbxReader.GotRawKey", EventVerbosity.Verbose);

            // Transform the key (this can take a while)
            IBuffer transformedKey;

            try
            {
                IKdfEngine kdf = HeaderData.KdfParameters.CreateEngine();

                LoggingFields fields = new LoggingFields();
                fields.AddString("KdfEngine", kdf.GetType().Name);
                this.logger.LogEvent("KdbxReader.StartingKeyTransform", fields, EventVerbosity.Info);

                transformedKey = await HeaderData.KdfParameters.CreateEngine().TransformKeyAsync(rawKey, token)
                                 .ConfigureAwait(false);

                if (transformedKey == null)
                {
                    throw new OperationCanceledException();
                }

                this.logger.LogEvent("KdbxReader.KeyTransformSucceeded", EventVerbosity.Info);
            }
            catch (OperationCanceledException)
            {
                return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.OperationCancelled)));
            }

            // In KDBX4, after the header is an HMAC-SHA-256 value computed over the header
            // allowing validation of header integrity.
            IBuffer          hmacKey     = HmacBlockHandler.DeriveHmacKey(transformedKey, HeaderData.MasterSeed);
            HmacBlockHandler hmacHandler = new HmacBlockHandler(hmacKey);

            IBuffer expectedMac = null;

            if (this.parameters.UseInlineHeaderAuthentication)
            {
                var algorithm = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
                CryptographicHash hmacHash = algorithm.CreateHash(hmacHandler.GetKeyForBlock(UInt64.MaxValue));

                DebugHelper.Assert(HeaderData.FullHeader != null);
                hmacHash.Append(HeaderData.FullHeader);

                expectedMac = hmacHash.GetValueAndReset();
            }

            // Hash transformed k (with the master seed) to get final cipher k
            hash.Append(transformedKey);
            IBuffer cipherKey = hash.GetValueAndReset();

            this.logger.LogEvent("KdbxReader.GotFinalCipherKey", EventVerbosity.Info);

            // Decrypt the document starting from the end of the header
            ulong headerLength = HeaderData.FullHeader.Length;

            if (this.parameters.UseInlineHeaderAuthentication)
            {
                // KDBX4 has a hash at the end of the header
                headerLength += 32;
            }

            stream.Seek(headerLength);
            if (expectedMac != null)
            {
                using (DataReader macReader = GetReaderForStream(stream))
                {
                    await macReader.LoadAsync(expectedMac.Length);

                    IBuffer actualMac = macReader.ReadBuffer(expectedMac.Length);

                    for (uint i = 0; i < expectedMac.Length; i++)
                    {
                        if (expectedMac.GetByte(i) != actualMac.GetByte(i))
                        {
                            this.logger.LogEvent("KdbxReader.HmacFailure", EventVerbosity.Critical);
                            return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.CouldNotDecrypt)));
                        }
                    }

                    macReader.DetachStream();
                }
            }

            IBuffer cipherText;

            try
            {
                cipherText = await GetCipherText(stream, hmacHandler);
            }
            catch (FormatException ex)
            {
                this.logger.LogEvent("KdbxReader.DataIntegrityFailure", ex.ToLoggingFields(), EventVerbosity.Critical);
                return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.DataIntegrityProblem, ex)));
            }

            IBuffer decryptedFile = DecryptDatabaseData(cipherText, cipherKey);

            if (decryptedFile == null)
            {
                this.logger.LogEvent("KdbxReader.DecryptionFailure", EventVerbosity.Critical);
                return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.CouldNotDecrypt)));
            }

            this.logger.LogEvent("KdbxReader.DecryptionSucceeded", EventVerbosity.Info);

            // Verify first 32 bytes of the clear data; if StreamStartBytes wasn't set
            // (e.g. due to KDBX4), nothing happens here.
            for (uint i = 0; i < (HeaderData.StreamStartBytes?.Length ?? 0); i++)
            {
                byte actualByte   = decryptedFile.GetByte(i);
                byte expectedByte = HeaderData.StreamStartBytes.GetByte(i);

                if (actualByte != expectedByte)
                {
                    this.logger.LogEvent("KdbxReader.PlaintextValidationFailure", EventVerbosity.Critical);
                    return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.FirstBytesMismatch)));
                }
            }

            this.logger.LogEvent("KdbxReader.PlaintextValidationSucceeded", EventVerbosity.Verbose);

            IBuffer plainText = await UnhashAndInflate(decryptedFile);

            if (plainText == null)
            {
                return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.CouldNotInflate)));
            }

            // Update HeaderData with info from the inner header, if relevant
            if (this.parameters.UseInnerHeader)
            {
                using (IRandomAccessStream plainTextStream = plainText.AsStream().AsRandomAccessStream())
                {
                    using (DataReader reader = GetReaderForStream(plainTextStream))
                    {
                        ReaderResult innerHeaderResult = await ReadInnerHeader(reader, HeaderData);

                        if (innerHeaderResult != ReaderResult.Success)
                        {
                            LoggingFields fields = new LoggingFields();
                            fields.AddInt32("Code", (int)innerHeaderResult.Code);
                            this.logger.LogEvent("KdbxReader.InnerHeaderReadFailure", fields, EventVerbosity.Critical);
                            return(new KdbxDecryptionResult(innerHeaderResult));
                        }

                        // Update plainText to point to the remainder of the buffer
                        uint bytesRemaining = plainText.Length - (uint)plainTextStream.Position;
                        await reader.LoadAsync(bytesRemaining);

                        plainText = reader.ReadBuffer(bytesRemaining);
                    }
                }
            }

            XDocument finalTree = null;

            try
            {
                finalTree = XDocument.Load(plainText.AsStream());
            }
            catch (XmlException)
            {
                return(null);
            }

            if (finalTree == null)
            {
                return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.MalformedXml)));
            }

            try
            {
                KdbxDocument parsedDocument = await Task.Run(() => new KdbxDocument(finalTree.Root, HeaderData.ProtectedBinaries, HeaderData.GenerateRng(), this.parameters));

                // Validate the final parsed header hash before returning
                if (this.parameters.UseXmlHeaderAuthentication &&
                    !String.IsNullOrEmpty(parsedDocument.Metadata.HeaderHash) &&
                    parsedDocument.Metadata.HeaderHash != HeaderData.HeaderHash)
                {
                    return(new KdbxDecryptionResult(new ReaderResult(KdbxParserCode.BadHeaderHash)));
                }

                return(new KdbxDecryptionResult(this.parameters, parsedDocument, this.rawKey));
            }
            catch (KdbxParseException e)
            {
                return(new KdbxDecryptionResult(e.Error));
            }
        }
Пример #9
0
        /// <summary>
        /// Used to service the given request. Once the image has been responded to the
        /// function will continue with requests until the queue is empty
        /// </summary>
        /// <param name="startingRequestedContext">The request to start with</param>
        /// <returns></returns>
        private async Task ServiceRequest(ImageManagerRequestInternal startingRequestedContext)
        {
            ImageManagerRequestInternal currentRequest = startingRequestedContext;

            while (currentRequest != null)
            {
                // Service the request in a try catch
                try
                {
                    string fileName = MakeFileNameFromUrl(currentRequest.Context.Url);

                    // If not we have to get the image
                    IBuffer imgBuffer = await m_baconMan.NetworkMan.MakeRawGetRequest(currentRequest.Context.Url);

                    // Turn the stream into an image
                    InMemoryRandomAccessStream imageStream = new InMemoryRandomAccessStream();
                    Stream readStream  = imgBuffer.AsStream();
                    Stream writeStream = imageStream.AsStreamForWrite();

                    // Copy the buffer
                    // #todo perf - THERE HAS TO BE A BTTER WAY TO DO THIS.
                    readStream.CopyTo(writeStream);
                    writeStream.Flush();

                    // Seek to the start.
                    imageStream.Seek(0);

                    // Create a response
                    ImageManagerResponseEventArgs response = new ImageManagerResponseEventArgs()
                    {
                        ImageStream = imageStream,
                        Request     = currentRequest.Context,
                        Success     = true
                    };

                    // Fire the callback
                    currentRequest.Context.m_onRequestComplete.Raise(currentRequest.Context, response);
                }
                catch (Exception e)
                {
                    // Report the error
                    m_baconMan.MessageMan.DebugDia("Error getting image", e);

                    // Create a response
                    ImageManagerResponseEventArgs response = new ImageManagerResponseEventArgs()
                    {
                        Request = currentRequest.Context,
                        Success = false
                    };

                    // Send the response
                    currentRequest.Context.m_onRequestComplete.Raise(currentRequest.Context, response);
                }

                // Once we are done, check to see if there is another we should service.
                lock (m_requestList)
                {
                    // Remove the current request.
                    m_requestList.Remove(currentRequest);

                    // Kill the current request
                    currentRequest = null;

                    // Check if there is another request we should service now.
                    for (int i = 0; i < MAX_RUNNING_IMAGE_REQUESTS; i++)
                    {
                        if (m_requestList.Count > i && !m_requestList[i].isServicing)
                        {
                            currentRequest             = m_requestList[i];
                            currentRequest.isServicing = true;
                            break;
                        }
                    }
                }
            }
        }
Пример #10
0
 private Stream BufferToStream(IBuffer buffer)
 {
     return(buffer.AsStream());
 }
Пример #11
0
        private async void AttemptSaveAsync()
        {
            if (!Processing)
            {
                Processing = true;

                AdaptButtonsToState();

                GC.Collect();

                var lowMemory = false;

                try
                {
                    long result = (long)DeviceExtendedProperties.GetValue("ApplicationWorkingSetLimit");

                    lowMemory = result / 1024 / 1024 < 300;
                }
                catch (ArgumentOutOfRangeException)
                {
                }

                IBuffer buffer = null;

                Model.OriginalImage.Position = 0;

                using (var source = new StreamImageSource(Model.OriginalImage))
                    using (var segmenter = new InteractiveForegroundSegmenter(source))
                        using (var annotationsSource = new BitmapImageSource(Model.AnnotationsBitmap))
                        {
                            segmenter.Quality           = lowMemory ? 0.5 : 1;
                            segmenter.AnnotationsSource = annotationsSource;

                            var foregroundColor = Model.ForegroundBrush.Color;
                            var backgroundColor = Model.BackgroundBrush.Color;

                            segmenter.ForegroundColor = Windows.UI.Color.FromArgb(foregroundColor.A, foregroundColor.R, foregroundColor.G, foregroundColor.B);
                            segmenter.BackgroundColor = Windows.UI.Color.FromArgb(backgroundColor.A, backgroundColor.R, backgroundColor.G, backgroundColor.B);

                            using (var effect = new LensBlurEffect(source, new LensBlurPredefinedKernel(Model.KernelShape, (uint)Model.KernelSize)))
                                using (var renderer = new JpegRenderer(effect))
                                {
                                    effect.KernelMap = segmenter;

                                    try
                                    {
                                        buffer = await renderer.RenderAsync();
                                    }
                                    catch (Exception ex)
                                    {
                                        System.Diagnostics.Debug.WriteLine("AttemptSave rendering failed: " + ex.Message);
                                    }
                                }
                        }

                if (buffer != null)
                {
                    using (var library = new MediaLibrary())
                        using (var stream = buffer.AsStream())
                        {
                            library.SavePicture("lensblur_" + DateTime.Now.Ticks, stream);

                            Model.Saved = true;

                            AdaptButtonsToState();
                        }
                }

                Processing = false;

                AdaptButtonsToState();
            }
        }
Пример #12
0
        private async void btnFinalizar_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            try
            {
                Type tipoPage = FragmentFrame.SourcePageType;

                StorageFolder localFolder = await Utils.BaseFolder.CreateFolderAsync(tipoPage.Name.Replace("Page", string.Empty), CreationCollisionOption.OpenIfExists);

                StorageFolder destinationFolder = await localFolder.CreateFolderAsync(Guid.NewGuid().ToString(), CreationCollisionOption.GenerateUniqueName);

                StorageFolder pdfFolder = await localFolder.CreateFolderAsync("Digitalizados", CreationCollisionOption.OpenIfExists);

                // Encabezado
                StorageFile file = await destinationFolder.CreateFileAsync("Metadata.dat", CreationCollisionOption.FailIfExists);

                await FileIO.WriteTextAsync(file, model.StringifyEtiquetas + Environment.NewLine);

                IEnumerable <string> query = from a in model.FileList
                                             select a.Name;

                await FileIO.AppendLinesAsync(file, query);

                List <Stream>  Fotos = new List <Stream>();
                List <IBuffer> lst   = new List <IBuffer>();

                // Detalle
                foreach (FileItem fila in model.FileList)
                {
                    StorageFile filepage = await model.DestinationFolder.GetFileAsync(fila.Name);

                    IBuffer buf = await FileIO.ReadBufferAsync(filepage);

                    lst.Add(buf);
                    Fotos.Add(buf.AsStream());

                    await filepage.MoveAsync(destinationFolder);
                }

                ////////////////////
                // 24-Oct-2016, Roberto Castro, Proceso que guarda el archivo en la maquina local
                Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
                bool value = Convert.ToBoolean(localSettings.Values["SaveLocalFile"]);
                if (value == true)
                {
                    Models.Archivos.Archivos_PostBindingModel model2 = new Models.Archivos.Archivos_PostBindingModel();
                    model2.Aplicacion = model.Aplicacion;
                    model2.Categoria  = model.Categoria;
                    model2.Etiquetas  = model.Etiquetas;

                    IEnumerable <IBuffer> archivos = lst;

                    IBuffer archivo = await ArchivosModel.PostArchivoPdf(model2, archivos);

                    byte[] st = archivo.ToArray();

                    var queryTags = from a in model2.Etiquetas
                                    select a.Valor;
                    string NombreArchivo = string.Join("-", queryTags) + ".pdf";
                    try
                    {
                        await obtenerArchivoGuardado(st, pdfFolder.Path + @"\" + NombreArchivo);
                    }
                    catch { }
                }
                ////////////////////
                // 08-Feb-2017, Roberto Castro, Si se cargaron imagen anteriormente digitalizadas, se borra la carpeta
                if (cboCargar.SelectedItem != null)
                {
                    TransferirModel c      = cboCargar.SelectedItem as TransferirModel;
                    StorageFolder   folder = await localFolder.GetFolderAsync(c.Nombre);

                    await folder.DeleteAsync();
                }
                ////////////////////

                LimpiarVista();

                rootPage.NotifyUser("El documento fue guardado exitosamente. Puede continuar.", NotifyType.StatusMessage);
            }
            catch (Exception ex)
            {
                rootPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
            }
        }
Пример #13
0
        private async void btnCombinar_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            if (model.Etiquetas.Count() > 0)
            {
                try
                {
                    model.ScenarioRunning = true;

                    Models.Etiquetas.Etiquetas_GetArchivosBindingModel mdl = new Models.Etiquetas.Etiquetas_GetArchivosBindingModel();
                    mdl.Aplicacion = model.Aplicacion;
                    mdl.Categoria  = model.Categoria;
                    mdl.Etiquetas  = model.Etiquetas;

                    long IDArchivo = await Models.EtiquetasModel.Get(mdl);

                    Models.Archivos.Archivos_GetBindingModel model2 = new Models.Archivos.Archivos_GetBindingModel();
                    model2.ID = IDArchivo;

                    IBuffer buffer = await Models.ArchivosModel.Get(model2);

                    Windows.Data.Pdf.PdfDocument pdf = await Windows.Data.Pdf.PdfDocument.LoadFromStreamAsync(buffer.AsStream().AsRandomAccessStream());

                    for (uint i = 0; i < pdf.PageCount; i++)
                    {
                        Windows.Data.Pdf.PdfPage page = pdf.GetPage(i);

                        StorageFile bmpFile = await model.DestinationFolder.CreateFileAsync(string.Format("Pagina {0}.bmp", i + 1), CreationCollisionOption.GenerateUniqueName);

                        IRandomAccessStream stream = await bmpFile.OpenAsync(FileAccessMode.ReadWrite);

                        await page.RenderToStreamAsync(stream);

                        await stream.FlushAsync();

                        stream.Dispose();
                        page.Dispose();

                        Utils.SetImageSourceFromFile(bmpFile, DisplayImage);

                        rootPage.NotifyUser("Apertura en progreso...", NotifyType.StatusMessage);
                        Utils.UpdateFileData(bmpFile, model);

                        ScanerListView.SelectedItem = model.FileList.Last();
                    }

                    rootPage.NotifyUser(String.Empty, NotifyType.StatusMessage);
                }
                catch (Exception)
                {
                    // No pasa nada
                }
                finally
                {
                    model.ScenarioRunning = false;
                }
            }
            else
            {
                rootPage.NotifyUser("Debe ingresar primero los datos", NotifyType.ErrorMessage);
            }
        }
Пример #14
0
        /// <inheritdoc />
        public override void ForwardProcessDataStream(System.IO.Stream inStream, System.IO.Stream outStream, Dictionary <string, string> options, out long writtenBytes)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            else if (!options.ContainsKey(PasswordOption))
            {
                throw new ArgumentException("Options must contain encryption key", "options");
            }

            if (outStream == null)
            {
                throw new ArgumentNullException("outStream");
            }

#if NETFX_CORE
            inStream.Seek(0, 0);
            outStream.Seek(0, 0);

            IBuffer pwBuffer   = CryptographicBuffer.ConvertStringToBinary(options[PasswordOption], BinaryStringEncoding.Utf8);
            IBuffer saltBuffer = CryptographicBuffer.CreateFromByteArray(SALT);

            // Derive key material for password size 32 bytes for AES256 algorithm
            KeyDerivationAlgorithmProvider keyDerivationProvider = Windows.Security.Cryptography.Core.KeyDerivationAlgorithmProvider.OpenAlgorithm("PBKDF2_SHA1");
            // using salt and 1000 iterations
            KeyDerivationParameters pbkdf2Parms = KeyDerivationParameters.BuildForPbkdf2(saltBuffer, 1000);

            // create a key based on original key and derivation parmaters
            CryptographicKey keyOriginal  = keyDerivationProvider.CreateKey(pwBuffer);
            IBuffer          keyMaterial  = CryptographicEngine.DeriveKeyMaterial(keyOriginal, pbkdf2Parms, 32);
            CryptographicKey derivedPwKey = keyDerivationProvider.CreateKey(pwBuffer);

            // derive buffer to be used for encryption salt from derived password key
            IBuffer saltMaterial = CryptographicEngine.DeriveKeyMaterial(derivedPwKey, pbkdf2Parms, 16);

            // display the buffers - because KeyDerivationProvider always gets cleared after each use, they are very similar unforunately
            string keyMaterialString  = CryptographicBuffer.EncodeToBase64String(keyMaterial);
            string saltMaterialString = CryptographicBuffer.EncodeToBase64String(saltMaterial);

            SymmetricKeyAlgorithmProvider symProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm("AES_CBC_PKCS7");
            // create symmetric key from derived password key
            CryptographicKey symmKey = symProvider.CreateSymmetricKey(keyMaterial);

            using (MemoryStream ms = new MemoryStream())
            {
                inStream.CopyTo(ms);
                // encrypt data buffer using symmetric key and derived salt material
                IBuffer resultBuffer = CryptographicEngine.Encrypt(symmKey, WindowsRuntimeBufferExtensions.GetWindowsRuntimeBuffer(ms), saltMaterial);
                resultBuffer.AsStream().CopyTo(outStream);
                writtenBytes = outStream.Position;
            }
#else
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(options[PasswordOption], SALT);
            var key = pdb.GetBytes(32);
            pdb.Reset();
            var iv = pdb.GetBytes(16);

            using (var transform = encrypter.CreateEncryptor(key, iv))
            {
                using (MemoryStream internalStream = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(internalStream, transform, CryptoStreamMode.Write))
                    {
                        StreamTools.Write(inStream, csEncrypt);
                        inStream.Flush();
                        csEncrypt.FlushFinalBlock();

                        internalStream.Seek(0, 0);
                        StreamTools.Write(internalStream, outStream);
                        writtenBytes = outStream.Position;
                    }
                }
            }
#endif
        }
Пример #15
0
        private async Task DownloadToCacheFileAsync(Uri uri, string fileName, CancellationToken cancellationToken)
        {
            Exception obj = null;
            int       num = 0;

            try
            {
                HttpClient httpClient = new HttpClient();
                try
                {
                    IBuffer source = await httpClient.GetBufferAsync(uri).AsTask(cancellationToken, new Progress <HttpProgress>(delegate(HttpProgress progress)
                    {
                        ulong?totalBytesToReceive = progress.TotalBytesToReceive;
                        if (totalBytesToReceive.HasValue)
                        {
                            double percentage = Math.Round(progress.BytesReceived * 100.0 / totalBytesToReceive.Value, 2);
                            EventHandler <DownloadProgressChangedArgs> expr_3E = this.DownloadProgressChanged;
                            if (expr_3E == null)
                            {
                                return;
                            }
                            expr_3E.Invoke(this, new DownloadProgressChangedArgs(uri, percentage));
                        }
                    }));

                    Stream stream = source.AsStream();
                    try
                    {
                        Stream stream2 = await UriLoader.CreateTempFileStreamAsync(fileName);

                        try
                        {
                            await stream.CopyToAsync(stream2);
                        }
                        finally
                        {
                            if (stream2 != null)
                            {
                                stream2.Dispose();
                            }
                        }
                        stream2 = null;
                    }
                    finally
                    {
                        if (stream != null)
                        {
                            stream.Dispose();
                        }
                    }
                    stream = null;
                }
                finally
                {
                    if (httpClient != null)
                    {
                        httpClient.Dispose();
                    }
                }
                httpClient = null;
            }
            catch (Exception obj_0)
            {
                num = 1;
                obj = obj_0;
            }

            if (num == 1)
            {
                await UriLoader.DeleteTempFileAsync(fileName);

                Exception expr_2FC = obj as Exception;
                if (expr_2FC == null)
                {
                    throw obj;
                }
                ExceptionDispatchInfo.Capture(expr_2FC).Throw();
            }
            obj = null;
        }
Пример #16
0
        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))
                    {
                        Interop       interop = SimpleIoc.Default.GetInstance <Interop>();
                        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));
        }