Forráskód Böngészése

Added support for saving a bitmap to a stream, initializing an icon from a stream, and added in a special-casing shortcut for Gtk when using Cairo as a rendering backend to make icons more efficient.

Jeremy Koritzinsky 9 éve
szülő
commit
d211c54aca

+ 5 - 0
src/Android/Avalonia.Android/AndroidPlatform.cs

@@ -76,5 +76,10 @@ namespace Avalonia.Android
         {
             return null;
         }
+
+        public IIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            return null;
+        }
     }
 }

+ 6 - 0
src/Avalonia.Controls/Icon.cs

@@ -5,6 +5,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Avalonia.Media.Imaging;
 
 namespace Avalonia.Controls
 {
@@ -13,6 +14,11 @@ namespace Avalonia.Controls
     /// </summary>
     public class Icon
     {
+        public Icon(IBitmap bitmap)
+        {
+            PlatformImpl = AvaloniaLocator.Current.GetService<IPlatformIconLoader>().LoadIcon(bitmap.PlatformImpl);
+        }
+
         public Icon(string fileName)
         {
             PlatformImpl = AvaloniaLocator.Current.GetService<IPlatformIconLoader>().LoadIcon(fileName);

+ 2 - 0
src/Avalonia.Controls/Platform/IPlatformIconLoader.cs

@@ -4,6 +4,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Avalonia.Media.Imaging;
 
 namespace Avalonia.Platform
 {
@@ -11,5 +12,6 @@ namespace Avalonia.Platform
     {
         IIconImpl LoadIcon(string fileName);
         IIconImpl LoadIcon(Stream stream);
+        IIconImpl LoadIcon(IBitmapImpl bitmap);
     }
 }

+ 6 - 0
src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.IO;
 using Avalonia.Platform;
 
@@ -66,5 +67,10 @@ namespace Avalonia.Media.Imaging
         {
             PlatformImpl.Save(fileName);
         }
+
+        public void Save(Stream stream)
+        {
+            PlatformImpl.Save(stream);
+        }
     }
 }

+ 7 - 0
src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System.IO;
 using Avalonia.Platform;
 
 namespace Avalonia.Media.Imaging
@@ -30,5 +31,11 @@ namespace Avalonia.Media.Imaging
         /// </summary>
         /// <param name="fileName">The filename.</param>
         void Save(string fileName);
+
+        /// <summary>
+        /// Saves the bitmap to a stream in png format.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        void Save(Stream stream);
     }
 }

+ 8 - 0
src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs

@@ -1,6 +1,8 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System.IO;
+
 namespace Avalonia.Platform
 {
     /// <summary>
@@ -23,5 +25,11 @@ namespace Avalonia.Platform
         /// </summary>
         /// <param name="fileName">The filename.</param>
         void Save(string fileName);
+
+        /// <summary>
+        /// Saves the bitmap to a stream.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        void Save(Stream stream);
     }
 }

+ 19 - 19
src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs

@@ -85,25 +85,25 @@ namespace Avalonia.Cairo.Media
             _context.Scale(scale.X, scale.Y);
             destRect /= scale;
 
-            if (opacityOverride < 1.0f) {
-                _context.PushGroup ();
-                Gdk.CairoHelper.SetSourcePixbuf (
-                    _context, 
-                    impl.Surface, 
-                    -sourceRect.X + destRect.X, 
-                    -sourceRect.Y + destRect.Y);
-
-                _context.Rectangle (destRect.ToCairo ());
-                _context.Fill ();
-                _context.PopGroupToSource ();
-                _context.PaintWithAlpha (opacityOverride);
-            } else {
-                _context.PushGroup ();
-                Gdk.CairoHelper.SetSourcePixbuf (
-                    _context, 
-                    impl.Surface, 
-                    -sourceRect.X + destRect.X, 
-                    -sourceRect.Y + destRect.Y);
+			if (opacityOverride < 1.0f) {
+				_context.PushGroup ();
+				Gdk.CairoHelper.SetSourcePixbuf (
+					_context, 
+					impl, 
+					-sourceRect.X + destRect.X, 
+					-sourceRect.Y + destRect.Y);
+
+				_context.Rectangle (destRect.ToCairo ());
+				_context.Fill ();
+				_context.PopGroupToSource ();
+				_context.PaintWithAlpha (opacityOverride);
+			} else {
+				_context.PushGroup ();
+				Gdk.CairoHelper.SetSourcePixbuf (
+					_context, 
+					impl, 
+					-sourceRect.X + destRect.X, 
+					-sourceRect.Y + destRect.Y);
 
                 _context.Rectangle (destRect.ToCairo ());
                 _context.Fill ();

+ 11 - 9
src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs

@@ -6,28 +6,30 @@ using Avalonia.Platform;
 
 namespace Avalonia.Cairo.Media.Imaging
 {
+    using System.IO;
     using Cairo = global::Cairo;
 
-    public class BitmapImpl : IBitmapImpl
+    public class BitmapImpl : Gdk.Pixbuf, IBitmapImpl
     {
         public BitmapImpl(Gdk.Pixbuf pixbuf)
+            :base(pixbuf, 0, 0, pixbuf.Width, pixbuf.Height)
         {
-            Surface = pixbuf;
         }
 
-        public int PixelWidth => Surface.Width;
+        public int PixelWidth => Width;
 
-        public int PixelHeight => Surface.Height;
+        public int PixelHeight => Height;
 
-        public Gdk.Pixbuf Surface
+        public void Save(string fileName)
         {
-            get;
+            // TODO: Test
+            Save(fileName, "png");
         }
 
-        public void Save(string fileName)
+        public void Save(Stream stream)
         {
-            // TODO: Test
-            Surface.Save(fileName, "png");
+            var buffer = SaveToBuffer("png");
+            stream.Write(buffer, 0, buffer.Length);
         }
     }
 }

+ 11 - 0
src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs

@@ -8,6 +8,7 @@ using Avalonia.Rendering;
 
 namespace Avalonia.Cairo.Media.Imaging
 {
+    using System.IO;
     using Cairo = global::Cairo;
 
     public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl
@@ -43,5 +44,15 @@ namespace Avalonia.Cairo.Media.Imaging
         {
             return _renderTarget.CreateDrawingContext();
         }
+
+        public void Save(Stream stream)
+        {
+            var tempFileName = Path.GetTempFileName();
+            Surface.WriteToPng(tempFileName);
+            using (var tempFile = new FileStream(tempFileName, FileMode.Create))
+            {
+                tempFile.CopyTo(stream);
+            }
+        }
     }
 }

+ 16 - 0
src/Gtk/Avalonia.Gtk/GtkPlatform.cs

@@ -124,5 +124,21 @@ namespace Avalonia.Gtk
         {
             return new IconImpl(new Gdk.Pixbuf(stream));
         }
+
+        public IIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            if (bitmap is Gdk.Pixbuf)
+            {
+                return new IconImpl((Gdk.Pixbuf)bitmap);
+            }
+            else
+            {
+                using (var memoryStream = new MemoryStream())
+                {
+                    bitmap.Save(memoryStream);
+                    return new IconImpl(new Gdk.Pixbuf(memoryStream));
+                } 
+            }
+        }
     }
 }

+ 25 - 3
src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs

@@ -2,9 +2,11 @@
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
 using Avalonia.Controls;
+using Avalonia.Media.Imaging;
 using Avalonia.Platform;
 using OmniXaml.TypeConversion;
 
@@ -14,7 +16,7 @@ namespace Avalonia.Markup.Xaml.Converters
     {
         public bool CanConvertFrom(IValueContext context, Type sourceType)
         {
-            return sourceType == typeof(string);
+            return sourceType == typeof(string) || typeof(IBitmap).GetTypeInfo().IsAssignableFrom(sourceType.GetTypeInfo());
         }
 
         public bool CanConvertTo(IValueContext context, Type destinationType)
@@ -24,14 +26,34 @@ namespace Avalonia.Markup.Xaml.Converters
 
         public object ConvertFrom(IValueContext context, CultureInfo culture, object value)
         {
-            var uri = new Uri((string)value, UriKind.RelativeOrAbsolute);
+            var path = value as string;
+            if (path != null)
+            {
+                return CreateIconFromPath(context, path); 
+            }
+            var bitmap = value as IBitmap;
+            if (bitmap != null)
+            {
+                return CreateIconFromBitmap(bitmap);
+            }
+            throw new NotSupportedException();
+        }
+
+        private Icon CreateIconFromBitmap(IBitmap bitmap)
+        {
+            return new Icon(bitmap);
+        }
+
+        private Icon CreateIconFromPath(IValueContext context, string path)
+        {
+            var uri = new Uri(path, UriKind.RelativeOrAbsolute);
             var baseUri = GetBaseUri(context);
             var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file";
 
             switch (scheme)
             {
                 case "file":
-                    return new Icon((string)value);
+                    return new Icon(path);
                 default:
                     var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
                     return new Icon(assets.Open(uri, baseUri));

+ 9 - 0
src/Skia/Avalonia.Skia/BitmapImpl.cs

@@ -80,5 +80,14 @@ namespace Avalonia.Skia
             return new DrawingContext(new BitmapDrawingContext(Bitmap));
         }
 
+        public void Save(Stream stream)
+        {
+            IntPtr length;
+            using (var image = SKImage.FromPixels(Bitmap.Info, Bitmap.GetPixels(out length), Bitmap.RowBytes))
+            using (var data = image.Encode())
+            {
+                data.SaveTo(stream);
+            }
+        }
     }
 }

+ 13 - 8
src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs

@@ -117,15 +117,20 @@ namespace Avalonia.Direct2D1.Media
 
             using (FileStream s = new FileStream(fileName, FileMode.Create))
             {
-                PngBitmapEncoder encoder = new PngBitmapEncoder(_factory);
-                encoder.Initialize(s);
-
-                BitmapFrameEncode frame = new BitmapFrameEncode(encoder);
-                frame.Initialize();
-                frame.WriteSource(WicImpl);
-                frame.Commit();
-                encoder.Commit();
+                Save(s);
             }
         }
+
+        public void Save(Stream stream)
+        {
+            PngBitmapEncoder encoder = new PngBitmapEncoder(_factory);
+            encoder.Initialize(stream);
+
+            BitmapFrameEncode frame = new BitmapFrameEncode(encoder);
+            frame.Initialize();
+            frame.WriteSource(WicImpl);
+            frame.Commit();
+            encoder.Commit();
+        }
     }
 }

+ 9 - 0
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -200,5 +200,14 @@ namespace Avalonia.Win32
             var icon = new System.Drawing.Bitmap(stream);
             return new IconImpl(icon);
         }
+
+        public IIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            using (var memoryStream = new MemoryStream())
+            {
+                bitmap.Save(memoryStream);
+                return new IconImpl(new System.Drawing.Bitmap(memoryStream));
+            }
+        }
     }
 }

+ 5 - 0
src/iOS/Avalonia.iOS/PlatformIconLoader.cs

@@ -8,6 +8,11 @@ namespace Avalonia.iOS
 {
     class PlatformIconLoader : IPlatformIconLoader
     {
+        public IIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            return null;
+        }
+
         public IIconImpl LoadIcon(Stream stream)
         {
             return null;