-
-
Save marchbold/0075bbf8ccf46ac76668 to your computer and use it in GitHub Desktop.
/** | |
* __ __ __ | |
* ____/ /_ ____/ /______ _ ___ / /_ | |
* / __ / / ___/ __/ ___/ / __ `/ __/ | |
* / /_/ / (__ ) / / / / / /_/ / / | |
* \__,_/_/____/_/ /_/ /_/\__, /_/ | |
* / / | |
* \/ | |
* http://distriqt.com | |
* | |
* @file VideoCameraUI.as | |
* @brief A Basic Starling Camera UI using the distriqt Camera ANE | |
* @author "Michael Archbold (ma@distriqt.com)" | |
* @created 30/03/2015 | |
* @copyright http://distriqt.com/copyright/license.txt | |
*/ | |
package com.distriqt.camera.starling | |
{ | |
import com.distriqt.extension.camera.Camera; | |
import com.distriqt.extension.camera.CameraMode; | |
import com.distriqt.extension.camera.CameraParameters; | |
import com.distriqt.extension.camera.CaptureDevice; | |
import com.distriqt.extension.camera.events.CameraEvent; | |
import flash.desktop.NativeApplication; | |
import flash.display.BitmapData; | |
import flash.display3D.textures.Texture; | |
import flash.events.Event; | |
import flash.geom.Matrix; | |
import flash.geom.Rectangle; | |
import flash.utils.ByteArray; | |
import starling.display.Image; | |
import starling.display.Sprite; | |
import starling.events.Event; | |
import starling.textures.Texture; | |
/** | |
* @author "Michael Archbold (ma@distriqt.com)" | |
*/ | |
public class VideoCameraUI extends Sprite | |
{ | |
/** | |
* Constructor | |
*/ | |
public function VideoCameraUI() | |
{ | |
super(); | |
addEventListener( starling.events.Event.ADDED_TO_STAGE, addedToStageHandler ); | |
} | |
//////////////////////////////////////////////////////// | |
// VARIABLES | |
// | |
private var _options : CameraParameters | |
private var _device : CaptureDevice; | |
private var _container : Sprite; | |
private var _preview : Image; | |
private var _previewTexture : starling.textures.Texture; | |
private var _previewData : ByteArray; | |
private var _previewBitmapData : BitmapData; | |
private var _previewBitmapRect : Rectangle; | |
private var _lastFrameProcessed : Number = -1; | |
//////////////////////////////////////////////////////// | |
// FUNCTIONALITY | |
// | |
//////////////////////////////////////////////////////// | |
// INTERNALS | |
// | |
private function initialiseExtension():void | |
{ | |
try | |
{ | |
Camera.init( Config.APP_KEY ); | |
if (Camera.isSupported) | |
{ | |
var devices:Array = Camera.instance.getAvailableDevices(); | |
for each (var device:CaptureDevice in devices) | |
{ | |
if (device.position == CaptureDevice.POSITION_FRONT) | |
{ | |
_device = device; | |
break; | |
} | |
} | |
_options = new CameraParameters(); | |
_options.enableFrameBuffer = true; | |
_options.cameraMode = new CameraMode( CameraMode.PRESET_HIGH ); | |
_options.deviceId = _device.id; | |
_options.frameBufferWidth = 1280; | |
_options.frameBufferHeight = 720; | |
Camera.instance.addEventListener( CameraEvent.VIDEO_FRAME, camera_videoFrameHandler ); | |
Camera.instance.initialise( _options ); | |
Camera.instance.setFocusMode( CameraParameters.FOCUS_MODE_CONTINUOUS ); | |
} | |
} | |
catch (e:Error) | |
{ | |
trace( e ); | |
} | |
} | |
private function releaseExtension():void | |
{ | |
try | |
{ | |
Camera.instance.removeEventListener( CameraEvent.VIDEO_FRAME, camera_videoFrameHandler ); | |
Camera.instance.release(); | |
Camera.instance.dispose(); | |
} | |
catch (e:Error) | |
{ | |
trace( e ); | |
} | |
} | |
private function DEG2RAD( degrees:Number ):Number | |
{ | |
return degrees * Math.PI / 180; | |
} | |
//////////////////////////////////////////////////////// | |
// EVENT HANDLERS | |
// | |
private function addedToStageHandler( event:starling.events.Event ):void | |
{ | |
_previewData = new ByteArray(); | |
_previewBitmapData = new BitmapData( 1, 1, false ); | |
_previewBitmapRect = new Rectangle(0,0,1,1); | |
_previewTexture = starling.textures.Texture.fromBitmapData( _previewBitmapData ); | |
_preview = new Image( _previewTexture ); | |
addChild( _preview ); | |
initialiseExtension(); | |
NativeApplication.nativeApplication.addEventListener( flash.events.Event.DEACTIVATE, deactivateHandler ); | |
NativeApplication.nativeApplication.addEventListener( flash.events.Event.ACTIVATE, activateHandler ); | |
} | |
private function deactivateHandler( event:flash.events.Event ):void | |
{ | |
releaseExtension(); | |
} | |
private function activateHandler( event:flash.events.Event ):void | |
{ | |
initialiseExtension(); | |
} | |
private function camera_videoFrameHandler( event:CameraEvent ):void | |
{ | |
var frame:Number = Camera.instance.receivedFrames; | |
if (frame != _lastFrameProcessed) | |
{ | |
if (-1 != Camera.instance.getFrameBuffer( _previewData )) | |
{ | |
try | |
{ | |
// | |
// Check we have an appropriately sized bitmapdata and texture | |
// Recreate if not | |
if (_previewBitmapData.width != Camera.instance.width || _previewBitmapData.height != Camera.instance.height) | |
{ | |
trace( "resizing to: (" + Camera.instance.width +", "+ Camera.instance.height +")" ); | |
_previewBitmapData.dispose(); | |
_previewTexture.dispose(); | |
_previewBitmapData = new BitmapData( Camera.instance.width, Camera.instance.height, false ); | |
_previewTexture = starling.textures.Texture.fromBitmapData( _previewBitmapData ); | |
_preview.texture = _previewTexture; | |
_preview.readjustSize(); | |
_previewBitmapRect = new Rectangle( 0, 0, _previewBitmapData.width, _previewBitmapData.height ); | |
var s:Number = 1.0; | |
var t:Matrix = new Matrix(); | |
if (_device.orientation == 90 || _device.orientation == 270) | |
{ | |
s = stage.stageWidth / _previewTexture.height; | |
t.translate( - _previewTexture.width * 0.5, - _previewTexture.height * 0.5 ); | |
t.rotate( DEG2RAD(_device.orientation) ); | |
t.scale( s, s ); | |
t.translate( _previewTexture.height * s * 0.5, _previewTexture.width * s * 0.5 ); | |
} | |
else | |
{ | |
s = stage.stageWidth / _previewTexture.width; | |
t.translate( - _previewTexture.width * 0.5, - _previewTexture.height * 0.5 ); | |
t.rotate( DEG2RAD(_device.orientation) ); | |
t.scale( s, s ); | |
t.translate( _previewTexture.width * s * 0.5, _previewTexture.height * s * 0.5 ); | |
} | |
// Something weird happens here with large bitmaps and it turns white? If you comment out this line it works but isn't rotated... | |
_preview.transformationMatrix = t; | |
} | |
// | |
// Update the bitmapdata and texture | |
_previewBitmapData.setPixels( _previewBitmapRect, _previewData ); | |
flash.display3D.textures.Texture(_previewTexture.base).uploadFromBitmapData( _previewBitmapData ); | |
} | |
catch (e:Error) | |
{ | |
trace( e ); | |
} | |
finally | |
{ | |
_previewData.clear(); | |
_lastFrameProcessed = frame; | |
} | |
} | |
} | |
} | |
} | |
} | |
// com.distriqt.Camera |
Hi,
You can't just change the rect to setPixels as it's related to the data in the byte array. Instead you should create a second bitmapdata of your target size and copy the region from the preview BitmapData :
var croppedBitmapData:BitmapData = new BitmapData( cropWidth, cropHeight );
croppedBitmapData.copyPixels(
_previewBitmapData,
new Rectangle(startPointX, startPointY, cropWidth, cropHeight), new Point(0, 0)
);
Just make sure that the cropped region is contained with in the size of the preview bitmap data.
Thanks marhbold.
By the way, I changed the order of matrices applied to translate, rotate, translate again then scale. This way it's now properly fitting on to the image.
t.translate( - _previewTexture.width * 0.5, - _previewTexture.height * 0.5 );
t.rotate( DEG2RAD(_device.orientation) );
t.translate( _previewTexture.height * s * 0.5, _previewTexture.width * s * 0.5 );
t.scale( s, s );
Please post your support questions in the github repository, we don't get notifications or follow these gists.
Great code, thaks very much!
To fix the White problem just need to set the generateMipMap false during the texture creation at line 197.
_previewTexture = starling.textures.Texture.fromBitmapData( _previewBitmapData, false );
I am also saving and applying the transformation matrix on a new bitmap data to return it as it looks.
var bd:BitmapData = new BitmapData(_preview.width, _preview.height, false, 0);
bd.draw(_previewBitmapData, _rotateMatrix);
This example works fine but I think it needs better documentation.
Is there any way to fit the bitmapdata into a square sized area? If not, is there a way to capture the image with square dimensions like 640x640? Changing the size of _previewBitmapRect didn't do the trick.
Thanks.