Browse Source

Added functionality to use CroppedBitmap directly in XAML

Вадим Мельников 5 years ago
parent
commit
3aab2d5619

+ 6 - 2
samples/ControlCatalog/Pages/ImagePage.xaml

@@ -23,7 +23,7 @@
 
       <DockPanel Grid.Column="1" Grid.Row="1" Margin="16">
         <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Crop</TextBlock>
-        <ComboBox Name="bitmapCrop" DockPanel.Dock="Top" SelectedIndex="0" SelectionChanged="BitmapCropChanged">
+        <ComboBox Name="bitmapCrop" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="BitmapCropChanged">
           <ComboBoxItem>None</ComboBoxItem>
           <ComboBoxItem>Center</ComboBoxItem>
           <ComboBoxItem>TopLeft</ComboBoxItem>
@@ -31,7 +31,11 @@
           <ComboBoxItem>BottomLeft</ComboBoxItem>
           <ComboBoxItem>BottomRight</ComboBoxItem>
         </ComboBox>
-        <Image Name="croppedImage"/>
+        <Image Name="croppedImage">
+          <Image.Source>
+            <CroppedBitmap  Source="/Assets/delicate-arch-896885_640.jpg" SourceRect="0 0 320 240"/>  
+          </Image.Source>
+        </Image>
       </DockPanel>
 
       <DockPanel Grid.Column="2" Grid.Row="1" Margin="16">

+ 5 - 13
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@@ -13,7 +13,6 @@ namespace ControlCatalog.Pages
         private readonly Image _bitmapImage;
         private readonly Image _drawingImage;
         private readonly Image _croppedImage;
-        private readonly IBitmap _croppedBitmapSource;
 
         public ImagePage()
         {
@@ -21,8 +20,6 @@ namespace ControlCatalog.Pages
             _bitmapImage = this.FindControl<Image>("bitmapImage");
             _drawingImage = this.FindControl<Image>("drawingImage");
             _croppedImage = this.FindControl<Image>("croppedImage");
-            _croppedBitmapSource = LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg");
-            _croppedImage.Source = new CroppedBitmap(_croppedBitmapSource, default);
         }
 
         private void InitializeComponent()
@@ -53,15 +50,16 @@ namespace ControlCatalog.Pages
             if (_croppedImage != null)
             {
                 var comboxBox = (ComboBox)sender;
-                _croppedImage.Source =  new CroppedBitmap( _croppedBitmapSource,  GetCropRect(comboxBox.SelectedIndex));
+                var croppedBitmap = _croppedImage.Source as CroppedBitmap;
+                croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
             }
         }
 
         private PixelRect GetCropRect(int index)
         {
-            var bitmapWidth = _croppedBitmapSource.PixelSize.Width;
-            var bitmapHeight = _croppedBitmapSource.PixelSize.Height;
-            var cropSize = new PixelSize(bitmapWidth / 2, bitmapHeight / 2);
+            var bitmapWidth = 640;
+            var bitmapHeight = 426;
+            var cropSize = new PixelSize(320, 240);
             return index switch
             {
                 1 => new PixelRect(new PixelPoint((bitmapWidth - cropSize.Width) / 2, (bitmapHeight - cropSize.Width) / 2), cropSize),
@@ -73,11 +71,5 @@ namespace ControlCatalog.Pages
             };
             
         }
-
-        private IBitmap LoadBitmap(string uri)
-        {
-            var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
-            return new Bitmap(assets.Open(new Uri(uri)));
-        }
     }
 }

+ 59 - 10
src/Avalonia.Visuals/Media/Imaging/CroppedBitmap.cs

@@ -1,25 +1,77 @@
 using System;
-using System.Collections.Generic;
-using System.Text;
 using Avalonia.Visuals.Media.Imaging;
 
 namespace Avalonia.Media.Imaging
 {
-    public class CroppedBitmap : IImage, IDisposable
+    /// <summary>
+    /// Crops a Bitmap.
+    /// </summary>
+    public class CroppedBitmap : AvaloniaObject, IImage, IAffectsRender, IDisposable
     {
+        /// <summary>
+        /// Defines the <see cref="Source"/> property.
+        /// </summary>
+        public static readonly StyledProperty<IImage> SourceProperty =
+            AvaloniaProperty.Register<CroppedBitmap, IImage>(nameof(Source));
+
+        /// <summary>
+        /// Defines the <see cref="SourceRect"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PixelRect> SourceRectProperty =
+            AvaloniaProperty.Register<CroppedBitmap, PixelRect>(nameof(SourceRect));
+
+        public event EventHandler Invalidated;
+
+        static CroppedBitmap()
+        {
+            SourceRectProperty.Changed.AddClassHandler<CroppedBitmap>((x, e) => x.SourceRectChanged(e));
+            SourceProperty.Changed.AddClassHandler<CroppedBitmap>((x, e) => x.SourceChanged(e));
+        }
+
+        /// <summary>
+        /// Gets or sets the source for the bitmap.
+        /// </summary>
+        public IImage Source
+        {
+            get => GetValue(SourceProperty);
+            set => SetValue(SourceProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets the rectangular area that the bitmap is cropped to.
+        /// </summary>
+        public PixelRect SourceRect
+        {
+            get => GetValue(SourceRectProperty);
+            set => SetValue(SourceRectProperty, value);
+        }
+
         public CroppedBitmap()
         {
             Source = null;
             SourceRect = default;
         }
-        public CroppedBitmap(IBitmap source, PixelRect sourceRect)
+
+        public CroppedBitmap(IImage source, PixelRect sourceRect)
         {
             Source = source;
             SourceRect = sourceRect;
         }
+
+        private void SourceChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            if (e.NewValue == null)
+                return;
+            if (!(e.NewValue is IBitmap))
+                throw new ArgumentException("Only IBitmap supported as source");
+            Invalidated?.Invoke(this, e);
+        }
+
+        private void SourceRectChanged(AvaloniaPropertyChangedEventArgs e) => Invalidated?.Invoke(this, e);
+
         public virtual void Dispose()
         {
-            Source?.Dispose();
+            (Source as IBitmap)?.Dispose();
         }
 
         public Size Size {
@@ -29,7 +81,7 @@ namespace Avalonia.Media.Imaging
                     return Size.Empty;
                 if (SourceRect.IsEmpty)
                     return Source.Size;
-                return SourceRect.Size.ToSizeWithDpi(Source.Dpi);
+                return SourceRect.Size.ToSizeWithDpi((Source as IBitmap).Dpi);
             }
         }
 
@@ -37,11 +89,8 @@ namespace Avalonia.Media.Imaging
         {
             if (Source == null)
                 return;
-            var topLeft = SourceRect.TopLeft.ToPointWithDpi(Source.Dpi);
+            var topLeft = SourceRect.TopLeft.ToPointWithDpi((Source as IBitmap).Dpi);
             Source.Draw(context, sourceRect.Translate(new Vector(topLeft.X, topLeft.Y)), destRect, bitmapInterpolationMode);           
         }
-
-        public IBitmap Source { get; }
-        public PixelRect SourceRect { get; }
     }
 }

+ 2 - 1
src/Avalonia.Visuals/Properties/AssemblyInfo.cs

@@ -8,7 +8,8 @@ using Avalonia.Metadata;
 [assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")]
+[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Imaging")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
 
 [assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")]
-[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")]
+[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")]