Actionscript: Blur everything except one object - actionscript-3

I am using the following to blur an object
var blur:BlurFilter = new BlurFilter();
blur.blurX = 10;
blur.blurY = 10;
blur.quality = BitmapFilterQuality.MEDIUM;
obj.filters = [blur];
I then moved to
root.filters = [blur];
Which blurs everything, but I want to not blur one object, so everything underneath it is blurred.
Can this be done.
I tried
obj.filters = [];
To turn it off on one object but course this did not work.

Related

Prevent ColorTransform from changing other filter colors (AS3)

I am trying to change the color of a movieclip when clicked, however I have a shadow filter on it that I want to stay black.
var cty:ColorTransform = new ColorTransform();
cty.color = 0xFFFF00; //color transform yellow
var shdw:DropShadowFilter = new DropShadowFilter();
shdw.color = 0x000000; <----clearly set to black
shdw.distance = 3;
shdw.angle = 45;
shdw.strength = 1;
shdw.blurX = 3;
shdw.blurY = 3;
thisclip.filters=[shdw];
thisclip.addEventListener(MouseEvent.CLICK,myevent);
function myevent(e:MouseEvent):void
{
thisclip.transform.colorTransform = cty;
thisclip.filters=[shdw]; <------ tried adding a refresher but doesnt work
}
The problem is that after the color change the shadow is changed to the same color as the object, is there a way to change the color WITHOUT changing the shadow filter color???
The problem is that after the color change the shadow is changed to
the same color as the object, is there a way to change the color
WITHOUT changing the shadow filter color???
You need to separate the item you want to be drop-shadowed and the item you want to colour transformed. One way is to create a "container" for thisclip and apply the shadow to the container itself, then only transform the colour of this clip. I've modified your code to show what I mean...
var cty:ColorTransform = new ColorTransform();
cty.color = 0xFFFF00; //# yellow
var shdw:DropShadowFilter = new DropShadowFilter();
shdw.color = 0x000000; //# black
shdw.strength = 1;
shdw.distance = 3; shdw.angle = 45;
shdw.blurX = shdw.blurY = 3; //# linked since same value for both
var contMC : MovieClip = new MovieClip;
addChild( contMC ); //# add to stage
contMC.addChild( thisclip ); //# add "thisclip" into container MC
contMC.x = 0; contMC.y = 0; //# set your own position
//thisclip.filters=[shdw];
contMC.filters=[shdw];
thisclip.addEventListener(MouseEvent.CLICK, myevent);
function myevent(e:MouseEvent):void
{
thisclip.transform.colorTransform = cty;
//e.currentTarget.transform.colorTransform = cty; //# use this for ANY listening object
}
Just remember if you create the container MC by code (like I showed) you can reference any added children by their usual instance names like so : thisclip.transform.colorTransform = cty;
But if you create the container MC on stage (with instance name contMC and cut/paste thisclip MC into it, then you now reference it by code as : contMC.thisclip.transform.colorTransform = cty;
tip #1 : To avoid adding a container, if your thisclip itself has an MC (or Sprite) holding some "to be coloured" content you can instead target that content by its instance name :
thisclip.someContent.transform.colorTransform = cty;
(here thisclip becomes the container with shadow, whilst someContent is the inner MC to be colour transformed).
tip #2 : I've added the line e.currentTarget.transform.colorTransform = cty; (but is commented out since not used) to show how you could have any clicked MC respond to the colour transform. Just make sure they are listening to the event like so :
clipInstanceName.addEventListener(MouseEvent.CLICK, myevent);
(now you can have multiple IF checks and adjust colour accordingly per clicked item using cty.color = some new Value; within if statements, before finally setting that .colorTransform = cty; ...

My ByteArray isn't retaining filters

I have an RTMP stream that I need to take a screenshot of. I got a security error using bitmapData.draw() since it was coming from AWS S3 so I found a workaround that allows me to take a screenshot of the video:
var bitmap = new Bitmap();
var graphicsData : Vector.<IGraphicsData>;
graphicsData = container.graphics.readGraphicsData(); //-- container is a sprite that holds my video element
bitmap.bitmapData = GraphicsBitmapFill(graphicsData[0]).bitmapData;
var image:ByteArray = new JPGEncoder(85).encode(bitmap.bitmapData);
At this point, I send the ByteArray to PHP, create a JPG out of the ByteArray and save it to the server. That all works great.
The issue is I apply filters realtime to the container sprite which alters the look of the video like brightness, contrast, saturation etc, but when saving to the server, the saved image doesn't contain the filters I had applied.
I tried reapplying the filters to bitmap, graphicsData and bitmap.bitmapData, but nothing worked.
How can I either retain the filters applied or reapply the filters to the above code?
EDIT
Here is how I initially apply the filters:
private function applyEffects(effects:Array):void
{
currentEffects = effects;
var props:Object = {};
for (var i:String in effects)
{
props[effects[i].effect] = effects[i].amount;
}
TweenLite.to(container,0,{colorMatrixFilter:props});
}
props object could look something like: {contrast:0.5,saturation:1}
Ok, I have solved this on my own with a little suggestion Jack Doyle (GSAP Author) gave me. I have described what I did differently in the comments of my code:
var graphicsData:Vector.<IGraphicsData>;
graphicsData = container.graphics.readGraphicsData();
var origBitmap:Bitmap = new Bitmap();
origBitmap.bitmapData = GraphicsBitmapFill(graphicsData[0]).bitmapData;
//-- at this point I have a screenshot of the video
var props:Object = {};
for (var i:String in currentEffects)
{
props[currentEffects[i].effect] = currentEffects[i].amount;
}
TweenLite.to(origBitmap,0,{colorMatrixFilter:props});
//-- at this point I've reapplied the effects.
//-- originally, sending bitmap.bitmapData to the encoder didn't retain the filters so I went 1 step further
//-- create a new bitmapData and draw the reapplied filter'd bitmap
var filteredBitmapData:BitmapData = new BitmapData(640,360);
var filteredBitmap:Bitmap = new Bitmap(filteredBitmapData);
filteredBitmapData.draw(origBitmap);
//-- encode the new bitmap data
var image:ByteArray = new JPGEncoder(85).encode(filteredBitmapData); //-- filteredBitmapData is now filtered and I can send this to the server

Blending objects with eachother but not with background actionscript 3

I have a number of objects (represented as DisplayObjects) that i wish to blend with eachother.
However behind these objects there is a background that i do not want to involve in the blending.
So basically i want to blend these objects with eachother and afterwards use the result of this blending as a new DisplayObject (for example to put it on top of a randomly colored background).
So what i have is:
var obj1:DisplayObject = getFirstObj();
var obj2:DisplayObject = getSecObj();
var background:DisplayObject = getBackground();
obj1.blendMode = BlendMode.ADD;
obj2.blendMode = BlendMode.ADD;
A first attempt i tried was putting these objects into a common DisplayObjectContainer hoping that blending mode would only be relative to all objects contained by the same DisplayObjectContainer, but this does not seem to be the case.
var objectsPool:Sprite = new Sprite();
objectsPool.addChild( obj1 );
objectsPool.addChild( obj2 );
addChild( background );
addchild( objectsPool );
So that diddent get me anywhere.
Any help is appreciated.
EDIT: changed DisplayObjectContainer to Sprite in the last code snippet
If you put the objects into a container, and remove it from the stage, you can then draw it with the BitmapData class and create a new Bitmap object representing the combination. This will have a transparent background, and it's blendMode will be normal, allowing you to use it on the background.
var obj1:DisplayObject = getFirstObj();
var obj2:DisplayObject = getSecObj();
var background:DisplayObject = getBackground();
obj1.blendMode = BlendMode.ADD;
obj2.blendMode = BlendMode.ADD;
var objectsPool:DisplayObjectContainer = new DisplayObjectContainer();
objectsPool.addChild( obj1 );
objectsPool.addChild( obj2 );
var bmd:BitmapData = new BitmapData(objectsPool.width,objectsPool.height,true,0);
bmd.draw(objectsPool);
var drawnObject:Bitmap = new Bitmap(bmd);
addChild( background );
addchild( drawnObject );
(untested code, good luck)
Rather going to the effort of drawing a Bitmap yourself, there are options that cause Flash to rasterize a layer and it's children automatically. Try:
container.cacheAsBitmap = true;
or try:
container.blendMode = "layer";
or try:
container.filters = [new GlowFilter(0,0,0,0)];
Any of those options should cause the children to render into a Bitmap under the hood, invalidating their individual blend modes/effects on the background.

Best way of attaching bitmaps from library with a linkagename (currently trying with - getDefinitionByName(tempName) as Class)

I basically have 5 images in library, which I've given af linkage name as so:
head_image0, head_image1, head_image2 etc...
On Stage I have two containers which I will be loading my images into.
- pictureContainer1_mc
- pictureContainer2_mc
Pr default I have already loaded an image into container1.
What will happen is that, when I click menu button2, then head_image2 will load into container2 and fade up from alpha 0 -> alpha 1 - giving a transition between the two images.
After the image has alpha'ed into container2, then I run a function to swap containers, so that container1 will hold the image currently loaded and container2 will be ready to load another picture upon menu button click.
This looks like the following:
//Function receiving an ID from the button click, which we can use to load the connected image
function headerFadeIn(receivedNumber:Number):void
{
//Getting container2 rdy to tween from 0 -> 1
pictureContainer2_mc.alpha = 0;
//Preparing image string - linkagename
var tempName:String = "header_image" + receivedNumber;
//Loading the image into container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
pictureContainer2_mc.addChild(headImage);
//Tweening currecntly added image from 0 -> 1
//When tween is done call function onFinishTween to swap containers
TweenLite.to(pictureContainer2_mc,1,{alpha:1, ease:menuEasing, onComplete:onFinishTween});
function onFinishTween():void
{
//Setting currently loaded image in container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
pictureContainer1_mc.addChild(headImage);
pictureContainer2_mc.alpha = 0;
}
}
This works for me. HOWEVER I'm experiencing some "lagging" issue. When I've clicked back and forward menu buttons to change images like 15 times, then the tweening begins to "lag" and wont happen in a smooth transition.
Any calls on this?
Could I do this in a smarter way?
I would suggest to create images only once, and reuse them. Also, after the tween, i would remove the old image and save it for the next time you need that image. Also, when you swap the image from container 2 into container 1, don't create a new one, just move the image from one container to the other.
Something like this, code is not tested, just to give you an idea.
var instances:Object = {};
var currentImage:String;
//Function receiving an ID from the button click, which we can use to load the connected image
function headerFadeIn(receivedNumber:Number):void
{
//Getting container2 rdy to tween from 0 -> 1
pictureContainer2_mc.alpha = 0;
//Preparing image string - linkagename
currentImage = "header_image" + receivedNumber;
var headImage:Bitmap = _getImage(currentImage);
pictureContainer2_mc.addChild(headImage);
//Tweening currecntly added image from 0 -> 1
//When tween is done call function onFinishTween to swap containers
TweenLite.to(pictureContainer2_mc,1,{alpha:1, ease:menuEasing, onComplete:onFinishTween});
function onFinishTween():void
{
//Setting currently loaded image in container 1
//cast returned DisplayObject into a Bitmap.
var headImage:Bitmap = pictureConainer2_mc.getChildByName(currentImage) as Bitmap;
pictureContainer1_mc.addChild(headImage);
pictureContainer2_mc.alpha = 0;
}
}
function _getImage(id:String):Bitmap{
if( instances[id] ) return instances[id];
//Loading the image into container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
instances[id] = headImage;
return headImage;
}

Unloading a Loader with actionscript 3

Hello and thank you very much for looking at this. I've spent too many hours struggling.
The code below loads a slideshow of four images, along with thumbnails for those images. It works fine.
I've added a button called "invis_button", that when pressed is supposed to remove the 3 loaders that make up the slideshow, using the removeChild command for each loader.
But this is the problem, there are 3 loaders involved in the slide-show. The removeChild command successfully removes one of the loaders (named "loader3"), but not the other two ("container3", and "thumbLoader3"). It returns an error stating "access of undefined property thumbLoader3" or "Container3".
Can someone tell me why this is ? Or better still, how to make that button (invis_button) unload the entire slide-show.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
var thumbLoader3:Loader;
var container3:Sprite = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
thumbLoader3 = new Loader();
thumbLoader3.load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3.x = thumbX3;
thumbLoader3.y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3);
thumbLoader3.addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
removeChild(loader3);
removeChild(thumbLoader3);
removeChild(container3);
}
Not sure if this is the entire reason behind what you're observing... but for starters, "thumbloader3" and "container3" are scoped locally to the loadThumbs3() method, which means once you finish executing the function, Flash's handles to those objects are lost (not to mention being in an entirely different scope)... try creating class-level properties for those two. Once that's done you should be able to successfully remove them from the stage later on.
I hope that you're also properly destroying your objects, and for the sake of brevity you just chose to omit that code above.
I've edited the code you had above & put the properties into the proper scope. (the multiple copies of thumbLoader3 are now collected inside of a vector (specialized array) so that they can be properly addressed when it comes time to destroy them)
I also wrote you a proper destroy method. ;)
I haven't tried it on my own machine, but give it a spin & see how it goes.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
// begin new instance properties..
// created a new property, allowing you to group (and hold on to) the multiple thumbLoaders
var thumbLoader3Vector:Vector.<Loader> = new Vector.<Loader>();
var container3:Sprite;
// end new instance properties
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
// this is where container3 used to be declared
container3 = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
var tPtr:int = thumbLoader3Vector.length;
thumbLoader3Vector.push(new Loader());
// this is where thumbLoader3 used to be declared & instantiated
thumbLoader3Vector[tPtr].load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3Vector[tPtr].x = thumbX3;
thumbLoader3Vector[tPtr].y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3Vector[tPtr]);
thumbLoader3Vector[tPtr].addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
// since the thumbLoader3 Loaders are children of container3 in the display list, we need to remove them first
for(var $i:uint = 0;$i<thumbLoader3Vector.length;$i++)
{
removeChild(thumbLoader3Vector[$i]);
// also make sure you remove the listener, so that the object will be picked up by garbage collection
thumbLoader3Vector[$i].removeEventListener(MouseEvent.CLICK, thumbClicked3);
}
// and then just set the entire vector to null
thumbLoader3Vector = null;
// remove the loader3 object & set it to null
removeChild(loader3);
loader3 = null;
// remove the container3 object & set it to null
removeChild(container3);
container3 = null;
}