Browse Source

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.

pull/575/head
Jeremy Koritzinsky 10 years ago
parent
commit
d211c54aca
  1. 5
      src/Android/Avalonia.Android/AndroidPlatform.cs
  2. 6
      src/Avalonia.Controls/Icon.cs
  3. 2
      src/Avalonia.Controls/Platform/IPlatformIconLoader.cs
  4. 6
      src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs
  5. 7
      src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs
  6. 8
      src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs
  7. 38
      src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs
  8. 20
      src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs
  9. 11
      src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
  10. 16
      src/Gtk/Avalonia.Gtk/GtkPlatform.cs
  11. 28
      src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs
  12. 9
      src/Skia/Avalonia.Skia/BitmapImpl.cs
  13. 21
      src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs
  14. 9
      src/Windows/Avalonia.Win32/Win32Platform.cs
  15. 5
      src/iOS/Avalonia.iOS/PlatformIconLoader.cs

5
src/Android/Avalonia.Android/AndroidPlatform.cs

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

6
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
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
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
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
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);
}
}

38
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 ();

20
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
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
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));
}
}
}
}
}

28
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
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);
}
}
}
}

21
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
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
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;

Loading…
Cancel
Save