Skip to content

Instantly share code, notes, and snippets.

@biochimia
Last active September 3, 2015 20:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save biochimia/74e16bdf8f57cf5ba3de to your computer and use it in GitHub Desktop.
Save biochimia/74e16bdf8f57cf5ba3de to your computer and use it in GitHub Desktop.
Fuse App to Take Pictures
<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>
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;
}
}
<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>
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);
}
}
}
<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>
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