Last active
September 3, 2015 20:32
-
-
Save biochimia/74e16bdf8f57cf5ba3de to your computer and use it in GitHub Desktop.
Fuse App to Take Pictures
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project> | |
<References> | |
<PackageReference Name="ObjC" /> | |
<PackageReference Name="Experimental.iOS" /> | |
<PackageReference Name="FuseCore" /> | |
<PackageReference Name="Fuse.BasicTheme" /> | |
<PackageReference Name="Fuse.Controls" /> | |
<PackageReference Name="Fuse.Elements" /> | |
</References> | |
<Files> | |
<UXFile Name="MainView.ux" /> | |
<SourceFile Name="MainView.ux.uno" /> | |
<SourceFile Name="ICamera.uno" /> | |
<SourceFile Name="iOS.Camera.uno" /> | |
<ExtensionsFile Name="iOS.Camera.Helper.cpp.uxl" /> | |
</Files> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Uno; | |
using Uno.Graphics; | |
namespace CameraApp | |
{ | |
public class PictureTakenArgs : EventArgs | |
{ | |
public Texture2D Picture; | |
} | |
public interface ICamera | |
{ | |
void Show(); | |
event EventHandler WillShow; | |
event EventHandler DidHide; | |
event EventHandler<PictureTakenArgs> PictureTaken; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Extensions Backend="CPlusPlus" Condition="iOS"> | |
<Type Name="CameraApp.iOS.Camera.Helper"> | |
<Set Source.FileExtension="mm" /> | |
<Method Signature="FillRGBA8888Buffer(Uno.Buffer,ObjC.ID,int,int)"> | |
<Require Entity="Uno.Buffer._data" /> | |
<Require Source.Include="CoreGraphics/CoreGraphics.h" /> | |
<Require Source.Include="UIKit/UIKit.h" /> | |
<Body> | |
void *data = @{Uno.Buffer:Of($0)._data}->Ptr(); | |
UIImage *image = (UIImage *) $1; | |
int width = $2; | |
int height = $3; | |
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); | |
CGContextRef context = CGBitmapContextCreate( | |
data, width, height, 8, 4 * width, colorSpace, | |
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); | |
CGContextDrawImage( | |
context, CGRectMake(0, 0, width, height), [image CGImage]); | |
CGContextRelease(context); | |
CGColorSpaceRelease(colorSpace); | |
</Body> | |
</Method> | |
</Type> | |
</Extensions> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Uno; | |
using Uno.Graphics; | |
using Uno.Compiler.ExportTargetInterop; | |
using iOS.CoreGraphics; | |
using iOS.Foundation; | |
using iOS.UIKit; | |
namespace CameraApp.iOS | |
{ | |
[ExportCondition("iOS")] | |
public class Camera | |
: ICamera | |
, IUIImagePickerControllerDelegate | |
{ | |
static readonly NSString EXIF; | |
static readonly NSString MEDIA_METADATA; | |
static readonly NSString ORIENTATION; | |
static readonly NSString ORIGINAL_IMAGE; | |
static readonly NSString PIXEL_X_DIMENSION; | |
static readonly NSString PIXEL_Y_DIMENSION; | |
static readonly bool IsCameraAvailable; | |
static Camera() | |
{ | |
EXIF = new NSString(); | |
EXIF.initWithString("{Exif}"); | |
MEDIA_METADATA = new NSString(); | |
MEDIA_METADATA.initWithString("UIImagePickerControllerMediaMetadata"); | |
ORIENTATION = new NSString(); | |
ORIENTATION.initWithString("Orientation"); | |
ORIGINAL_IMAGE = new NSString(); | |
ORIGINAL_IMAGE.initWithString("UIImagePickerControllerOriginalImage"); | |
PIXEL_X_DIMENSION = new NSString(); | |
PIXEL_X_DIMENSION.initWithString("PixelXDimension"); | |
PIXEL_Y_DIMENSION = new NSString(); | |
PIXEL_Y_DIMENSION.initWithString("PixelYDimension"); | |
IsCameraAvailable = UIImagePickerController._isSourceTypeAvailable( | |
UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera); | |
} | |
[ExportCondition("iOS")] | |
[TargetSpecificImplementation] | |
class Helper | |
{ | |
[TargetSpecificImplementation] | |
public static extern void FillRGBA8888Buffer(Buffer buffer, ObjC.ID image, int width, int height); | |
} | |
// | |
// ICamera | |
// | |
public void ICamera.Show() | |
{ | |
var picker = new UIImagePickerController(); | |
picker.init(); | |
picker.Delegate = this; | |
// Camera is not available on the simulator, so fallback to Photo | |
// Library. | |
picker.SourceType = IsCameraAvailable | |
? UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera | |
: UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypePhotoLibrary; | |
OnWillShow(); | |
UIApplication._sharedApplication().KeyWindow.RootViewController.presentModalViewControllerAnimated(picker, true); | |
} | |
public event EventHandler ICamera.WillShow; | |
public event EventHandler ICamera.DidHide; | |
public event EventHandler<PictureTakenArgs> ICamera.PictureTaken; | |
private void OnWillShow() | |
{ | |
EventHandler handler = WillShow; | |
if (handler != null) | |
handler(this, EventArgs.Empty); | |
} | |
private void OnDidHide(UIImagePickerController picker) | |
{ | |
picker.dismissModalViewControllerAnimated(true); | |
EventHandler handler = DidHide; | |
if (handler != null) | |
handler(this, EventArgs.Empty); | |
} | |
// | |
// IUIImagePickerControllerDelegate | |
// | |
public void imagePickerControllerDidCancel(UIImagePickerController picker) | |
{ | |
OnDidHide(picker); | |
} | |
private UIImage ImageForKey(NSDictionary dict, NSString key) | |
{ | |
if (dict == null) | |
return null; | |
ObjC.ID id = dict.objectForKey(key); | |
return id != null ? new UIImage(id) : null; | |
} | |
private NSDictionary DictionaryForKey(NSDictionary dict, NSString key) | |
{ | |
if (dict == null) | |
return null; | |
ObjC.ID id = dict.objectForKey(key); | |
return id != null ? new NSDictionary(id) : null; | |
} | |
private NSNumber NumberForKey(NSDictionary dict, NSString key) | |
{ | |
if (dict == null) | |
return null; | |
ObjC.ID id = dict.objectForKey(key); | |
return id != null ? new NSNumber(id) : null; | |
} | |
private void ProcessPictureFromCamera(UIImage image, NSDictionary info) | |
{ | |
NSDictionary metadata = DictionaryForKey(info, MEDIA_METADATA); | |
NSDictionary exifData = DictionaryForKey(metadata, EXIF); | |
if (metadata == null) | |
{ | |
debug_log "Image metadata not found"; | |
return; | |
} | |
if (exifData == null) | |
debug_log "Exif metadata not found"; | |
else | |
{ | |
NSNumber pixelXDimension = NumberForKey(exifData, PIXEL_X_DIMENSION); | |
NSNumber pixelYDimension = NumberForKey(exifData, PIXEL_Y_DIMENSION); | |
if (pixelXDimension != null && pixelYDimension != null) | |
{ | |
int2 size = int2(pixelXDimension.IntValue, pixelYDimension.IntValue); | |
// Size reflects stored data, but no orientation information seems | |
// to be available in EXIF. | |
debug_log "Image size from Exif: " + size; | |
} | |
} | |
// A separate orientation key provides this information outside the | |
// EXIF dictionary. | |
NSNumber orientation = NumberForKey(metadata, ORIENTATION); | |
if (orientation != null) | |
{ | |
debug_log "Magic orientation number: " + orientation.IntValue; | |
// Magic orientation values (gathered by playing with device) | |
// | |
// 1 - LandscapeLeft | |
// 3 - LandscapeRight | |
// 6 - PortraitUp | |
// 8 - PortraitUpsideDown | |
} | |
} | |
private void ProcessPictureFromLibrary(UIImage image, NSDictionary info) | |
{ | |
// TODO: NSURL with picture location available in info | |
} | |
public void imagePickerControllerDidFinishPickingMediaWithInfo(UIImagePickerController picker, NSDictionary info) | |
{ | |
EventHandler<PictureTakenArgs> handler = PictureTaken; | |
if (handler != null) | |
{ | |
UIImage image = ImageForKey(info, ORIGINAL_IMAGE); | |
int2 size; | |
{ | |
CGSize _size = image.Size; | |
size.X = (int) _size.Width; | |
size.Y = (int) _size.Height; | |
} | |
debug_log "Picture taken, of size " + size.X + " x " + size.Y | |
+ ", with orientation " + image.ImageOrientation; | |
if (IsCameraAvailable) | |
ProcessPictureFromCamera(image, info); | |
else | |
ProcessPictureFromLibrary(image, info); | |
switch (image.ImageOrientation) | |
{ | |
default: | |
break; | |
case UIImageOrientation.UIImageOrientationLeft: | |
case UIImageOrientation.UIImageOrientationRight: | |
case UIImageOrientation.UIImageOrientationLeftMirrored: | |
case UIImageOrientation.UIImageOrientationRightMirrored: | |
// Transpose coordinates to match stored format | |
size = size.YX; | |
break; | |
} | |
Texture2D texture = new Texture2D(size, Format.RGBA8888, false); | |
// TODO: Rotate texture | |
Buffer buffer = new Buffer(size.X * size.Y * 4); | |
Helper.FillRGBA8888Buffer(buffer, image.Handle, size.X, size.Y); | |
texture.Update(buffer); | |
PictureTakenArgs eventArgs = new PictureTakenArgs(); | |
eventArgs.Picture = texture; | |
handler(this, eventArgs); | |
} | |
OnDidHide(picker); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<App xmlns:b="Fuse.BasicTheme" ux:Class="CameraApp.MainView"> | |
<b:BasicTheme /> | |
<DockPanel> | |
<ScrollViewer ClipToBounds="true"> | |
<StackPanel> | |
<Image Height="400" Margin="5, 5, 5, 5" ux:Name="Photo" /> | |
<Button Text="Take Picture" Clicked="TakePicture" /> | |
</StackPanel> | |
</ScrollViewer> | |
</DockPanel> | |
</App> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Fuse.Resources; | |
using Fuse.Triggers; | |
namespace CameraApp | |
{ | |
public partial class MainView | |
{ | |
ICamera camera; | |
bool EnsureCameraInitialized() | |
{ | |
if (camera != null) | |
return true; | |
if (defined(iOS)) | |
{ | |
camera = new iOS.Camera(); | |
} | |
if (camera == null) | |
{ | |
debug_log "Camera not implemented for current platform"; | |
return false; | |
} | |
camera.PictureTaken += OnPictureTaken; | |
return true; | |
} | |
void TakePicture(object sender, ClickedArgs args) | |
{ | |
if (EnsureCameraInitialized()) | |
camera.Show(); | |
} | |
void OnPictureTaken(object sender, PictureTakenArgs args) | |
{ | |
debug_log "A picture was taken"; | |
var imageSource = new Fuse.Resources.TextureImageSource(); | |
imageSource.Texture = args.Picture; | |
Photo.Source = imageSource; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment