Initial hack at Android / Cocoa bitmap loading

This commit is contained in:
Paul Betts 2013-06-30 14:25:44 -07:00
Родитель bbababc914
Коммит 90c28c21b4
6 изменённых файлов: 271 добавлений и 4 удалений

73
Splat/Android/Bitmaps.cs Normal file
Просмотреть файл

@ -0,0 +1,73 @@
using System;
using System.Threading.Tasks;
using System.IO;
using Android.Graphics;
using System.Threading;
namespace Splat
{
class AndroidBitmapLoader : IBitmapLoader
{
public Task<IBitmap> Load(Stream sourceStream, float? desiredWidth, float? desiredHeight)
{
if (desiredWidth == null) {
return Task.Run(() => BitmapFactory.DecodeStream(sourceStream).FromNative());
}
var opts = new BitmapFactory.Options() {
OutWidth = (int)desiredWidth.Value,
OutHeight = (int)desiredHeight.Value,
};
var noPadding = new Rect(0, 0, 0, 0);
return Task.Run(() => BitmapFactory.DecodeStream(sourceStream, noPadding, opts).FromNative());
}
public IBitmap Create(float width, float height)
{
return Bitmap.CreateBitmap((int)width, (int)height, Bitmap.Config.Argb8888).FromNative();
}
}
sealed class AndroidBitmap : IBitmap
{
internal Bitmap inner;
public AndroidBitmap(Bitmap inner)
{
this.inner = inner;
}
public float Width {
get { return inner.Width; }
}
public float Height {
get { return inner.Height; }
}
public Task Save(CompressedBitmapFormat format, float quality, Stream target)
{
var fmt = format == CompressedBitmapFormat.Jpeg ? Bitmap.CompressFormat.Jpeg : Bitmap.CompressFormat.Png;
return Task.Run(() => { inner.Compress(fmt, (int)quality * 100, target); });
}
public void Dispose()
{
var disp = Interlocked.Exchange(ref inner, null);
if (disp != null) disp.Dispose();
}
}
public static class BitmapMixins
{
public static Bitmap ToNative(this IBitmap This)
{
return ((AndroidBitmap)This).inner;
}
public static IBitmap FromNative(this Bitmap This, bool copy = false)
{
if (copy) return new AndroidBitmap(This.Copy(This.GetConfig(), true));
return new AndroidBitmap(This);
}
}
}

89
Splat/Bitmaps.cs Normal file
Просмотреть файл

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Splat
{
public enum CompressedBitmapFormat
{
Png, Jpeg,
}
/// <summary>
/// Represents the platform-specific image loader class. Unless you are
/// testing image loading, you don't usually need to implement this.
/// </summary>
public interface IBitmapLoader
{
/// <summary>
/// Loads a bitmap from a byte stream
/// </summary>
/// <param name="sourceStream">The stream to load the image from.</param>
/// <param name="desiredWidth">The desired width of the image.</param>
/// <param name="desiredHeight">The desired height of the image.</param>
/// <returns>A future result representing the loaded image</returns>
Task<IBitmap> Load(Stream sourceStream, float? desiredWidth, float? desiredHeight);
/// <summary>
/// Creates an empty bitmap of the specified dimensions
/// </summary>
/// <param name="width">The width of the canvas</param>
/// <param name="height">The height of the canvas</param>
/// <returns>A new image. Use ToNative() to convert this to a native bitmap</returns>
IBitmap Create(float width, float height);
}
/// <summary>
/// Represents a bitmap image that was loaded via a ViewModel. Every platform
/// provides FromNative and ToNative methods to convert this object to the
/// platform-specific versions.
/// </summary>
public interface IBitmap : IDisposable
{
/// <summary>
/// Width in pixel units (depending on platform)
/// </summary>
float Width { get; }
/// <summary>
/// Height in pixel units (depending on platform)
/// </summary>
float Height { get; }
/// <summary>
/// Saves an image to a target stream
/// </summary>
/// <param name="format">The format to save the image in.</param>
/// <param name="quality">If JPEG is specified, this is a quality
/// factor between 0.0 and 1.0f where 1.0f is the best quality.</param>
/// <param name="target">The target stream to save to.</param>
/// <returns>A signal indicating the Save has completed.</returns>
Task Save(CompressedBitmapFormat format, float quality, Stream target);
}
/// <summary>
/// This class loads and creates bitmap resources in a platform-independent
/// way.
/// </summary>
public static class BitmapLoader
{
// TODO: This needs to be improved once we move the "Detect in Unit Test
// Runner" code into Splat
static IBitmapLoader _Current;
public static IBitmapLoader Current {
get {
var ret = _Current;
if (ret == null) {
throw new Exception("Could not find a default bitmap loader. This should never happen, your dependency resolver is broken");
}
return ret;
}
set { _Current = value; }
}
}
}

95
Splat/Cocoa/Bitmaps.cs Normal file
Просмотреть файл

@ -0,0 +1,95 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
#if UIKIT
using MonoTouch.UIKit;
using MonoTouch.Foundation;
#else
using MonoMac.AppKit;
using MonoMac.Foundation;
using UIImage = MonoMac.AppKit.NSImage;
#endif
namespace Splat
{
class CocoaBitmapLoader : IBitmapLoader
{
public Task<IBitmap> Load(Stream sourceStream, float? desiredWidth, float? desiredHeight)
{
return Task.Run(() => {
var data = NSData.FromStream(sourceStream);
#if UIKIT
return (IBitmap)new CocoaBitmap(UIImage.LoadFromData(data));
#else
return (IBitmap) new CocoaBitmap(new UIImage(data));
#endif
});
}
public IBitmap Create(float width, float height)
{
throw new NotImplementedException();
}
}
sealed class CocoaBitmap : IBitmap
{
internal UIImage inner;
public CocoaBitmap(UIImage inner)
{
this.inner = inner;
}
public float Width {
get { return inner.Size.Width; }
}
public float Height {
get { return inner.Size.Height; }
}
public Task Save(CompressedBitmapFormat format, float quality, Stream target)
{
return Task.Run(() => {
#if UIKIT
var data = format == CompressedBitmapFormat.Jpeg ? inner.AsJPEG((float)quality) : inner.AsPNG();
data.AsStream().CopyTo(target);
#else
var imageRep = (NSBitmapImageRep)NSBitmapImageRep.ImageRepFromData(inner.AsTiff());
var props = format == CompressedBitmapFormat.Png ?
new NSDictionary() :
new NSDictionary(new NSNumber(quality), new NSString("NSImageCompressionFactor"));
var type = format == CompressedBitmapFormat.Png ? NSBitmapImageFileType.Png : NSBitmapImageFileType.Jpeg;
var outData = imageRep.RepresentationUsingTypeProperties(type, props);
outData.AsStream().CopyTo(target);
#endif
});
}
public void Dispose()
{
var disp = Interlocked.Exchange(ref inner, null);
if (disp != null) disp.Dispose();
}
}
public static class BitmapMixins
{
public static UIImage ToNative(this IBitmap This)
{
return ((CocoaBitmap)This).inner;
}
public static IBitmap FromNative(this UIImage This, bool copy = false)
{
if (copy) return new CocoaBitmap((UIImage)This.Copy());
return new CocoaBitmap(This);
}
}
}

4
Splat/Resources/Resource.designer.cs сгенерированный
Просмотреть файл

@ -9,9 +9,9 @@
// </autogenerated>
// ------------------------------------------------------------------------------
[assembly: Android.Runtime.ResourceDesignerAttribute("Splatmonodroid.Resource", IsApplication=false)]
[assembly: Android.Runtime.ResourceDesignerAttribute("Splat.Resource", IsApplication=false)]
namespace Splatmonodroid
namespace Splat
{

Просмотреть файл

@ -44,6 +44,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Bitmaps.cs" />
<Compile Include="Android\Bitmaps.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
@ -52,4 +54,7 @@
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<ItemGroup>
<Folder Include="Android\" />
</ItemGroup>
</Project>

Просмотреть файл

@ -17,18 +17,18 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\monotouch</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<DefineConstants>DEBUG; UIKIT</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\monotouch</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<DefineConstants>UIKIT</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -38,6 +38,11 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Cocoa\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Compile Include="Bitmaps.cs" />
<Compile Include="Cocoa\Bitmaps.cs" />
</ItemGroup>
</Project>