Пример #1
0
        /// <summary>
        /// Resizes the Mask Surface to the given size
        /// </summary>
        /// <param name="surfaceLock">The object to lock to prevent multiple threads
        /// from accessing the surface at the same time.</param>
        /// <param name="surface">CompositionDrawingSurface</param>
        /// <param name="size">New size of the Mask Surface</param>
        public void ResizeDrawingSurface(object surfaceLock, CompositionDrawingSurface surface, Size size)
        {
            // Cannot resize to Size.Empty. Will throw exception!
            if (size.IsEmpty)
            {
                return;
            }

            // Ensuring that the size contains positive values
            size.Width  = Math.Max(0, size.Width);
            size.Height = Math.Max(0, size.Height);

            //
            // Since multiple threads could be trying to get access to the device/surface
            // at the same time, we need to do any device/surface work under a lock.
            //
            lock (surfaceLock)
            {
                CanvasComposition.Resize(surface, size);
            }
        }
Пример #2
0
        public override async Task Draw(CompositionGraphicsDevice device, Object drawingLock, CompositionDrawingSurface surface, Size size)
        {
            var canvasDevice = CanvasComposition.GetCanvasDevice(device);

            using (var canvasBitmap = await CanvasBitmap.LoadAsync(canvasDevice, _uri))
            {
                var bitmapSize = canvasBitmap.Size;

                //
                // Because the drawing is done asynchronously and multiple threads could
                // be trying to get access to the device/surface at the same time, we need
                // to do any device/surface work under a lock.
                //
                lock (drawingLock)
                {
                    Size surfaceSize = size;
                    if (surface.Size != size || surface.Size == new Size(0, 0))
                    {
                        // Resize the surface to the size of the image
                        CanvasComposition.Resize(surface, bitmapSize);
                        surfaceSize = bitmapSize;
                    }

                    // Allow the app to process the bitmap if requested
                    if (_handler != null)
                    {
                        _handler(surface, canvasBitmap, device);
                    }
                    else
                    {
                        // Draw the image to the surface
                        using (var session = CanvasComposition.CreateDrawingSession(surface))
                        {
                            session.Clear(Windows.UI.Color.FromArgb(0, 0, 0, 0));
                            session.DrawImage(canvasBitmap, new Rect(0, 0, surfaceSize.Width, surfaceSize.Height), new Rect(0, 0, bitmapSize.Width, bitmapSize.Height));
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Renders the CanvasBitmap on the CompositionDrawingSurface based on the given options.
        /// </summary>
        /// <param name="surfaceLock">The object to lock to prevent multiple threads
        /// from accessing the surface at the same time.</param>
        /// <param name="surface">CompositionDrawingSurface on which the CanvasBitmap has to be rendered.</param>
        /// <param name="canvasBitmap">CanvasBitmap created by loading the image from the Uri</param>
        /// <param name="options">Describes the image's resize and alignment options in the allocated space.</param>
        private static void RenderBitmap(object surfaceLock, CompositionDrawingSurface surface, CanvasBitmap canvasBitmap,
                                         CompositionSurfaceImageOptions options)
        {
            var surfaceSize = surface.Size;

            // If the canvasBitmap is null, then just fill the surface with the SurfaceBackgroundColor
            if (canvasBitmap == null)
            {
                // No need to render if the width and/or height of the surface is zero
                if (surfaceSize.IsEmpty || surfaceSize.Width.IsZero() || surfaceSize.Height.IsZero())
                {
                    return;
                }

                //
                // Since multiple threads could be trying to get access to the device/surface
                // at the same time, we need to do any device/surface work under a lock.
                //
                lock (surfaceLock)
                {
                    using (var session = CanvasComposition.CreateDrawingSession(surface))
                    {
                        // Clear the surface with the SurfaceBackgroundColor
                        session.Clear(options.SurfaceBackgroundColor);
                    }

                    // No need to proceed further
                    return;
                }
            }

            //
            // Since multiple threads could be trying to get access to the device/surface
            // at the same time, we need to do any device/surface work under a lock.
            //
            lock (surfaceLock)
            {
                // Is AutoResize Enabled?
                if (options.AutoResize)
                {
                    // If AutoResize is allowed and the canvasBitmap size and surface size are
                    // not matching then resize the surface to match the canvasBitmap size.
                    //
                    // NOTE: HorizontalAlignment, Vertical Alignment and Stretch will be
                    // handled by the CompositionSurfaceBrush created using this surface.
                    //
                    if (canvasBitmap.Size != surfaceSize)
                    {
                        // Resize the surface
                        CanvasComposition.Resize(surface, canvasBitmap.Size);
                        surfaceSize = canvasBitmap.Size;
                    }

                    // No need to render if the width and/or height of the surface is zero
                    if (surfaceSize.IsEmpty || surface.Size.Width.IsZero() || surface.Size.Height.IsZero())
                    {
                        return;
                    }

                    // Draw the image to the surface
                    using (var session = CanvasComposition.CreateDrawingSession(surface))
                    {
                        // Render the image
                        session.DrawImage(canvasBitmap,                                                      // CanvasBitmap
                                          new Rect(0, 0, surfaceSize.Width, surfaceSize.Height),             // Target Rectangle
                                          new Rect(0, 0, canvasBitmap.Size.Width, canvasBitmap.Size.Height), // Source Rectangle
                                          options.Opacity,                                                   // Opacity
                                          options.Interpolation);                                            // Interpolation
                    }
                }
                else
                {
                    // No need to render if the width and/or height of the surface is zero
                    if (surfaceSize.IsEmpty || surface.Size.Width.IsZero() || surface.Size.Height.IsZero())
                    {
                        return;
                    }

                    var bitmapSize   = canvasBitmap.Size;
                    var sourceWidth  = bitmapSize.Width;
                    var sourceHeight = bitmapSize.Height;
                    var ratio        = sourceWidth / sourceHeight;
                    var targetWidth  = 0d;
                    var targetHeight = 0d;
                    var left         = 0d;
                    var top          = 0d;

                    // Stretch Mode
                    switch (options.Stretch)
                    {
                    case Stretch.None:
                        targetWidth  = sourceWidth;
                        targetHeight = sourceHeight;
                        break;

                    case Stretch.Fill:
                        targetWidth  = surfaceSize.Width;
                        targetHeight = surfaceSize.Height;
                        break;

                    case Stretch.Uniform:
                        // If width is greater than height
                        if (ratio > 1.0)
                        {
                            targetHeight = Math.Min(surfaceSize.Width / ratio, surfaceSize.Height);
                            targetWidth  = targetHeight * ratio;
                        }
                        else
                        {
                            targetWidth  = Math.Min(surfaceSize.Height * ratio, surfaceSize.Width);
                            targetHeight = targetWidth / ratio;
                        }
                        break;

                    case Stretch.UniformToFill:
                        // If width is greater than height
                        if (ratio > 1.0)
                        {
                            targetHeight = Math.Max(surfaceSize.Width / ratio, surfaceSize.Height);
                            targetWidth  = targetHeight * ratio;
                        }
                        else
                        {
                            targetWidth  = Math.Max(surfaceSize.Height * ratio, surfaceSize.Width);
                            targetHeight = targetWidth / ratio;
                        }
                        break;
                    }

                    // Horizontal Alignment
                    switch (options.HorizontalAlignment)
                    {
                    case AlignmentX.Left:
                        left = 0;
                        break;

                    case AlignmentX.Center:
                        left = (surfaceSize.Width - targetWidth) / 2.0;
                        break;

                    case AlignmentX.Right:
                        left = surfaceSize.Width - targetWidth;
                        break;
                    }

                    // Vertical Alignment
                    switch (options.VerticalAlignment)
                    {
                    case AlignmentY.Top:
                        top = 0;
                        break;

                    case AlignmentY.Center:
                        top = (surfaceSize.Height - targetHeight) / 2.0;
                        break;

                    case AlignmentY.Bottom:
                        top = surfaceSize.Height - targetHeight;
                        break;
                    }

                    // Draw the image to the surface
                    using (var session = CanvasComposition.CreateDrawingSession(surface))
                    {
                        // Clear the surface with the SurfaceBackgroundColor
                        session.Clear(options.SurfaceBackgroundColor);
                        // Render the image
                        session.DrawImage(canvasBitmap,                                   // CanvasBitmap
                                          new Rect(left, top, targetWidth, targetHeight), // Target Rectangle
                                          new Rect(0, 0, sourceWidth, sourceHeight),      // Source Rectangle
                                          options.Opacity,                                // Opacity
                                          options.Interpolation);                         // Interpolation
                    }
                }
            }
        }
Пример #4
0
        private static async Task <CompositionSurfaceBrush> LoadWin2DSurfaceBrushFromImageAsync(
            [NotNull] Compositor compositor, [NotNull] CanvasControl canvas, [NotNull] Uri uri, int timeThreshold = 1000, bool reload = false)
        {
            TaskCompletionSource <CompositionSurfaceBrush> tcs = new TaskCompletionSource <CompositionSurfaceBrush>();

            async Task <CompositionSurfaceBrush> LoadImageAsync(bool shouldThrow)
            {
                // Load the image - this will only succeed when there's an available Win2D device
                try
                {
                    using (CanvasBitmap bitmap = await CanvasBitmap.LoadAsync(canvas, uri))
                    {
                        // Get the device and the target surface
                        CompositionGraphicsDevice device  = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvas.Device);
                        CompositionDrawingSurface surface = device.CreateDrawingSurface(default(Size),
                                                                                        DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);

                        // Calculate the surface size
                        Size size = bitmap.Size;
                        CanvasComposition.Resize(surface, size);

                        // Draw the image on the surface and get the resulting brush
                        using (CanvasDrawingSession session = CanvasComposition.CreateDrawingSession(surface))
                        {
                            session.Clear(Color.FromArgb(0, 0, 0, 0));
                            session.DrawImage(bitmap, new Rect(0, 0, size.Width, size.Height), new Rect(0, 0, size.Width, size.Height));
                            CompositionSurfaceBrush brush = surface.Compositor.CreateSurfaceBrush(surface);
                            return(brush);
                        }
                    }
                }
                catch when(!shouldThrow)
                {
                    // Win2D error, just ignore and continue
                    return(null);
                }
            }

            async void Canvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
            {
                // Cancel previous actions
                args.GetTrackedAction()?.Cancel();

                // Load the image and notify the canvas
                Task <CompositionSurfaceBrush> task = LoadImageAsync(false);
                IAsyncAction action = task.AsAsyncAction();

                try
                {
                    args.TrackAsyncAction(action);
                    CompositionSurfaceBrush brush = await task;
                    action.Cancel();
                    tcs.TrySetResult(brush);
                }
                catch (COMException)
                {
                    // Somehow another action was still being tracked
                    tcs.TrySetResult(null);
                }
            }

            // Lock the semaphore and check the cache first
            await Win2DSemaphore.WaitAsync();

            if (!reload && SurfacesCache.TryGetValue(uri.ToString(), out CompositionSurfaceBrush cached))
            {
                Win2DSemaphore.Release();
                return(cached);
            }

            // Load the image
            canvas.CreateResources += Canvas_CreateResources;
            try
            {
                // This will throw and the canvas will re-initialize the Win2D device if needed
                await LoadImageAsync(true);
            }
            catch (ArgumentException)
            {
                // Just ignore here
            }
            catch
            {
                // Win2D messed up big time
                tcs.TrySetResult(null);
            }
            await Task.WhenAny(tcs.Task, Task.Delay(timeThreshold).ContinueWith(t => tcs.TrySetResult(null)));

            canvas.CreateResources -= Canvas_CreateResources;
            CompositionSurfaceBrush instance = tcs.Task.Result;
            String key = uri.ToString();

            if (instance != null && !SurfacesCache.ContainsKey(key))
            {
                SurfacesCache.Add(key, instance);
            }
            Win2DSemaphore.Release();
            return(instance);
        }