Initial hack at Android / Cocoa bitmap loading
This commit is contained in:
Родитель
bbababc914
Коммит
90c28c21b4
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
Загрузка…
Ссылка в новой задаче