How to distort images (or FXG) in Flex? - apache-flex

I want to distort images (or FXGs) in Flex.
Basically just want to modify the edges of an image like the image below. I know how to make simple distortions but I can't find a way of doing that.

The answers were right... what you need is a DisplacementMapFilter!!
The displacementImage should be grey in general -> means no distortion, and add a white and a gray radial gradient to each lower and upper edgelike this:
And with the Map you go like this:
package {
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
import flash.net.URLRequest;
public class DistortImage extends Sprite
{
private var sourceImage:Loader;
private var distortMap:Loader;
public function DistortImage()
{
super();
// Loading the Image to be distorted
sourceImage = new Loader();
var requ: URLRequest = new URLRequest("text.jpg");
sourceImage.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMap);
sourceImage.load(requ);
}
private function loadMap( E:Event = null ):void{
// loading distortion map ( grayscale )
distortMap = new Loader();
var requ: URLRequest = new URLRequest("distortMap.jpg");
distortMap.contentLoaderInfo.addEventListener(Event.COMPLETE, applyDistortion);
distortMap.load(requ);
}
private function applyDistortion( E:Event = null ):void{
// get jpg as BitmapData
var bmpData:BitmapData = new BitmapData( distortMap.content.width,distortMap.content.height);
bmpData.draw(distortMap);
// create the filter - notice gray(128,128,128) means no distortion white is negative black is positive distortion
var offsetOfMap:Point = new Point(0,0);
var redChannelCode:uint = BitmapDataChannel.RED; // is not important cause you just need oneway distortion
var yDistortion:int = 20; // strength
var distortFilter:DisplacementMapFilter = new DisplacementMapFilter(bmpData,offsetOfMap,0,redChannelCode,0,yDistortion,DisplacementMapFilterMode.COLOR,0xffffff,0);
// filters need to be included in an array to add on display Object
var filters:Array = new Array();
filters.push(distortFilter);
// adding filter to image
sourceImage.filters = filters;
addChild(sourceImage);
}
}
}

Related

AS3: AddChild issue -- "TypeError: Error #2007: Parameter child must be non-null."

My following code gave me
TypeError: Error #2007: Parameter child must be non-null runtime error.
not sure why...I would appreciate any help...
mySb = new ScrollBar();
mySb.x = cont.x; //+ cont.width;
mySb.y = cont.y;
mySb.height = contMask.height;
mySb.enabled = true;
addChild(mySb);
Updated
package com.search.view
{
import com.search.events.YouTubeSearchEvent;
import fl.controls.ScrollBar;
import fl.controls.Slider;
import fl.controls.UIScrollBar;
import fl.events.ScrollEvent;
import fl.events.SliderEvent;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.net.URLLoader;
public class SearchResultContainer extends Sprite
{
private var cont:videoCont;
private var contMask:Sprite;
private var mySb:ScrollBar;
public function SearchResultContainer()
{
super();
}
public function get selectedVideoID():String{
return newVideoID;
}
public function createContainer(_x:Number,_y:Number, videoResult:Array):void{
cont=new videoCont();
cont.x=_x;
cont.y=_y;
addChild(cont);
contMask = new Sprite();
contMask.x = cont.x;
contMask.y = cont.y;
createMask(contMask,0x000000,452,88);
addChild(contMask);
cont.mask = contMask;
mySb = new ScrollBar();
mySb.x = cont.x; //+ cont.width;
mySb.y = cont.y;
mySb.height = contMask.height;
mySb.enabled = true;
addChild(mySb); //problem code here...
}
private function createMask(inSrc:*,inColor:Number=0x999999,inW:Number=80,inH:Number=50):void{
var rect:Shape=new Shape();
rect.graphics.clear();
rect.graphics.beginFill(inColor);
rect.graphics.drawRect(0,0,inW,inH);
rect.graphics.endFill();
inSrc.addChild(rect);
}
}
}
I am in Flex environment....
Try to add a breakpoint before the problem occurs and check the mySb value , it looks like it's probably null , if it's not you'll have to look for null values either in the DisplayObjects you're using or the properties you're assigning them... if it is null , maybe you need to set more properties to your ScrollBar instance before adding it to the display list...
In my case I solved it adding the component to the movie library, but working in Flash CS5.5 environment.

How come this image won't resize to fit the sprite?

I have this snippet of ActionScript code that is supposed to resize an image to fit the sprite: (as in rescale the image not just clip it)
package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.events.Event;
public class Main extends Sprite
{
[Embed(source = 'img.png')]
private var TheImage:Class;
public static const TheImageWidth:Number = 1300;
public static const TheImageHeight:Number = 1300;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var image:Bitmap = new TheImage();
addChild(image);
image.scaleX = width / TheImageWidth;
image.scaleY = height / TheImageHeight;
}
}
}
Why isn't it working? The image isn't getting the right dimensions.
try
image.image.content.width = TheImageWidth;
image.image.content.height = TheImageHeight;
I had to do the something like this for imagery. We had issue with using MapImage and the MapImageLayer using ArcGIS for Flex 2.5. It seems to be fix in 3.5, Anyways I had to put an image into a sprite and paint the image based on the sprites width. If you want to scale the image to the sprite's dimensions you will need to use the Matrix API and use the scale method. The values passed into this should be the sprite's width divided by the image's width assuming the image is bigger than your sprite. Do the same with the height. Here is the code I used to accomplish the task.
const point:MapPoint = geometry as MapPoint;
sprite.x = toScreenX(map, point.x);
sprite.y = toScreenY(map, point.y);
// grab left x point for upper left then for lower right
// actua
var bottomLeftX:Number = toScreenX(map, geomertyWrapper.extent.xmin);
var topRightX:Number = toScreenX(map, geomertyWrapper.extent.xmax);
var bottomLeftY:Number = toScreenY(map, geomertyWrapper.extent.ymin);
var topRightY:Number = toScreenY(map, geomertyWrapper.extent.ymax);
iconWidth = Math.abs(topRightX - bottomLeftX);
iconHeight = Math.abs(topRightY - bottomLeftY);
sprite.width = iconWidth;
sprite.height = iconHeight;
var scaleX:Number = iconWidth/bitmapData.width;
var scaleY:Number = iconHeight/bitmapData.height;
m_matrix.a = 1.0;
m_matrix.d = 1.0;
m_matrix.scale(scaleX, scaleY);
m_matrix.tx = -iconWidth / 2;
m_matrix.ty = -iconHeight / 2;
//Values needed for drawing AlertNotificationInstance
sprite.graphics.beginBitmapFill(m_bitmapData, m_matrix, false, false);
sprite.graphics.drawRect(m_matrix.tx, m_matrix.ty,
iconWidth,
iconHeight);
sprite.graphics.endFill();
Hope this helps.

generate screenshot and send it to server (not using FileReference.upload)

Do you have any ideas?
Maybe this can help too, this example creates a BitmapData instance, and then sends that as a ByteArray to the server, (in my case, I was using PHP) ... you'll need to write the server side code, but there's nothing quite special here
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
import flash.utils.ByteArray;
import mx.graphics.codec.PNGEncoder;
import mx.utils.Base64Encoder;
public class DataUpload extends Sprite
{
private var _loader:URLLoader;
public function DataUpload()
{
// create a bitmap data
var bd:BitmapData = createDummyImage();
var png:PNGEncoder = new PNGEncoder();
var ba:ByteArray = png.encode(bd);
var b64:Base64Encoder = new Base64Encoder();
b64.encodeBytes(ba);
// initialize loader
_loader = new URLLoader();
_loader.addEventListener(Event.COMPLETE, loadCompleteHandler);
_loader.addEventListener(ProgressEvent.PROGRESS, loadProgressHandler);
var request:URLRequest = new URLRequest("http://localhost/YOUR_PHP_SCRIPT_URI");
request.method = URLRequestMethod.POST;
var variables:URLVariables = new URLVariables();
variables.fileData = b64;
variables.fileName = "foobar";
request.data = variables;
_loader.load(request);
}
protected function loadCompleteHandler(event:Event):void {
trace("complete");
}
protected function loadProgressHandler(event:ProgressEvent):void {
trace("progress : ", event.bytesLoaded / event.bytesTotal);
}
private function createDummyImage():BitmapData {
var bd:BitmapData = new BitmapData(300, 300, true, 0x00ffffff);
var shape:Shape = new Shape();
shape.graphics.beginFill(0xff0000);
shape.graphics.drawCircle(10, 10, 10);
shape.graphics.endFill();
bd.draw(shape);
return bd;
}
}
}
Step 1: Use ImageSnapshot to capture the screenshot (I assume we're just talking about the Flash screen, not the OS). This can handle the image encoding for you, or you can capture BitmapData and reencode yourself.
Step 2(a): Use a MultipartLoader to post the generated bytes. Flash security in Flash Player 10 will require the HTTP post to occur on user interaction.
or
Step 2(b): Use a regular URLLoader/URLRequest to post the generated bytes (Base64 encoded, say).

calling a function in file1.as from file2.as?

How can I call a function in file1.as from file2.as?
here is the code.
package com.modestmaps
{
import com.modestmaps.overlays.MarkerClip;
import flash.display.Graphics;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.filters.BlurFilter;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.text.TextField;
//import mx.core.Application;
import mx.core.Application;
import flash.events.MouseEvent;
public class InfoBubble extends Sprite
{
private var btn_close:String = "http://(.yada.yada.)/media/close_button.swf";
public var textField:TextField;
public var background:Shape;
public var shadow:Shape;
public var infoClip:MarkerClip;
protected var map:InfoMap;
//var infoClip:MarkerClip;
public var infoBubble:InfoBubble;
public function InfoBubble(urlLink:String)
{
//the name of my markers are set to the links of the swf files in which I want to load into the infobubble
this.name = urlLink;
this.mouseEnabled = false;
this.mouseChildren = true;
this.buttonMode=false;
shadow = new Shape();
shadow.filters = [ new BlurFilter(16, 16) ];
shadow.transform.matrix = new Matrix(1, 0, -0.5, 0.5, 0, 0);
addChild(shadow);
background = new Shape();
addChild(background);
textField = new TextField();
textField.selectable = false;
//the infobubble is still sized according to the textField.width and height
//I don't know how to get the size of the loaded swf
textField.width = textField.textWidth+432+4;
textField.height = textField.textHeight+288+4;
//add main swf
var request:URLRequest = new URLRequest(urlLink);
var loader:Loader = new Loader();
loader.load(request);
addChild(loader);
//position the main swf
//current measurements of swf file w432 h288
loader.y = -288 - 37;
loader.x = mx.core.FlexGlobals.topLevelApplication.LBloaderX;
//add close button
var reqButton:URLRequest = new URLRequest(btn_close);
var loader2:Loader = new Loader();
loader2.load(reqButton);
addChild(loader2);
loader2.addEventListener(MouseEvent.CLICK, closeInfoBubble);
function closeInfoBubble(event:MouseEvent):void
{
infoClip.removeMarkerObject(infoBubble)
infoBubble = null
}
//position the closebutton swf
//current measurements of closebutton swf file w18 h18
loader2.y = -286 - 37;
loader2.x = mx.core.FlexGlobals.topLevelApplication.LBloader2X;
// remember that things in marker clips are positioned with (0,0) at the given location
textField.y = -textField.height - 35;
textField.x = -10;
//I need to find out how to detect the width and height of the swf file loaded into loader2
//instead of the size of the textField
var rect:Rectangle = textField.getRect(this);
// get your graph paper ready, here's a "speech bubble"
background.graphics.beginFill(0x12345);
shadow.graphics.beginFill(0x000000);
for each (var g:Graphics in [ background.graphics, shadow.graphics ] ) {
g.moveTo(rect.left, rect.top);
g.lineTo(rect.right, rect.top);
g.lineTo(rect.right, rect.bottom);
g.lineTo(rect.left+15, rect.bottom);
g.lineTo(rect.left+10, rect.bottom+15);
g.lineTo(rect.left+5, rect.bottom);
g.lineTo(rect.left, rect.bottom);
g.lineTo(rect.left, rect.top);
g.endFill();
}
}
}
}
in this package i am attempting to add the shadow, which works, and then add the infobubble, which works, and then add a main swf which works, and then add a close_button.swf which it does load the swf; however, when I try to add the listener, I am unable to make the infobubble close back up.
Convention typically allows for one .as file per class, so you would need to have a reference to an instantiated object of that class inside the second one.
That said, we need -way- more information to provide any kind of useful answer.
To add to Tegeril's answer: Aside from accessing the functions inside of an instantiated class, you could also (as is the case in a utility class), make the functions static. In this case you could call the method like so: ClassName.methodName(), without the need to instantiate.... my random 2p.

Best way to get the color where a mouse was clicked in AS3

I have an image (mx) and i want to get the uint of the pixel that was clicked.
Any ideas?
A few minutes on the BitmapData LiveDoc Page will take you where you need to go. Once you have your image loaded into a Bitmap variable, you can access its BitmapData property. Add a Mouse Click Event Listener to the image and then use BitmapData::getPixel. The example for getPixel shows how to convert the uint response to an rgb hex code.
Here's a modification of the Example given on the BitmapData page that worked for me (using mxmlc - YMMV):
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
public class BitmapDataExample extends Sprite {
private var url:String = "santa-drunk1.jpg";
private var size:uint = 200;
private var image:Bitmap;
public function BitmapDataExample() {
configureAssets();
}
private function configureAssets():void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
var request:URLRequest = new URLRequest(url);
loader.load(request);
addChild(loader);
}
private function completeHandler(event:Event):void {
var loader:Loader = Loader(event.target.loader);
this.image = Bitmap(loader.content);
this.addEventListener(MouseEvent.CLICK, this.clickListener);
}
private function clickListener(event:MouseEvent):void {
var pixelValue:uint = this.image.bitmapData.getPixel(event.localX, event.localY)
trace(pixelValue.toString(16));
}
}
}
Here's an even simpler implementation. All you do is take a snapshot of the stage using the draw() method of bitmapData, then use getPixel() on the pixel under the mouse. The advantage of this is that you can sample anything that's been drawn to the stage, not just a given bitmap.
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.*;
stage.addEventListener(MouseEvent.CLICK, getColorSample);
function getColorSample(e:MouseEvent):void {
var bd:BitmapData = new BitmapData(stage.width, stage.height);
bd.draw(stage);
var b:Bitmap = new Bitmap(bd);
trace(b.bitmapData.getPixel(stage.mouseX,stage.mouseX));
}
Hope this is helpful!
Edit:
This edited version uses a single BitmapData, and removes the unnecessary step of creating a Bitmap. If you're sampling the color on MOUSE_MOVE then this is essential to avoid memory issues.
Note: if you're using a custom cursor sprite you'll have to use an object other than 'state' or else you'll be sampling the color of the custom sprite instead of what's under it.
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.*;
private var _stageBitmap:BitmapData;
stage.addEventListener(MouseEvent.CLICK, getColorSample);
function getColorSample(e:MouseEvent):void
{
if (_stageBitmap == null) {
_stageBitmap = new BitmapData(stage.width, stage.height);
}
_stageBitmap.draw(stage);
var rgb:uint = _stageBitmap.getPixel(stage.mouseX,stage.mouseY);
var red:int = (rgb >> 16 & 0xff);
var green:int = (rgb >> 8 & 0xff);
var blue:int = (rgb & 0xff);
trace(red + "," + green + "," + blue);
}
This is not specific to Flex or mx:Image, and allows you to grab a pixel color value from any bitmap drawable object (provided you have permission):
private const bitmapData:BitmapData = new BitmapData(1, 1);
private const matrix:Matrix = new Matrix();
private const clipRect:Rectangle = new Rectangle(0, 0, 1, 1);
public function getColor(drawable:IBitmapDrawable, x:Number, y:Number):uint
{
matrix.setTo(1, 0, 0, 1, -x, -y)
bitmapData.draw(drawable, matrix, null, null, clipRect);
return bitmapData.getPixel(0, 0);
}
You could easily grab a pixel from the stage or your mx:Image instance. It's a lot more efficient than drawing the entire stage (or drawable object), and should be fast enough to hook up to MouseEvent.MOUSE_MOVE for instant visual feedback.

Resources