Save original bitmapData from scaled video in AS3 - actionscript-3

I have a flash photo booth (web cam) application that I'm trying to wrap up but seem to be having issues trying to save a 640x480 image from a scaled down video window. The video seems to be scaling down fine but when I draw it to a bitmap it's shrinking the photo even more so I had to create a matrix scale of 2.0 to resize it back to 640x480 and I'm not sure if doing so is hurting the quality of the image. I don't want to use any resize hacks (especially up-scaling).
I'm new to AS3 so please forgive me.
import flash.display.Bitmap;
import flash.display.BitmapData;
import com.adobe.images.JPGEncoder;
var cam:Camera = Camera.getCamera();
cam.setQuality(0, 100);
cam.setMode(640,480,30,true); // setMode(videoWidth, videoHeight, video fps, favor area)
var video:Video = new Video();
video.attachCamera(cam);
video.x = 382;
video.y = 225;
video.width = 256;
video.height = 192;
addChild(video);
var bitmapData:BitmapData = new BitmapData(640,480);
var bitmap:Bitmap = new Bitmap(bitmapData);
bitmap.x = 648;
bitmap.y = 225;
bitmap.width = 256;
bitmap.height = 192;
addChildAt(bitmap, 18);
photoCapture.buttonMode = true;
photoCapture.addEventListener(MouseEvent.CLICK,captureImage);
here is the dirty part...
function captureImage(e:MouseEvent):void {
var scale:Number=2.0;
var matrix:Matrix = new Matrix();
matrix.scale(scale, scale);
bitmapData.draw(video, matrix, null, null, null, true);
var jpgEncoder:JPGEncoder=new JPGEncoder(100);
var byteArray:ByteArray=jpgEncoder.encode(bitmapData);
var fileReference:FileReference=new FileReference();
fileReference.save(byteArray, ".jpg");
}
Basically I just want two small box's about 256x192 showing the video stream (640x480) and captured photo (640x480) and when I save it actually saves a 640x480 image.

var video:Video = new Video(640, 480);
This should prevent having to use a matrix. Video by default is 320x240.

First you create a video 256x192
then you create a bitmapData 640x480
then you shrink this bitmapdata (well, the bitmap actually) to 256x192
then you try to draw a small video into a large bitmap(data) - no wonder that you have to upscale
Create a BitmapData, Bitmap and Video in the same size and everything should be OK.
If you want the final image to be 640x480 you should create video, bitmap, bitmapdata in this size, then add the video to an empty MovieClip/Sprite (container) and scale container in order to fit it on the screen.

private var cam:Camera;
private var myVideo:Video;
private function attachCamera():void
{
cam = Camera.getCamera();
cam.setMode(8192,6144,30,true);
cam.setQuality(0,100);
myVideo = new Video(160,120);
//Flip preview on camera and result!
var flip:Matrix = new Matrix();
flip.scale(-1,1)
flip.translate(myVideo.width,0)
myVideo.transform.matrix = flip;
myVideo.attachCamera(cam);
videoDisplay.addChild(myVideo);
}
private function takePicture():void
{
var bd:BitmapData = new BitmapData(cam.width,cam.height);
//fill db with source bitmap!!!
cam.drawToBitmapData(bd)
//Then the bd contains the highest possible camera source!
// But videoDisplay show's small preview!
}

Related

Actionscript 3.0 - tracing the path of a moving body ;

I'm learning AS3.0 currently. I am trying to design a simple two body planet simulation. I need to show the paths of the planets on the screen. So my question is, once I have the updated x and y coordinates for the planets at each Timer interval, how do I change the color of the pixel (x,y) of the stage so that it shows the path of the planets? Is there some command of the form stage.x = color?
Thanks!
I recommend using BitmapData's draw() method to render your planets as pixels each time you update them. It basically works like a 'screenshot' of the display object you pass it as n argument. If you pass the objects transformation, the position/rotation/scale will be visible (as opposed to drawing from 0,0). This way, you will only be updating pixels instead of continuously creating new display objects.
Here's a basic commented example:
import flash.display.Sprite;
import flash.events.Event;
var trails:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list
var dot:Sprite = addChild(new Sprite()) as Sprite;
dot.graphics.lineStyle(3);
dot.graphics.drawCircle(-4, -4, 8);
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
dot.x = mouseX;
dot.y = mouseY;
//draw trails of the dot
trails.draw(dot,dot.transform.concatenatedMatrix,trailsFade);//draw the dot into the bitmap data using the dot's transformation (x,y, rotation, scale)
}
Notice the trails when you move the mouse and how they are affected by the (update) speed.
Here's a longer example using multiple objects:
import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var trails:BitmapData = new BitmapData(w,h,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,0.1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var mercuryPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var venusPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var mercury:Sprite = mercuryPivot.addChild(getCircleSprite(24.40 / 4,0xCECECE)) as Sprite;
var venus:Sprite = venusPivot.addChild(getCircleSprite(60.52 / 4,0xFF2200)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
mercury.x = 5791 / 40;
venus.x = 10820 / 40;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
mercuryPivot.rotation += 0.5;
venusPivot.rotation += 0.25;
earthPivot.rotation += 0.12;
//draw trails
trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
Notice we call trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);
but it could be trails.draw(earth,earth.transform.concatenatedMatrix,trailsFade); if you only want to draw the trails of earth.
In the example above I'm just nesting sprites and using the rotation property to keep things simple. You might want to use a bit of trigonometry to update positions because planets will probably not have perfectly circular orbits and pass through the exact location every single time.
Update
Thinking about this more, using the old school Graphics API might be handy for you if you get started and haven't got used to playing with pixels yet.
It's easy to get started with: objects that can be displayed in flash player can have a graphics property (see the Shape/Sprite/MovieClip classes). (You can have display object that you can't draw into whether you can nest elements into (DisplayObjectContainer) or not(DisplayObject), but that's a whole other thing for you too look into).
This graphics property Sprites and MovieClip has allows you to draw programmatically using simply commands such as: setting a stroke(lineStyle()), a fill (beginFill()/endFill()), moving an imaginary 'pen' without drawing (moveTo), drawing a line (lineTo), a circle, a rectangle, a rounded rectangle, etc. It's all there.
So, a minimal drawing program would look a bit like this:
import flash.events.MouseEvent;
import flash.events.Event;
var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously
function mouseEventHandler(e:MouseEvent):void{
mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY);//place the graphics 'pen' at this new location
}
function update(e:Event):void{
if(mousePressed) graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location
}
or a more complex version where you use the speed of the mouse movement to influence the stroke thickness and transparency:
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;
var prevPos:Point = new Point();//previous mouse position
var currPos:Point = new Point();//current mouse position
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))
stage.doubleClickEnabled = true;
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(MouseEvent.DOUBLE_CLICK,function(e:MouseEvent):void{graphics.clear()});//double click to clear
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously
function mouseEventHandler(e:MouseEvent):void{
mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY);
}
function update(e:Event):void{
//currPos.setTo(mouseX,mouseY);//this works for flash player 11 and above instead of setting x,y separately
currPos.x = mouseX;
currPos.y = mouseY;
var mappedValue: Number = Point.distance(currPos,prevPos) / (w+h);//map the distance between points
//prevPos.copyFrom(currPos);//this works for flash player 11 and above instead of setting x,y separately
prevPos.x = mouseX;
prevPos.y = mouseY;
graphics.lineStyle(mappedValue * 100,0,1.0-(0.25+mappedValue));
if(mousePressed) graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location
}
So going back to the tracing of a planet path, using the graphics api, my previous example would look like so:
import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Point;
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var hasMoved:Boolean = false;//has the graphics 'pen' been moved ?
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
earthPivot.rotation += 0.12;
//draw trails
drawTrail(earth,0x0000FF);
}
function drawTrail(s:Sprite,color:int) {
var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
if(!hasMoved){//if the graphics 'pen' wasn't moved (is still at 0,0), this will happen only once: the 1st time you draw the mouse position
graphics.moveTo(globalPos.x,globalPos.y);//move it to where we're about to draw first
hasMoved = true;//and make sure we've marked that the above was done
}
graphics.lineStyle(1,color);
graphics.lineTo(globalPos.x,globalPos.y);
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
From my experience, using this older drawing API can get slow if you have a lot of lines on stage. I say older because it might actually be 15 years old now. Flash Player 10 introduced a newer drawing API. You can read on it on the Adobe Devnet but I warmly recommend Senocular's Flash Player 10 Drawing API Tutorial and his slides and example code from Flash Camp
Back to pixels: it's not that hard. You use the BitmapData class to manipulate pixels and use a Bitmap instance so you can add those pixels on stage. Here's a minimal drawing program:
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
canvas.setPixel(int(mouseX),int(mouseY),0x990000);//pretty easy, right ?
}
want to make trippy patterns, sure thing, have a play:
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
canvas.lock();//when updating multiple pixels or making multiple pixel operations
canvas.perlinNoise(mouseX,mouseY,mouseX/stage.stageWidth * 8,getTimer(),false,true);
canvas.unlock();//when you're done changing pixels, commit the changes
}
So, back to the trails example:
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var canvas:BitmapData = new BitmapData(w,h,false,0xFFFFFF);
addChild(new Bitmap(canvas));
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
earthPivot.rotation += 0.12;
//draw trails
drawTrail(earth,0x0000FF,canvas);
}
function drawTrail(s:Sprite,color:int,image:BitmapData) {
var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
image.setPixel(int(globalPos.x),int(globalPos.y),color);//colour a pixel at a set position
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
Which looks like this:
Not sure if it's what you want though, but pixels are fun to use and pretty fast too.
With a bit of math you can do some minimal 3D as well.
Also, for your inspiration on drawing in actionscript, you can have a look at some of Keith Peters', Erik Natzke, Joshua Davis, etc.
No, there isn't such a command, but you can always create a very simple Sprite object and add it to the stage at the corresponding position. Something like:
var dot:Sprite = new Sprite();
dot.graphics.beginFill(0xCCCCCC);
dot.graphics.drawRect(-1, -1, 2, 2);
dot.graphics.endFill();
dot.x = x;
dot.y = y;
addChild(dot);

AS3 BitmapData Percentage Comparison

I'm working on a game with a lawn mower that orients itself to the mouse and colours white over a grass Bitmap to give the illusion of a mower cutting (erasing) grass.
I want to create a function that checks the percentage of grass cut, which basically means checking how much white is currently drawn into the grass image.
How would I go about doing this? Is there an easy way?
Here is my current code:
import flash.display.BitmapData;
import flash.events.Event;
var bitmapData = new grass();
var bitmap = new Bitmap(bitmapData);
var mower = new Mower();
var radiance:Number = 180/Math.PI;
var erase:Sprite=new Sprite();
erase.cacheAsBitmap = true;
bitmap.y=0;
bitmap.x=0;
addChild(bitmap);
addChild(erase);
addChild(mower);
this.addEventListener(Event.ENTER_FRAME, function(e:Event):void
{
erase.graphics.beginFill(0xFFFFFF);
erase.graphics.drawCircle(mower.x,mower.y,25);
erase.graphics.endFill();
var mowerdirection = - (Math.atan2(mouseX-mower.x, mouseY-mower.y))*radiance;
mower.rotation = mowerdirection;
followMower();
var myTestingBitmapData:BitmapData = new BitmapData(bitmapData.width, bitmapData.height, true, 0x00000000);
trace( myTestingBitmapData.compare( bitmap.bitmapData) )
});
erase.addEventListener(MouseEvent.CLICK, function(e:Event):void
{
trace('click');
});
function followMower():void
{
var dx:int = mower.x - mouseX;
var dy:int = mower.y - mouseY;
mower.x -= dx / 10;
mower.y -= dy /10;
}
You can try to use image analysing frameworks or some methods to count colour in an image. There is build in function called histogram that may help you, you can also use solution of this post or under this link

MovieClip disappear after changing width and height in AS3

I am trying to load an image from an url in as3, as follows:
var myImageLoader:Loader = new Loader();
private var mcImage: MovieClip = new MovieClip();
var myImageLocation:URLRequest = new URLRequest("http://example.com/xyz.jpg");
myImageLoader.load(myImageLocation);
mcImage.addChild(myImageLoader);
mcImage.x = 100;
mcImage.y = 100;
//mcImage.width = 50;
//mcImage.height = 50;
addChild(mcImage);
The code above works fine, but since my desire image has a different size comparing to the original image, changing its size is necessary here. So after using the lines, which are commented in the code above, the mcImage disappear.
I tried to use mcImage.scaleX =myImageLoader.width/50 , but since myImageLoader is not loaded at the beginning, we cannot get the width of myImageLoader which is null.
It's the often error with setting sizes, you can't set size of empty display object (object that width and height are zero). To set size of display object you need first to draw something on it's graphics (for example 1*1 px rectangle), but you should understand that after it you will just scale your display object relatively to it's original size, for example if you draw 1*1 px rectangle and set with=height=50, scaleX and scaleY for it will be 50, so your loaded image if we say about loader will be giant size :) It's all about sizing in flash.
What about your task: there is one common rule - don't resize loader, resize loaded image. As I said above resizing of loader will only scale your image rather than set it sizes. Add complete handler and resize loader.content as you want.
Example:
public function astest()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplte);
addChild(loader);
loader.load(new URLRequest("https://www.google.ru/images/srpr/logo3w.png"));
}
protected function onComplte(event:Event):void
{
EventDispatcher(event.target).removeEventListener(event.type, arguments.callee);
var image:DisplayObject = (event.target as LoaderInfo).content;
image.width = 50;
image.height = 50;
}
You need to get loadComplete event on your loader before playing with your MC
var myImageLoader:Loader = new Loader();
private var mcImage: MovieClip = new MovieClip();
var myImageLocation:URLRequest = new URLRequest("http://example.com/xyz.jpg");
myImageLoader.addEventListener(Event.COMPLETE, completeHandler);
myImageLoader.load(myImageLocation);
function completeHandler(e:Event){
mcImage.x = 100;
mcImage.y = 100;
mcImage.width = 50;
mcImage.height = 50;
addChild(mcImage);
mcImage.addChild(myImageLoader);
}
try this:
var myImageLoader:Loader = new Loader();
//hide until loaded
myImageLoader.visible = false;
//listen for load completed
myImageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
//...rest of your code (without setting width/height)
Then add this to resize and make visible when loaded:
function completeHandler(event:Event):void
{
myImageLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
myImageLoader.content.width = 50;
myImageLoader.content.height = 50;
myImageLoader.visible = true;
}

Three.js does not show texture on sphere

There are some threads about textures which do not showing up. I have tried them all, but nothing helped.
I have spent a few hours on this now. Every time I end up looking at a black sphere.
I am working on Chrome v18 and Windows 7. I also tried Firefox, but this browser does not really support Three.js.
This is the body of the script:
<body>
<script src="../build/Three.js"></script>
<script src="js/Stats.js"></script>
<script src="../build/jquery-1.7.2.min.js"></script>
This is the script itself:
// stap1) camera, set the scene size
var WIDTH = 400,
HEIGHT = 300;
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR );
// stap2) scene:
var scene = new THREE.Scene();
// the camera starts at 0,0,0 so pull it back
scene.add(camera);
camera.position.z = +300;
// get the DOM element to attach to
// - assume we've got jQuery to hand
var container = $('#container');
// stap3)create a WebGL renderer:
var renderer = new THREE.WebGLRenderer();
// start the renderer
renderer.setSize(WIDTH, HEIGHT);
// attach the render-supplied DOM element
container.append(renderer.domElement);
// bol maken:
// create the sphere's material
// b.v: THREE.MeshBasicMaterial
var sphereMaterial = new THREE.MeshLambertMaterial(
{
map: THREE.ImageUtils.loadTexture("http://dev.root.nl/tree/examples/textures/ash_uvgrid01.jpg")
});
// set up the sphere vars
var radius = 50, segments = 16, rings = 16;
var sphereGeometry = new THREE.SphereGeometry(radius, segments, rings);
// create a new mesh with sphere geometry -
var sphere = new THREE.Mesh(
sphereGeometry,
sphereMaterial
);
sphere.position.x=0;
var s=1;
sphere.scale.set(s, s, s);
// add the sphere to the scene
scene.add(sphere);
// create a point light
var pointLight = new THREE.PointLight( 0xFFFFFF );
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
// draw!
renderer.render(scene, camera);
You need to wait until the image used as texture is fully downloaded.
I have put your code on the web: http://jsfiddle.net/4Qg7K/ and just added a classic "render loop":
requestAnimationFrame(render);
function render(){
requestAnimationFrame(render);
sphere.rotation.y += 0.005; //rotation stuff, just for fun
renderer.render(scene, camera);
};
requestAnimationFrame function works like a timer, calling to the render function each time the browser is ready to update the web page.
BTW, Three.js works fine with Firefox.

AS3 webcam resolution/size issue

I do not really know much in regard to Flash or Action Scripts but I have been having a bit of trouble with AS3 and webcams. I have a script that connects to a webcam and then sends its output to a php script that saves the captured image. This works all except for one problem. It seems that the maximum resolution allowed for the actual Camera object is 320x240. I went to the extreme of hooking a Canon 60D up as a webcam because I have a normal webcam that is supposed to have max resolution of 1280x720 and all I can get is a 320x240 image from it. What I have found so far is the max I can get out of the Canon is also 320x240. Maybe I have been looking at this to long but I am stumped. Below is a sample of the action script where videoCapture should be 1024x768. What happens instead is a 1024x768 image is created with a black background and in the top left is a 320x240 image from videoCapture. I could obviously resize this but that would defeat the purpose being poor quality. Is there something I am missing here or maybe some limitation of Flash even?
// adds event listener to the stage for keydown events.
stage.addEventListener(KeyboardEvent.KEY_DOWN, detectEnterKey);
import flash.display.Bitmap;
import flash.display.BitmapData;
import com.adobe.images.JPGEncoder;
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
var bandwidth:int = 0;
var quality:int = 100;
var cam:Camera = Camera.getCamera();
var videoCapture:Video = new Video();
var previewPortData:BitmapData = new BitmapData(1024, 768, true, 0x00000000);
var previewPort:Bitmap = new Bitmap(previewPortData);
function onCameraStatus(evt):void {
if (evt.code == "Camera.Muted") {
Security.showSettings(SecurityPanel.CAMERA);
}
}
// detects the keycode looking for enter key pressed.
function detectEnterKey(event:KeyboardEvent):void {
//trace("keycode: "+event.keyCode);
if (event.keyCode == Keyboard.ENTER) {
previewPortData.draw(videoCapture);
var myEncoder:JPGEncoder = new JPGEncoder(100);
var byteArray:ByteArray = myEncoder.encode(previewPortData);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var saveJPG:URLRequest = new URLRequest("save.php");
saveJPG.requestHeaders.push(header);
saveJPG.method = URLRequestMethod.POST;
saveJPG.data = byteArray;
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, sendComplete);
urlLoader.load(saveJPG);
function sendComplete(event:Event):void {
trace("compete");
}
}
}
if (cam == null) {
Security.showSettings(SecurityPanel.CAMERA);
} else {
cam.addEventListener(StatusEvent.STATUS, onCameraStatus)
cam.setQuality(bandwidth, quality);
cam.setMode(1024, 768, 30, false);
videoCapture.attachCamera(cam);
videoCapture.width = 1024;
videoCapture.height = 768;
addChild(videoCapture);
previewPort.x = 430;
previewPort.y = 50;
addChild(previewPort);
}
I also just had this problem. Solved it by including the width and height parameters when creating the Video object instead of setting them afterwards via Video.height and Video.width. Once i did that, all bitmapData taken from that video was correctly sized.
This is how i originally created the video that did not work (looked fine, but resulted in incorrectly sized bitmaps):
var vid = new Video();
vid.width = 640;
vid.height = 480;
...
This worked (bitmaps from this video were correctly sized):
var vid = new Video(640, 480);
...
Would love to know why the first way doesn't work. Maybe that's the bug mentioned above. (I didn't have access to that site so couldn't see it.)
Sounds like this bug was never fixed: http://bugs.adobe.com/jira/browse/FP-2138
I had a similar issue. What worked for me was that I replaced:
previewPortData.draw(videoCapture);
With:
previewPortData.draw(stage);