ActionScript3 - Drawing video(webcam) output on BitmapData with shifted position - actionscript-3

I'm trying to draw a video(webcam) output on a Bitmapdata, it works if the position of the video is at (0,0) but when I shift the video to (200,0), the drawn output also shifted.
The code is pretty simple
// omitted for brevity
var videoContainer:Sprite = new Sprite();
// Video is added
videoContainer.addChild(video)
// position is offsetted
videoContainer.x = 200;
videoContainer.y = 200;
this.addChild(videoContainer)
// Generate Bitmap
var bd:BitmapData = new BitmapData(video.width, video.height, false, 0x0);
bd.x = video.x;
bd.y = video.y + video.height;
this.addChild(bd);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void {
// start drawing
bd.lock()
bd.draw(video);
bd.unlock();
}
I've tried to reposition it with a matrix, but apparently the entire original source had changed.
Is there a way to ensure that the output remains at (0,0) even if the videoContainer were offsetted from (0,0)?

First of all, it looks like you have a type in your code:
var bd:Bitmap = new BitmapData(video.width, video.height, false, 0x0);
It should throw an error, because an instance of BitmapData couldn't be assigned to a variable with the type Bitmap. But, I guess, it's just a type.
Secondly, it looks like your bitmap is shifted, because you shift it =)
bd.x = video.x;
I would advice to remove/comment this code.
Upd:
Also, please, could you try the next method for getting a BitmapData instance of the DisplayObject with applied transform changes:
function getBitmapDataFromDisplayObject(
displayObject:DisplayObject,
transparent:Boolean = true,
fillColor:uint = 0x00000000,
smoothing:Boolean = true,
customRect:Rectangle = null):BitmapData
{
var bitmapData:BitmapData;
try
{
var tempRect:Rectangle = displayObject.getRect(displayObject);
if (customRect)
{
tempRect = customRect;
}
var matrix:Matrix = new Matrix();
matrix.tx = -tempRect.x;
matrix.ty = -tempRect.y;
//bitmapData = new BitmapData(tempRect.right, tempRect.bottom, transparent, fillColor);
bitmapData = new BitmapData(tempRect.width, tempRect.height, transparent, fillColor);
bitmapData.draw(displayObject, matrix, null, null, null, smoothing);
}catch (error:Error)
{
bitmapData = null;
}
return bitmapData
}

Related

How to get index of a Bitmap Image from bitmapdata(from an Array)?

I am wondering if i have an Array that push content that is Bitmap, how do i get index of a specific image when clicked. I tried to use indexOf but no luck, my codes are below.
Thanks for your time!
Code:
//First Part is where i add the URLRequest and add the image into contentHolder then onto Stage
function loadImage():void {
for(var i:int = 5; i < somedata.length; i++){
if(somedata[i]){
var loader:Loader = new Loader();
loader.load(new URLRequest("http://www.rentaid.info/rent/"+somedata[i]));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
}
}
}
function onImageLoaded(e:Event):void {
loadedArray.push(e.target.content as Bitmap);
for(var i:int = 0; i < loadedArray.length; i++){
var currentY1:int = 200;
e.currentTarget.loader.content.height =200;
e.currentTarget.loader.content.y += currentY1;
currentY1 += e.currentTarget.loader.content.height +300;
_contentHolder.mouseChildren = false; // ignore children mouseEvents
_contentHolder.mouseEnabled = true; // enable mouse on the object - normally set to true by default
_contentHolder.useHandCursor = true; // add hand cursor on mouse over
_contentHolder.buttonMode = true;
_contentHolder.addChild(loadedArray[i]);
addChild(_contentHolder);
_contentHolder.addEventListener(MouseEvent.CLICK, gotoscene);
}
}
// then the part where i try to get the index
function gotoscene(e:MouseEvent):void {
var index:Number;
index = loadedArray.indexOf(e.target);
trace(index);
}
Edit:
var viewport:Viewport = new Viewport();
viewport.y = 0;
viewport.addChild(_contentHolder);
Your first question has very simple answer:
var image:Bitmap = new Bitmap();
var images:Array = new Array(image);
for (var i:uint = 0; i < images.length; i++) {
// images[i].bitmapData is the original image in your array
// image.bitmapData is searched one
if (images[i].bitmapData == image.bitmapData) {
// found
}
}
But your problem is bigger than this. I see you keep wandering around..
You should add listener to each child, not the content holder as one. I usually don't use Loaders, but get their Bitmaps and wrap them in Sprites or something, that I add into the scene. You should store either this Sprite or your Loader into that array, not the Bitmap. Then add listener to each of them (Sprite or Loader, not Bitmap) and get the target. Depending on what you've stored in the array, you can easily get it as:
function gotoscene(e:MouseEvent):void {
var index:uint = loadedArray(indexOf(e.target));
}
But it's important to store one specific type that will actually be clickable. Don't think about the Bitmap - it's only a graphic representation, and doesn't do much in the code.
**EDIT:
Okay I'm adding the code you need but it's important to understand what you are doing and not just rely on someone else's answer :)
function onImageLoaded(e:Event):void {
var bitmap:Bitmap = e.target.content as Bitmap; // get the Bitmap
var image:Sprite = new Sprite();
image.addChild(bitmap); // wrap it inside new Sprite
// add listener to Sprite!
image.addEventListener(MouseEvent.CLICK, gotoscene);
// gets url of current image (http://website.com/images/image1.jpg)
var url:String = e.target.loaderURL;
// get only the number from that url by replacing or by some other way
// this removes the first part and results in "1.jpg"
var name:String = url.replace("http://website.com/images/image", "");
// this removes the extension and results in number only - 1, 2, 3
// it's important to change this depending on your naming convention
name = name.replace(".jpg", "");
image.name = "button" + name; // results in "button1", "button2", "button3"
// store object, name, or whatever (not really needed in your case, but commonly used)
loadedArray.push(image.name);
image.x = counter * 100; // position so you can see them, at 100, 200, 300, etc.
_contentHolder.addChild(image); // add newly created Sprite to content
}
function gotoscene(e:MouseEvent):void {
var name:String = e.target.name;
// strips down "button" from "button1", and only the number remains,
// which is 1, 2, 3, etc. the number of the scene :)
var scene:uint = name.replace("button", "");
// you're the man now :)
}

Converting a Shape to a Bitmap

I have created a subclass of Shape that contains paired GraphicsPath and GraphicsStroke objects. The class has a public method for retrieving the shape as a bitmap for passage to a Pixelbender kernel - the method is as follows:
public function GetBitmap():Bitmap{
var bmpData:BitmapData = new BitmapData(this.width, this.height, true, 0x00FFFFFF);
bmpData.draw(this);
return new Bitmap(bmpData);
}
To test these, I have the following code:
var v:Vector.<Number> = new <Number>[10,10,50,10,50,50]; //defines GraphicsPath.data to be used
var wave:CustomWave = new CustomWave(v,0xff0000); //constructor for the subclass
wave.Refresh(); //clears the Shape and redraws the GraphicsPath
//adds as shape
addChild(wave);
//adds as bitmap
var bmp:Bitmap = wave.GetBitmap()
addChild(bmp);
The visual output from both:
Any idea what could be causing the difference?
It's a long story, how to work with width and height, if you don't want any problems, draw your path from (0,0) or you can modify your function:
public function GetBitmap():Bitmap {
var bounds: Rectangle = getBounds(this);
var bmpData:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
bmpData.draw(this, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));
return new Bitmap(bmpData);
}
It may have something to do with the registration point of the Shape you're drawing into the Bitmap. Any chance you draw stuff above or to the left of the 0,0 coordinates? Then you'd have to add some params (perhaps a transformation Matrix) to the draw call, to get the right offset and such.

How do you add stroke to text in a GPU rendered Mobile app? [duplicate]

Unfortunately the filters do not work (drop shadow, glow) in GPU mode. I'm looking for an opportunity to use these effects to text in this mode. I will welcome any advice.
As Astraport mentions, you'll need to draw the textfield out to a bitmapData every time you update the text using bitmapData.draw().
If you use textField.getBounds to determine the size of the bitmapData you need, the resulting bounds rectangle will not include the extra size due to the filter (e.g. a DropShadowFilter sticks out the side of the textbox by certain pixels depending on the 'distance' and 'blur'). To ensure that you include the filters when you draw the bitmap, you'll also need to use bitmapData.generateFilterRect() to get the correct size rect.
Code snippet (untested, but general idea):
// Remember the transform matrix of the text field
var offset : Matrix = myTextField.transform.matrix.clone();
// Get the bounds of just the textfield (does not include filters)
var tfBounds : Rectangle = myTextField.getBounds( myTextField.parent );
// Create a bitmapData that is used just to calculate the size of the filters
var tempBD : BitmpaData = new BitmapData( Math.ceil(tfBounds.width), Math.ceil(tfBounds.height) );
// Make a copy of the textField bounds. We'll adjust this with the filters
var finalBounds : rectangle = tfBounds.clone();
// Step through each filter in the textField and adjust our bounds to include them all
var filterBounds : rectangle;
for each (var filter : BitmapFilter in myTextField.filters) {
filterBounds = tempBD.generateFilterRect( tfBounds, filter );
finalBounds.left = Math.min( finalBounds.left, filterBounds.left );
finalBounds.right = Math.max( finalBounds.right, filterBounds.right );
finalBounds.top = Math.min( finalBounds.top, filterBounds.top );
finalBounds.bottom = Math.max( finalBounds.bottom, filterBounds.bottom );
}
// Now draw the textfield to a new bitmpaData
var textFieldBD : BitmpaData = new BitmapData( Math.ceil(finalBounds.width), math.ceil(finalBounds.height) );
offset.tx = -finalBounds.x;
offset.ty = -finalBounds.y;
textFieldBD.draw( myTextField.parent, offset, myTextField.transform.colorTransform );
// Create a bitmap and add the bitmap data. Note: normally you would create a
// bitmap once and just update the bitmpaData
var bitmap : Bitmap = new Bitmap();
myTextField.parent.addChild( bitmap );
// Position the bitmap in same place as textField
bitmap.bitmapData = textFieldBD;
bitmap.x = myTextField.x - finalBounds.x;
bitmap.y = myTextField.y - finalBounds.y;
myTextField.visible = false;
Here is how to convert ANY DisplayObject to a Bitmap - useful for "restoring" filter effects in AIR GPU mobile rendermode. This is Pixelthis's solution, fixed, optimized and tested:
// => 'bitmap' must belong to the same parent as 'obj'. 'obj' should be invisible.
static public function Update(obj:DisplayObject, bitmap:Bitmap):void {
//trace("CacheToBmp",obj.name);
// Remember the transform matrix of the text field
var offset:Matrix = obj.transform.matrix.clone();
// Get the bounds of just the textfield (does not include filters)
var bounds:Rectangle = obj.getBounds(obj);
// Create a bitmapData that is used just to calculate the size of the filters
var tempBD:BitmapData = new BitmapData( Math.ceil(bounds.width), Math.ceil(bounds.height), false );
bounds.width = obj.width;
bounds.height = obj.height;
// Make a copy of the textField bounds. We'll adjust this with the filters
var finalBounds:Rectangle = new Rectangle(0,0,bounds.width,bounds.height);
// Step through each filter in the textField and adjust our bounds to include them all
var filterBounds:Rectangle;
for each (var filter:BitmapFilter in obj.filters) {
filterBounds = tempBD.generateFilterRect( tempBD.rect, filter );
finalBounds = finalBounds.union(filterBounds);
}
finalBounds.offset(bounds.x,bounds.y);
finalBounds.x = Math.floor(finalBounds.x);
finalBounds.y = Math.floor(finalBounds.y);
finalBounds.width = Math.ceil(finalBounds.width);
finalBounds.height = Math.ceil(finalBounds.height);
// Now draw the textfield to a new bitmpaData
var data:BitmapData = new BitmapData( finalBounds.width, finalBounds.height, false, 0 );
offset.tx = -finalBounds.x;
offset.ty = -finalBounds.y;
data.drawWithQuality( obj, offset, obj.transform.colorTransform, obj.blendMode, null, true, StageQuality.HIGH );
bitmap.bitmapData = data;
// Position the bitmap in same place as 'obj'
bitmap.x = obj.transform.matrix.tx + finalBounds.x;
bitmap.y = obj.transform.matrix.ty + finalBounds.y;
}
The basic idea is to apply the filters as normal and then draw the display object to a bitmapdata and add the bitmap to the stage. See http://forums.adobe.com/message/3934192 for an example.
If the text that you are applying this to is static it should be easy enough to do, but if you want to apply this dynamic text (for example, a score counter that will change frequently, or text that is user-editable) I imagine it may start to get annoying, but I don't know of any other solution.

AS3 return dropped object to initial location

I am using codes from http://hub.tutsplus.com/tutorials/create-a-drag-and-drop-puzzle-in-actionscript-30--active-2920 to make a drag and drop decoration game. I am trying to make it so that when the dropped object is dragged out of target location (which is an outline of the shape in my case), it goes back to initial location... basically reversing the drag and drop. I've been messing around with really random codes and so far this line is the closest to what I want but I don't think the code is right and also it doesnt return to initial location, it just goes to the side of the stage.
so, I added the else if line to stopDragObject which got the object to be removed from target location, but it randomly goes to the side of the stage, and not initial location:
private function stopDragObject(evt:MouseEvent):void {
if (evt.target.hitTestObject(getChildByName(evt.target.name + "Target"))) {
evt.target.x = getChildByName(evt.target.name + "Target").x;
evt.target.y = getChildByName(evt.target.name + "Target").y;
} else if (evt.target.x = null) {
evt.target.x = xPos;
evt.target.y = yPos;
}
evt.target.stopDrag();
}
Solved
after reading the lesson from below, I ended up with this and it works perfectly! (not exactly the way like the lesson but at least it works...)
private function stopDragObject(evt:MouseEvent):void {
if (evt.target.hitTestObject(getChildByName(evt.target.name + "Target"))) {
evt.target.x = getChildByName(evt.target.name + "Target").x;
evt.target.y = getChildByName(evt.target.name + "Target").y;
} else {
evt.target.x = getChildByName(evt.target.name + "Int").x;
evt.target.y = getChildByName(evt.target.name + "Int").y;
}
evt.target.stopDrag();
}
I added a initial object so the object could only be either at target or initial :)
I will try to teach neither provide code.
Lets draw two rectangles:
var s1:Sprite = new Sprite()
var s2:Sprite = new Sprite()
with (s1)
{
graphics.beginFill(0xfcaaaa, .7)
graphics.drawRect(0, 0, 400, 400)
graphics.endFill()
}
with (s2)
{
graphics.beginFill(0x00aaaa, .7)
graphics.drawRect(0, 0, 30, 30)
graphics.endFill()
}
addChild(s1)
addChild(s2)
Is't that simple? You see that s1 is much bigger than s2 (dimentions: 400, 400 vs 30, 30 ) Now place s2 to the center of our big s1:
s2.x = 200;
s2.y = 200;
We will use s1 for the boundaries of s2 movings.
This code is a simplest solution for dragging our s2 rectangle (Sprite):
s2.addEventListener(MouseEvent.MOUSE_DOWN, onDown)
s2.addEventListener(MouseEvent.MOUSE_UP, onUp)
function onDown(e:MouseEvent):void
{
(e.currentTarget as Sprite).startDrag();
}
function onUp(e:MouseEvent):void
{
(e.currentTarget as Sprite).stopDrag();
}
Now, the basic solution for returning our Sprite to the starting position: hitTestObject will return true, if Sprite s2 is still located in the area of Sprite s1. More helpful functions here. Lets check it. Change onUp function this way:
function onUp(e:MouseEvent):void
{
var s:Sprite = (e.currentTarget as Sprite);
s.stopDrag();
if (!s.hitTestObject(s1))
{
s.x = 200;
s.y = 200;
}
}
You see that now s2 gets returned to the starting position if it gets dragged out from the area of s1.
Now the main part:
What to do, if you can't predict the starting position of the object? Now, when we know how to deal with already known coordinates, this is the challange. I assume that there are several implementations of this functionality exist. One of the best way is to set additional parameters e.g. startingX and startingY for the dragging object when starting drag. E.g. in our example when onDown function gets called. I guess you dealing with Sprites or MovieClips and don't have the ability to do this.
Lets go another way and use Dictionary object. Dictionary is some kind of traditional Hash Map with the ability to use objects as keys.
Hash map is kind of storage, where you can put any value mapped by a key, provided by you. In actionscript 3 we have Object as a limited implementation of Hash Map. Why use it? In two words because it's simple and fast. But with Object we can't use other Objects as keys, only strings ints numbers etc..
var sites:Object = new Object();
sites['stackoverflow'] = "http://stackoverflow.com/"
trace(sites.stackoverflow) // outputs-> http://stackoverflow.com/
With Dictionary we can use Objects as keys.
Lets create it:
var startCoordinates:Dictionary = new Dictionary();
To save coordinates, we need x and y property.
FYI: new Object() is equivalent of {}
var capitals:Object = new Object();
capitals['Italy'] = 'Rome';
is equivalent of
var capitals:Object = {Italy: 'Rome'};
To save current position we will use this code:
var s:Sprite = (e.currentTarget as Sprite);
startCoordinates[s] = { x: s.x, y: s.y };
And the whole code in our example will look like this:
var s1:Sprite = new Sprite()
var s2:Sprite = new Sprite()
addChild(s1)
addChild(s2)
with (s1)
{
graphics.beginFill(0xfcaaaa, .7)
graphics.drawRect(0, 0, 400, 400)
graphics.endFill()
}
with (s2)
{
graphics.beginFill(0x00aaaa, .7)
graphics.drawRect(0, 0, 30, 30)
graphics.endFill()
}
s2.x = 200;
s2.y = 200;
s2.addEventListener(MouseEvent.MOUSE_DOWN, onDown)
s2.addEventListener(MouseEvent.MOUSE_UP, onUp)
var startCoordinates:Dictionary = new Dictionary()
function onDown(e:MouseEvent):void
{
var s:Sprite = (e.currentTarget as Sprite);
startCoordinates[s] = { x: s.x, y: s.y };
s.startDrag();
}
function onUp(e:MouseEvent):void
{
var s:Sprite = (e.currentTarget as Sprite);
s.stopDrag();
if (!s.hitTestObject(s1))
{
s.x = startCoordinates[s].x;
s.y = startCoordinates[s].y;
}
delete startCoordinates[s];
}

Comparing bitmap is not working

I am trying to compare the bitmap 1 to bitmap 2 and if they equal to 0 I want them to do something. so for sake of seeing what it's returning I added a trace. but it seems like it's tracing out something totally different from what I expected. This is the code:
var scratch_c : Scratch_card = new Scratch_card ();
var backgr: Background = new Background ();
var mouseclick:Number;
var masking:Sprite = new Sprite()
var bmd1:BitmapData = new BitmapData(742, 165);
var bm:Bitmap = new Bitmap(bmd1);
addChild (bm);
bm.x=20;
bm.y=40;
bmd1.draw(scratch_c);
var bmd2:BitmapData = new BitmapData(742, 165);
var bm2:Bitmap = new Bitmap(bmd2);
addChild (bm2);
bm2.x=20;
bm2.y=40;
bmd2.draw(backgr);
bm2.mask = masking;
addChild(masking);
stage.addEventListener(MouseEvent.MOUSE_DOWN, Pressing);
stage.addEventListener(MouseEvent.MOUSE_MOVE, Moving);
stage.addEventListener(MouseEvent.MOUSE_UP, Lifting);
function Pressing(event:MouseEvent):void {
mouseclick = 1;
}
function Moving(event:MouseEvent):void {
if (mouseclick == 1) {
masking.graphics.beginFill(0x000000);
masking.graphics.drawEllipse(mouseX, mouseY, 70, 60);
masking.graphics.endFill();
}
}
function Lifting(event:MouseEvent):void {
trace(bmd1.compare(bmd2));
mouseclick = 0;
}
This is what it is tracing out
How can I make it compare the pixels of bmd1 and bmd2?
Why is it not returning a number?
Not a percentage but it should return a new BitMapData object that you could assign as an image.
BitMapData.compare( )
Returns Object — If the two BitmapData objects have the same dimensions (width and height), the method returns a new BitmapData object that has the difference between the two objects (see the main discussion). If the BitmapData objects are equivalent, the method returns the number 0. If the widths of the BitmapData objects are not equal, the method returns the number -3. If the heights of the BitmapData objects are not equal, the method returns the number -4.
Taken from here
Result:
Your bitmaps are not equivalent, thats why you get an object made of 2 different bitmaps.
Have you tried
if(bmd1.compare(bmd2) == bmd2){
// complete
}
However after looking at your code a little more. i think you need to test on the masking not bmd1
So something like this.
var mymask:BitmapData = new BitmapData(742, 165, true,0x000000000);
mymask.draw(masking);
if(mymask.compare(bmd2) == bmd2){
// complete
}
untested code but should put you on the right path