Exemple #1
0
        /// <summary>
        /// Return a paint with Stroke style
        /// </summary>
        /// <param name="destinationRect">RectF that will be drawn into - used by ImageBrush</param>
        /// <returns>A Paint with Stroke style</returns>
        internal Paint GetStrokePaint(Windows.Foundation.Rect destinationRect)
        {
            var paint = GetPaintInner(destinationRect);

            paint?.SetStyle(Paint.Style.Stroke);
            return(paint);
        }
Exemple #2
0
        private async Task RefreshImage(CancellationToken ct, Windows.Foundation.Rect drawRect)
        {
            if (ImageSource is ImageSource imageSource && (_imageSourceChanged || !imageSource.IsOpened) && !drawRect.HasZeroArea())
            {
                try
                {
                    var image = await imageSource.Open(ct, targetWidth : (int)drawRect.Width, targetHeight : (int)drawRect.Height);

                    if (image != null || imageSource.IsImageLoadedToUiDirectly)
                    {
                        OnImageOpened();
                    }
                    else
                    {
                        OnImageFailed();
                    }
                }
                catch (Exception ex)
                {
                    this.Log().Error("RefreshImage failed", ex);
                    OnImageFailed();
                }
            }
            _onImageLoaded?.Invoke();
        }
Exemple #3
0
        /// <summary>
        /// Return a paint with Fill style
        /// </summary>
        /// <param name="destinationRect">RectF that will be drawn into - used by ImageBrush</param>
        /// <returns>A Paint with Fill style</returns>
        internal Paint GetFillPaint(Windows.Foundation.Rect destinationRect)
        {
            var paint = GetPaintInner(destinationRect);

            paint?.SetStyle(SystemFill);
            return(paint);
        }
Exemple #4
0
        private async void RefreshImageAsync(Windows.Foundation.Rect drawRect)
        {
            CoreDispatcher.CheckThreadAccess();

            var cd = new CancellationDisposable();

            _refreshPaint.Disposable = cd;

            await RefreshImage(cd.Token, drawRect);
        }
Exemple #5
0
        /// <summary>
        /// Loads the ImageBrush's source bitmap and transforms it based on target bounds and shape, Stretch mode, and RelativeTransform.
        /// </summary>
        /// <param name="drawRect">The destination bounds</param>
        /// <param name="maskingPath">An optional path to clip the bitmap by (eg an ellipse)</param>
        /// <returns>A bitmap transformed based on target bounds and shape, Stretch mode, and RelativeTransform</returns>
        internal async Task <Bitmap> GetBitmap(CancellationToken ct, Windows.Foundation.Rect drawRect, Path maskingPath = null)
        {
            await RefreshImage(ct, drawRect);

            if (ct.IsCancellationRequested)
            {
                return(null);
            }
            return(TryGetTransformedBitmap(drawRect, maskingPath));
        }
Exemple #6
0
        /// <summary>
        /// Transforms ImageBrush's source bitmap based on target bounds and shape, Stretch mode, and RelativeTransform.
        /// </summary>
        /// <param name="drawRect">The destination bounds</param>
        /// <param name="maskingPath">An optional path to clip the bitmap by (eg an ellipse)</param>
        /// <returns></returns>
        private Bitmap TryGetTransformedBitmap(Windows.Foundation.Rect drawRect, Path maskingPath = null)
        {
            var imgSrc = ImageSource;

            if (imgSrc == null || !imgSrc.TryOpenSync(out var sourceBitmap))
            {
                return(null);
            }

            if (sourceBitmap.Handle == IntPtr.Zero || sourceBitmap.IsRecycled)
            {
                if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Error))
                {
                    this.Log().Error("Attempted to use a collected or recycled bitmap.");
                }
                return(null);
            }

            var outputBitmap = Bitmap.CreateBitmap((int)drawRect.Width, (int)drawRect.Height, Android.Graphics.Bitmap.Config.Argb8888);

            //and a temporary canvas that will draw into the bitmap
            using (var bitmapCanvas = new Canvas(outputBitmap))
            {
                var matrix = GenerateMatrix(drawRect, sourceBitmap);
                var paint  = new Paint()
                {
                    //Smoothes edges of painted area
                    AntiAlias = true,
                    //Applies bilinear sampling (smoothing) to interior of painted area
                    FilterBitmap = true,
                    //The color is not important, we just want an alpha of 100%
                    Color = Colors.White
                };

                //Draw ImageBrush's bitmap to temporary canvas
                bitmapCanvas.DrawBitmap(sourceBitmap, matrix, paint);

                //If a path was supplied, mask the area outside of it
                if (maskingPath != null)
                {
                    //This will draw an alpha of 0 everywhere *outside* the supplied path, leaving the bitmap within the path http://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
                    paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.DstOut));
                    maskingPath.ToggleInverseFillType();
                    bitmapCanvas.DrawPath(maskingPath, paint);
                    maskingPath.ToggleInverseFillType();
                }
                return(outputBitmap);
            }
        }
Exemple #7
0
        /// <summary>
        /// Create matrix to transform image based on relative dimensions of bitmap and drawRect, Stretch mode, and RelativeTransform
        /// </summary>
        /// <param name="drawRect"></param>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private Android.Graphics.Matrix GenerateMatrix(Windows.Foundation.Rect drawRect, Bitmap bitmap)
        {
            var matrix = new Android.Graphics.Matrix();

            // Note that bitmap.Width and bitmap.Height (in physical pixels) are automatically scaled up when loaded from local resources, but aren't when acquired externally.
            // This means that bitmaps acquired externally might not render the same way on devices with different densities when using Stretch.None.

            var sourceRect      = new Windows.Foundation.Rect(0, 0, bitmap.Width, bitmap.Height);
            var destinationRect = GetArrangedImageRect(sourceRect.Size, drawRect);

            matrix.SetRectToRect(sourceRect.ToRectF(), destinationRect.ToRectF(), Android.Graphics.Matrix.ScaleToFit.Fill);

            RelativeTransform?.ToNative(matrix, new Size(drawRect.Width, drawRect.Height), isBrush: true);
            return(matrix);
        }
Exemple #8
0
        /// <summary>
        /// Transforms ImageBrush's bitmap based on target bounds and shape, Stretch mode, and RelativeTransform, and draws it to the supplied canvas.
        /// </summary>
        /// <param name="destinationCanvas">The canvas to draw the final image on</param>
        /// <param name="drawRect">The destination bounds</param>
        /// <param name="maskingPath">An optional path to clip the bitmap by (eg an ellipse)</param>
        internal void DrawBackground(Canvas destinationCanvas, Windows.Foundation.Rect drawRect, Path maskingPath = null)
        {
            //Create a temporary bitmap
            var output = TryGetTransformedBitmap(drawRect, maskingPath);

            if (output == null)
            {
                return;
            }

            var paint = new Paint();

            //Draw the output bitmap to the screen
            var rect = new Android.Graphics.Rect(0, 0, (int)drawRect.Width, (int)drawRect.Height);

            destinationCanvas.DrawBitmap(output, rect, rect, paint);
        }
Exemple #9
0
            public LayoutState(Windows.Foundation.Rect area, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, Thickness padding)
            {
                Area            = area;
                Background      = background;
                BorderBrush     = borderBrush;
                CornerRadius    = cornerRadius;
                BorderThickness = borderThickness;
                Padding         = padding;

                var imageBrushBackground = Background as ImageBrush;

                BackgroundImageSource = imageBrushBackground?.ImageSource;

                BackgroundColor  = (Background as SolidColorBrush)?.Color;
                BorderBrushColor = (BorderBrush as SolidColorBrush)?.Color;

                BackgroundFallbackColor = (Background as XamlCompositionBrushBase)?.FallbackColor;
            }
Exemple #10
0
        internal void ScheduleRefreshIfNeeded(Windows.Foundation.Rect drawRect, Action onImageLoaded)
        {
            _onImageLoaded = onImageLoaded;

            //If ImageSource or draw size has changed, refresh the Paint
            //TODO: should also check if Stretch has changed
            if (_imageSourceChanged || !drawRect.Equals(_lastDrawRect))
            {
                _imageSourceChanged = false;

                if (ImageSource != null)
                {
                    RefreshImageAsync(drawRect);
                }
                else
                {
                    _refreshPaint.Disposable = null;
                }
                _lastDrawRect = drawRect;
            }
        }
Exemple #11
0
        /// <summary>
        /// Synchronously tries to return a bitmap for this ImageBrush. If the backing image is not available,
        /// a fetch will be scheduled and the onImageLoaded callback will be called once the backing image is ready.
        /// </summary>
        /// <param name="drawRect">The destination bounds</param>
        /// <param name="onImageLoaded">A callback that will be called when the backing image changes (eg, to redraw your view)</param>
        /// <param name="maskingPath">An optional path to clip the bitmap by (eg an ellipse)</param>
        /// <returns>A bitmap transformed based on target bounds and shape, Stretch mode, and RelativeTransform</returns>
        internal Bitmap TryGetBitmap(Windows.Foundation.Rect drawRect, Action onImageLoaded, Path maskingPath = null)
        {
            ScheduleRefreshIfNeeded(drawRect, onImageLoaded);

            return(TryGetTransformedBitmap(drawRect, maskingPath));
        }
Exemple #12
0
        //Load bitmap from ImageBrush and set it as a bitmapDrawable background on target view
        private static async Task <IDisposable> SetImageBrushAsBackground(CancellationToken ct, BindableView view, ImageBrush background, Windows.Foundation.Rect drawArea, Path maskingPath, Action onImageSet)
        {
            var bitmap = await background.GetBitmap(ct, drawArea, maskingPath);

            onImageSet();

            if (ct.IsCancellationRequested || bitmap == null)
            {
                bitmap?.Recycle();
                bitmap?.Dispose();
                return(Disposable.Empty);
            }

            var bitmapDrawable = new BitmapDrawable(bitmap);

            SetDrawableAlpha(bitmapDrawable, (int)(background.Opacity * __opaqueAlpha));
            ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(bitmapDrawable));

            return(Disposable.Create(() =>
            {
                bitmapDrawable?.Bitmap?.Recycle();
                bitmapDrawable?.Dispose();
            }));
        }
Exemple #13
0
        private static IDisposable DispatchSetImageBrushAsBackground(BindableView view, ImageBrush background, Windows.Foundation.Rect drawArea, Action onImageSet, Path maskingPath = null)
        {
            var disposable = new CompositeDisposable();

            Dispatch(
                view?.Dispatcher,
                async ct =>
            {
                var bitmapDisposable = await SetImageBrushAsBackground(ct, view, background, drawArea, maskingPath, onImageSet);
                disposable.Add(bitmapDisposable);
            }
                )
            .DisposeWith(disposable);

            return(disposable);
        }