make AS Camera actually take a picture. Needs better UI at some point
Project: http://git-wip-us.apache.org/repos/asf/flex-asjs/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-asjs/commit/b83027c6 Tree: http://git-wip-us.apache.org/repos/asf/flex-asjs/tree/b83027c6 Diff: http://git-wip-us.apache.org/repos/asf/flex-asjs/diff/b83027c6 Branch: refs/heads/develop Commit: b83027c65bbf7387792d29e63fb580602d783fe7 Parents: 135f04d Author: Alex Harui <aha...@apache.org> Authored: Tue May 6 00:12:22 2014 -0700 Committer: Alex Harui <aha...@apache.org> Committed: Tue May 6 00:12:22 2014 -0700 ---------------------------------------------------------------------- frameworks/as/projects/FlexJSUI/build.xml | 2 +- .../as/projects/FlexJSUI/compile-config.xml | 2 +- .../src/org/apache/cordova/camera/Camera.as | 95 +++++- .../src/org/apache/flex/utils/PNGEncoder.as | 304 +++++++++++++++++++ .../flex/utils/ViewSourceContextMenuOption.as | 2 +- 5 files changed, 395 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/b83027c6/frameworks/as/projects/FlexJSUI/build.xml ---------------------------------------------------------------------- diff --git a/frameworks/as/projects/FlexJSUI/build.xml b/frameworks/as/projects/FlexJSUI/build.xml index 514b42d..3dfe5d8 100644 --- a/frameworks/as/projects/FlexJSUI/build.xml +++ b/frameworks/as/projects/FlexJSUI/build.xml @@ -72,7 +72,7 @@ <jvmarg line="${compc.jvm.args}"/> <load-config filename="compile-config.xml" /> <arg value="+playerglobal.version=${playerglobal.version}" /> - <arg value="+env.PLAYERGLOBAL_HOME=${env.PLAYERGLOBAL_HOME}" /> + <arg value="+env.AIR_HOME=${env.AIR_HOME}" /> </compc> </target> http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/b83027c6/frameworks/as/projects/FlexJSUI/compile-config.xml ---------------------------------------------------------------------- diff --git a/frameworks/as/projects/FlexJSUI/compile-config.xml b/frameworks/as/projects/FlexJSUI/compile-config.xml index a72ad58..7db518e 100644 --- a/frameworks/as/projects/FlexJSUI/compile-config.xml +++ b/frameworks/as/projects/FlexJSUI/compile-config.xml @@ -22,7 +22,7 @@ <accessible>false</accessible> <external-library-path> - <path-element>${env.PLAYERGLOBAL_HOME}/${playerglobal.version}/playerglobal.swc</path-element> + <path-element>${env.AIR_HOME}/frameworks/libs/air/airglobal.swc</path-element> </external-library-path> <locale/> http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/b83027c6/frameworks/as/projects/FlexJSUI/src/org/apache/cordova/camera/Camera.as ---------------------------------------------------------------------- diff --git a/frameworks/as/projects/FlexJSUI/src/org/apache/cordova/camera/Camera.as b/frameworks/as/projects/FlexJSUI/src/org/apache/cordova/camera/Camera.as index 9a8a980..3984b44 100644 --- a/frameworks/as/projects/FlexJSUI/src/org/apache/cordova/camera/Camera.as +++ b/frameworks/as/projects/FlexJSUI/src/org/apache/cordova/camera/Camera.as @@ -18,6 +18,25 @@ //////////////////////////////////////////////////////////////////////////////// package org.apache.cordova.camera { + import flash.display.BitmapData; + import flash.display.DisplayObject; + import flash.display.DisplayObjectContainer; + import flash.display.Sprite; + import flash.events.ActivityEvent; + import flash.events.KeyboardEvent; + import flash.events.MouseEvent; + import flash.filesystem.File; + import flash.filesystem.FileMode; + import flash.filesystem.FileStream; + import flash.geom.Rectangle; + import flash.media.Camera; + import flash.media.Video; + import flash.ui.Keyboard; + import flash.utils.ByteArray; + + import org.apache.flex.utils.PNGEncoder; + + [Mixin] public class Camera { public static var DestinationType:Object = { @@ -48,13 +67,20 @@ package org.apache.cordova.camera FRONT : 1 // Use the front-facing camera }; + private static var root:DisplayObjectContainer; + + public static function init(r:DisplayObjectContainer):void + { + root = r; + } + public function Camera() { - pictureSourceType = Camera.PictureSourceType.PHOTOLIBRARY; - destinationType = Camera.DestinationType.DATA_URL; - mediaType = Camera.MediaType.PICTURE; - encodingType = Camera.EncodingType.JPEG; - direction = Camera.Direction.BACK; + pictureSourceType = org.apache.cordova.camera.Camera.PictureSourceType.PHOTOLIBRARY; + destinationType = org.apache.cordova.camera.Camera.DestinationType.DATA_URL; + mediaType = org.apache.cordova.camera.Camera.MediaType.PICTURE; + encodingType = org.apache.cordova.camera.Camera.EncodingType.JPEG; + direction = org.apache.cordova.camera.Camera.Direction.BACK; } public var pictureSourceType:int; @@ -63,14 +89,69 @@ package org.apache.cordova.camera public var encodingType:int; public var direction:int; + private var cameraSuccess:Function; + private var cameraError:Function; + private var ui:Sprite; + private var camera:flash.media.Camera; + public function getPicture( cameraSuccess:Function, cameraError:Function, cameraOptions:Object ) : void { - // stub for JavaScript version + this.cameraSuccess = cameraSuccess; + this.cameraError = cameraError; + + camera = flash.media.Camera.getCamera(); + + if (camera != null) { + ui = new Sprite(); + var video:Video = new Video(camera.width * 2, camera.height * 2); + video.attachCamera(camera); + ui.addChild(video); + root.addChild(ui); + ui.addEventListener(MouseEvent.CLICK, mouseClickHandler); + ui.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); + } else { + trace("You need a camera."); + } + } + + private function mouseClickHandler(event:MouseEvent):void + { + savePicture(); + root.removeChild(ui); + } + + private function keyDownHandler(event:KeyboardEvent):void + { + if (event.keyCode == Keyboard.ESCAPE) + root.removeChild(ui); + else if (event.keyCode == Keyboard.ENTER || event.keyCode == Keyboard.SPACE) + { + savePicture(); + root.removeChild(ui); + } + } + + private function savePicture():void + { + var f:File = File.createTempFile(); + var bd:BitmapData = new BitmapData(camera.width, camera.height, false); + var pix:ByteArray = new ByteArray(); + var rect:Rectangle = new Rectangle(0, 0, camera.width, camera.height); + camera.copyToByteArray(rect, pix); + pix.position = 0; + bd.setPixels(rect, pix); + var png:PNGEncoder = new PNGEncoder(); + var ba:ByteArray = png.encode(bd); + var fs:FileStream = new FileStream(); + fs.open(f, FileMode.WRITE); + fs.writeBytes(ba); + fs.close(); + cameraSuccess(f.url); } public function cleanup( cameraSuccess:Function, cameraError:Function ) : void { - // stub for JavaScript version + // no cleanup required in Flash } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/b83027c6/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/PNGEncoder.as ---------------------------------------------------------------------- diff --git a/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/PNGEncoder.as b/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/PNGEncoder.as new file mode 100644 index 0000000..bd1fce4 --- /dev/null +++ b/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/PNGEncoder.as @@ -0,0 +1,304 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package org.apache.flex.utils +{ + +import flash.display.BitmapData; +import flash.utils.ByteArray; + +/** + * The PNGEncoder class converts raw bitmap images into encoded + * images using Portable Network Graphics (PNG) lossless compression. + * + * <p>For the PNG specification, see http://www.w3.org/TR/PNG/</p>. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class PNGEncoder +{ + + // this is a copy of mx.graphics.codec.PNGEncoder + + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + /** + * @private + * The MIME type for a PNG image. + */ + private static const CONTENT_TYPE:String = "image/png"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function PNGEncoder() + { + super(); + + initializeCRCTable(); + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Used for computing the cyclic redundancy checksum + * at the end of each chunk. + */ + private var crcTable:Array; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // contentType + //---------------------------------- + + /** + * The MIME type for the PNG encoded image. + * The value is <code>"image/png"</code>. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get contentType():String + { + return CONTENT_TYPE; + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * Converts the pixels of a BitmapData object + * to a PNG-encoded ByteArray object. + * + * @param bitmapData The input BitmapData object. + * + * @return Returns a ByteArray object containing PNG-encoded image data. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function encode(bitmapData:BitmapData):ByteArray + { + return internalEncode(bitmapData, bitmapData.width, bitmapData.height, + bitmapData.transparent); + } + + /** + * Converts a ByteArray object containing raw pixels + * in 32-bit ARGB (Alpha, Red, Green, Blue) format + * to a new PNG-encoded ByteArray object. + * The original ByteArray is left unchanged. + * + * @param byteArray The input ByteArray object containing raw pixels. + * This ByteArray should contain + * <code>4 * width * height</code> bytes. + * Each pixel is represented by 4 bytes, in the order ARGB. + * The first four bytes represent the top-left pixel of the image. + * The next four bytes represent the pixel to its right, etc. + * Each row follows the previous one without any padding. + * + * @param width The width of the input image, in pixels. + * + * @param height The height of the input image, in pixels. + * + * @param transparent If <code>false</code>, alpha channel information + * is ignored but you still must represent each pixel + * as four bytes in ARGB format. + * + * @return Returns a ByteArray object containing PNG-encoded image data. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function encodeByteArray(byteArray:ByteArray, width:int, height:int, + transparent:Boolean = true):ByteArray + { + return internalEncode(byteArray, width, height, transparent); + } + + /** + * @private + */ + private function initializeCRCTable():void + { + crcTable = []; + + for (var n:uint = 0; n < 256; n++) + { + var c:uint = n; + for (var k:uint = 0; k < 8; k++) + { + if (c & 1) + c = uint(uint(0xedb88320) ^ uint(c >>> 1)); + else + c = uint(c >>> 1); + } + crcTable[n] = c; + } + } + + /** + * @private + */ + private function internalEncode(source:Object, width:int, height:int, + transparent:Boolean = true):ByteArray + { + // The source is either a BitmapData or a ByteArray. + var sourceBitmapData:BitmapData = source as BitmapData; + var sourceByteArray:ByteArray = source as ByteArray; + + if (sourceByteArray) + sourceByteArray.position = 0; + + // Create output byte array + var png:ByteArray = new ByteArray(); + + // Write PNG signature + png.writeUnsignedInt(0x89504E47); + png.writeUnsignedInt(0x0D0A1A0A); + + // Build IHDR chunk + var IHDR:ByteArray = new ByteArray(); + IHDR.writeInt(width); + IHDR.writeInt(height); + IHDR.writeByte(8); // bit depth per channel + IHDR.writeByte(6); // color type: RGBA + IHDR.writeByte(0); // compression method + IHDR.writeByte(0); // filter method + IHDR.writeByte(0); // interlace method + writeChunk(png, 0x49484452, IHDR); + + // Build IDAT chunk + var IDAT:ByteArray = new ByteArray(); + for (var y:int = 0; y < height; y++) + { + IDAT.writeByte(0); // no filter + + var x:int; + var pixel:uint; + + if (!transparent) + { + for (x = 0; x < width; x++) + { + if (sourceBitmapData) + pixel = sourceBitmapData.getPixel(x, y); + else + pixel = sourceByteArray.readUnsignedInt(); + + IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | 0xFF)); + } + } + else + { + for (x = 0; x < width; x++) + { + if (sourceBitmapData) + pixel = sourceBitmapData.getPixel32(x, y); + else + pixel = sourceByteArray.readUnsignedInt(); + + IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | + (pixel >>> 24))); + } + } + } + IDAT.compress(); + writeChunk(png, 0x49444154, IDAT); + + // Build IEND chunk + writeChunk(png, 0x49454E44, null); + + // return PNG + png.position = 0; + return png; + } + + /** + * @private + */ + private function writeChunk(png:ByteArray, type:uint, data:ByteArray):void + { + // Write length of data. + var len:uint = 0; + if (data) + len = data.length; + png.writeUnsignedInt(len); + + // Write chunk type. + var typePos:uint = png.position; + png.writeUnsignedInt(type); + + // Write data. + if (data) + png.writeBytes(data); + + // Write CRC of chunk type and data. + var crcPos:uint = png.position; + png.position = typePos; + var crc:uint = 0xFFFFFFFF; + for (var i:uint = typePos; i < crcPos; i++) + { + crc = uint(crcTable[(crc ^ png.readUnsignedByte()) & uint(0xFF)] ^ + uint(crc >>> 8)); + } + crc = uint(crc ^ uint(0xFFFFFFFF)); + png.position = crcPos; + png.writeUnsignedInt(crc); + } +} + +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/b83027c6/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/ViewSourceContextMenuOption.as ---------------------------------------------------------------------- diff --git a/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/ViewSourceContextMenuOption.as b/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/ViewSourceContextMenuOption.as index 5dc0a3b..23a1324 100644 --- a/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/ViewSourceContextMenuOption.as +++ b/frameworks/as/projects/FlexJSUI/src/org/apache/flex/utils/ViewSourceContextMenuOption.as @@ -69,7 +69,7 @@ public class ViewSourceContextMenuOption implements IBead _strand = value; var menuHost:InteractiveObject = InteractiveObject(value); - var cm:ContextMenu = menuHost.contextMenu; + var cm:ContextMenu = ContextMenu(menuHost.contextMenu); if (!cm) { cm = new ContextMenu();