Gradient usage on GraphicsPath object - actionscript-3

I am currently trying to apply a gradient to a GraphicsPath object. My code is as follows:
import flash.display.*;
var style:GraphicsStroke = new GraphicsStroke(3);
style.fill = new GraphicsGradientFill('linear',[0xFF0000,0x00FF00],[1,1],[0,255]);
var line_commands:Vector.<int> = new <int>[1,2];
var line_points:Vector.<Number> = new <Number>[0,0,800,600];
var line:GraphicsPath = new GraphicsPath(line_commands, line_points);
var image:Vector.<IGraphicsData> = new <IGraphicsData>[style, line];
graphics.drawGraphicsData(image);
If I'm not mistaken, the stroke used should cause the line to linearly fade between red and green with full red being at 0,0 and full green at 800,600. When run, however, there is no full red and only a tiny hint of the fade around the 0,0 point. I've been messing around with options for a couple hours to no avail... anyone have an idea of what's going on here?

You miss the matrix parameter for gradient fill object.
var mat:matrix=new Matrix();
mat.createGradientBox(800,600);
style.fill.matrix=mat;

Related

as3 - setting textures alpha-value

For an Actionscript 3 "drawing application", I want to be able to chose a Texture and set it's transparency.
Therefore I try to set the alpha-transparency of a texture.
But it's not working.
What I do:
At first I use graphics.linestyle() to set the lines thickness and ALPHA-value.
After that I (a) load a png, (b) read it's bitmapData and (c) then use it with lineBitmapStyle.
Result:
When drawing lines (with moveTo, lineTo, etc) the lines use the texture, but IGNORE THE "Alpha" which was set with lineStyle.
What am I doing wrong?
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, setTexture);
setTexture(e:Event):void
{
e.currentTarget.removeEventListener(e.type, arguments.callee);
//Try 1: Trying to set the Alpha-Trasparency with "lineStyle"-Command:
myDrawContainer.graphics.lineBitmapStyle(5, 0xFF0000, 0,6);
//Try 2: Trying to set the Alpha-Transparency by changing the Alpha-Value of the loaded content:
myLoader.content.alpha = 0.6;
//Getting the BitmapData of the Image:
BitmapDataOfMyTexture = Bitmap(LoaderInfo(e.target).content).bitmapData
//"Using" the TBitmapData as "Color/Texture" for my Drawing:
myDrawContainer.graphics.lineBitmapStyle( BitmapDataOfMyTexture );
//Test-Drawing:
myDrawContainer.graphics.moveTo( 0, 0 );
myDrawContainer.graphics.moveTo( 500, 500 ); //-> RESULT: Textured Line WITHOUT Transparency!
}
RESULT: I get a line which uses the texture but WITHOUT Transparency.
(Update) THE SOLUTION: (Thanks to DodgerThud)
For setting/changing the Alpha-Channel of a loaded image, you don't use "lineStyle" but...
Create a NEW colorTransform-object
Then set it's "alphaMultiplier"-attribute to the specific alphaChannel
And then apply this newly created colorTransform-Object to the loaded BitmapData, by using the "colorTransform"-Method of the loaded BitmapData.
BUT :
This does NOT work with images that don't have an alpha-Channel or don't have their alpha-channel activated. Those images only get DARKER when lowering the alpha-Channel. In those cases you have to do this:
At FIRST I create NEW BitmapData-Object with "new", set its width and height to the width and height of the loaded Image and set it 3rd Argument to TRUE (= transparency: ON). So you got a "Container" which has transparency ACTIVATED.
Then you use "copyPixels" on this "Container"-Object to fill it with the pixels of the LOADED BitmapData-Object.
And right after this the above approach with the "colorTransform"-Object brings the expected result.
So HERE'S THE WORKING CODE:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, setTexture);
setTexture(e:Event):void
{
e.currentTarget.removeEventListener(e.type, arguments.callee);
//Getting the BitmapData of the Image:
BitmapDataOfMyTexture = Bitmap(LoaderInfo(e.target).content).bitmapData
//Create an ADDITIONAL BitmapData-Object with 3rd
//argument set to TRUE and with same width and height
//as the LOADED image:
var BMDContainerWithAlphaActivated:BitmapData;
BMDContainerWithAlphaActivated = new BitmapData(BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height, true, 0xFFFFFF);
//Copy the pixels of the loaded image into the newly created
//"BitmapData-Container with activated AlphaChannel":
BMDContainerWithAlphaActivated.copyPixels(BitmapDataOfMyTexture, new Rectangle(0, 0, BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height), new Point(0,0))
//Modify the Alpha-Value (of the NEW BitmapData-Object):
var colorChanges:ColorTransform = new ColorTransform();
colorChanges.alphaMultiplier = 0.3;
BMDContainerWithAlphaActivated.colorTransform(new Rectangle(0, 0, BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height), colorChanges);
//"Using" the (NEW) BitmapData as "Color/Texture" for my Drawing:
myDrawContainer.graphics.lineBitmapStyle( BMDContainerWithAlphaActivated );
//Test-Drawing:
myDrawContainer.graphics.moveTo( 0, 0 );
myDrawContainer.graphics.moveTo( 500, 500 ); //-> RESULT: Textured Line WITH Transparency 0.3!
}
Ah I see, this is a bit more complex than I initially thought.
Alright, looking at the documentation for lineBitmapStyle shows me that the function expects the following parameters: lineBitmapStyle(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false)
Now, matrix, repeat and smooth will not help us here (matrix is used here for transformation, i.e. positioning, rotation etc.), but bitmap:BitmapData might. What we need to do is manipulate the BitmapData of the loaded PNG file before passing it to lineBitmapStyle. Sadly we cannot set the alpha value directly on the BMD, so we can try to colorTransform it.
This is untested code, but I think it is the right approach:
..
//store the bitmapdata in a seperate local variable
var bmd:BitmapData = LoaderInfo(e.target).content;
//create a ColorTransform Object to change the values of the BMD
var cTransform:ColorTransform = new ColorTransform();
//now here I am unsure, manipulating the alpha value of the BMD
cTransform.alphaMultiplier = 0.6;
//defining the rectangle dimensions of the bmd, we want it to be over the entire texture
var rect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height);
//apply the colorTransformation on the BMD
bmd.colorTransform(rect,cTransform);
...
//the now manipulated BMD gets set as lineBitmapStyle
myDrawContainer.graphics.lineBitmapStyle(bmd);
And now that I think about it, maybe we can workaround setting the alpha value on the BMD, by creating a Bitmap first, set the alpha value there and use the bitmapdata of the Bitmap instead. Like this:
var bmd:BitmapData = LoaderInfo(e.target).content;
var bm:Bitmap = new Bitmap(bmd);
bm.alpha = 0.6;
myDrawContainer.graphics.lineBitmapStyle(bm.bitmapData);
Alright, the first snippet from above seems to be the way to do it, but the transparent value of the BitmapData needs to be true. Given that you do not directly create the BitmapData yourself and the value is false, we have quite a tricky situation here.
Another approach would be to create an additional bitmapdata that allows for transparancy and draw() the bitmapdata of the loaded image on it:
var bmdSource:BitmapData = LoaderInfo(e.target).content;
var bmd:BitmapData = new BitmapData(bmdSource.width, bmdSource.height,true,0xffffffff);
var cTransform:ColorTransform = new ColorTransform();
cTransform.alphaMultiplier = 0.6;
var rect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height);
bmd.colorTransform(rect,cTransform);
//now we have a completely white bitmapdata bmd, with an alpha value of 0.6
//we draw the contents of the bmdSource onto bmd, the alpha value effect should carry over
bmd.draw(bmdSource);

AS3 image rotate within / scale to fit sprite

We're making bitmap data from a sprite where we want to take an image and rotate within / scale to fit. This is our code, which includes a rotation.
_rotation defines how much the user has input.
The problem is, we're getting an output file that is 100% white.
We think that the image is rotating about 0x0y therefore rotating the image outside the bounds of the sprite.
Furthermore, the image is not scaling to the child, instead is sort of "cropping" as it inherits.
What is the best way of doing this? Basically we want to take an image and rotate within / scale to fit
var sprite1:Sprite = new Sprite();
addChild(sprite1);
var photoBitmap:Bitmap = new Bitmap(_bitmapData);
sprite1.addChild(photoBitmap);
sprite1.rotation = _rotation;
var sprite2:Sprite = new Sprite();
addChild(sprite2);
sprite2.addChild(sprite1);
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
bitmapData.draw(sprite2);
The simple way to draw sprite with scaling/rotating is using Matrix in method bitmapData.draw().
Example:
var sourceImage:SomeSprite = new SomeSprite();
var matrix:Matrix = new Matrix();
matrix.scale(0.5, 0.5);
matrix.rotate(0.5 * Math.PI);
var newImage:BitmapData = new BitmapData(sourceImage.width/2, sourceImage.height/2);
newImage.draw(sourceImage, matrix);
Your issue is likely a cause of rotating around the top left corner (which can make the entire object left of or above the registration point (0 x and 0 y) and not get drawn.
An easy way you can account for this, is to move sprite1 after the rotation to account for the new size and position caused by rotating:
...
sprite2.addChild(sprite1);
var actualPosition:Rectangle = sprite2.getBounds(sprite2); //this gets the new position/dimensions of the object
sprite1.x = -actualPosition.x;
sprite1.y = -actualPosition.y;
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
...

AS3 Having trouble understanding Rectangle Intersection

I'm trying to get Rectangle.intersection to provide me with the rectangle of the intersection area of 2 overlapping shapes but not having much success.
The code below is simply 2 shapes the same size. The top most shape is draggable.
When the drag is stopped I perform a bottomRect.intersection(topRect) call but this always returns the full size of the rect, not the intersection size.
(the code can be copied and pasted into a new ActionScript file on the first frame and run.)
Does anyone have an idea where I'm going wrong?
Thanks
import flash.geom.Rectangle;
import flash.display.Sprite;
var bottomSprite:Sprite = new Sprite();
addChild(bottomSprite);
var bottomRect:Shape = new Shape;
bottomRect.graphics.beginFill(0xFF0000);
bottomRect.graphics.drawRect(0, 0, 320,480);
bottomRect.graphics.endFill();
bottomSprite.addChild(bottomRect);
var topSprite:Sprite = new Sprite();
addChild(topSprite);
var topRect:Shape = new Shape;
topRect.graphics.beginFill(0x000033);
topRect.graphics.drawRect(0, 0, 320,480);
topRect.graphics.endFill();
topSprite.addChild(topRect);
var bottomBoundsRect:Rectangle = stage.getBounds(bottomSprite);
trace("START: bottomBoundsRect ", bottomBoundsRect);
var topBoundsRect:Rectangle = stage.getBounds(topSprite);
trace("START: topBoundsRect ", topBoundsRect);
topSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
topSprite.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
function mouseDownHandler(evt:MouseEvent):void{
topSprite.startDrag();
}
function mouseUpHandler(evt:MouseEvent):void{
topSprite.stopDrag();
topBoundsRect = stage.getBounds(topSprite);
trace("INTERSECTION RECT", bottomBoundsRect.intersection(topBoundsRect));
}
The problem is because of wrong toIntersect property that you pass:
topBoundsRect = stage.getBounds(topSprite);
trace("INTERSECTION RECT", bottomBoundsRect.intersection(topBoundsRect));
What you do is that you get the bounds of the topSprite agains the Stage. If you trace it, it will give you something like this:
(x=-62, y=-41, w=382, h=521)
So you have a bounds that start at 0,0 and have bigger width/height, because you move the topSprite - here I've moved it 62 pixels to the right (382 - 320 [width]), and 41 pixels down (521 - 480 [height]).
The actual intersection of this rectangle against the bottom one, is exactly the size of the bottom one.
What you should do is something similar to this:
// somehow get the rectangle of the bottom sprite
var br:Rectangle = new Rectangle(bottomSprite.x, bottomSprite.y, bottomSprite.width, bottomSprite.height);
// somehow get the rectangle of the top sprite
var tr:Rectangle = new Rectangle(topSprite.x, topSprite.y, topSprite.width, topSprite.height);
trace (br.intersection(tr)); // intersect them
There are few ways to get the bounds, but this is also working and shows the idea.
Hope that helps! :)

Change Bitmap to different shapes in Windows Phone app

I've been looking for the solution for some time and haven't yet found it. One of the functions of my app is to load an image and then to change its shape - e.g. I load a normal rectangular image, and then there are 2-3 buttons - change the image to a circle, triangular or some other shape. Is sth like that even possible with Bitmaps? I found a lot of interesting things about Nokia imaging SDK, but all the shape stuff i found was LensBlurEffect, which isn't exactly what i need.
If someone could point me in the right direction, I would be really grateful!
Thank You in advance for help!
Best regards,
Roman
I'm working on filters that draws shapes using Nokia Imaging SDK. To solve your problem, I created sample project that uses Nokia Imaging SDK's blend filter and my custom shape filters.
Actually you can do the same thing with shape image as David refers (background is black, foreground white) instead of using my custom filters (EllipseShapeFilter above example code).
Here is sample code;
var ellipseImage = new WriteableBitmap(1024, 768);
Rect origin = new Rect(new Point(512, 384), new Size(512, 384));
uint white = 0xff000000 | (255 << 16) | (255 << 8) | 255;
var image = LoadFromResources(new Uri(#"/BlendImageSample;component/Assets/Sample.jpg", UriKind.Relative));
using (var ellipseSource = new BitmapImageSource(ellipseImage.AsBitmap()))
using (var ellipse = new EllipseShapeFilter(ellipseSource, white, origin))
{
ellipseImage = await new WriteableBitmapRenderer(ellipse, ellipseImage).RenderAsync();
}
ImageViewer.Source = ellipseImage;
using (var backgroundSource = new BitmapImageSource(ellipseImage.AsBitmap()))
using (var foregroundSource = new BitmapImageSource(image.AsBitmap()))
using (var filterEffect = new FilterEffect(backgroundSource))
{
using (BlendFilter blendFilter = new BlendFilter())
{
blendFilter.ForegroundSource = foregroundSource;
blendFilter.BlendFunction = BlendFunction.Darken;
filterEffect.Filters = new[] { blendFilter };
var OutputBitmap = new WriteableBitmap(image.PixelWidth, image.PixelHeight);
var result = await new WriteableBitmapRenderer(filterEffect, OutputBitmap).RenderAsync();
ImageViewer.Source = result;
}
}
Github - BlendImageSample
Well the bitmap is always going to be rectangular, there is nothing you can do about that.
What you can do is make some pixels transparent, thus making the bitmap appear of a different shape.
One way to do this using the Nokia Imaging SDK is to use the BlendFilter to blend a transparent image (I suggest just a ColorImageSource) over the original image. You can provide different masks to create different "shapes."

To check whether Movie Clip got filled at one place

I have created a empty movie clip .
And i,m brushing on that .(i.e)Filling(Begin Fill) it with ellipse for every click .
How do I check whether it is filled at particular place .(say 400 x 400 from x=0,y=0)?
First you would need to convert it to a bitmapdata format.
Then you would use the function getPixel to query it.
import flash.display.Bitmap;
import flash.display.BitmapData;
// Lets say drawingpad is a MovieClip that is getting ellipses drawn on it.
var bitmap:Bitmap = new Bitmap(new BitmapData(stage.stageWidth,stage.stageHeight));
bitmap.draw(drawingpad);
var value:uint = bitmap.bitmapData.getPixel(400,400);
Hope this helps
I assume with "400 x 400 from x=0,y=0" you mean a the area between 0,0 and 400,400.
You need to copy the content of the rectangle of your MovieClip to a Bitmap, to be able to get information about its pixels.
// coordinates as in the question's example, could be method parameters
var x1:int=0;
var y1:int=0;
var x2:int=400;
var y2:int=400;
// bitmap with transparency, with a size of the rectangle to check
var bitmap:Bitmap = new Bitmap(new BitmapData(x2-x1, y2-y1, true, 0x00000000));
// draw the painted mc to the bitmap, displaced to upper left x and y
bitmap.draw(mc, new Matrix(1,0,0,1,-x1,-y1)));
Using getColorBoundsRect, you can check if a bitmap contains a colour, or if it contains any other colours. Now check if it contains any other colour than 'transparent' (= any other colours with an alpha value>0):
var maskColor:uint = 0xFF000000; // ignore rgb, only check alpha values
var color:uint = 0x00000000; // 'empty', fully transparent color
// get a rect containing all pixels with not fully transparent colors
var colorBoundsRect:Rectangle = bitmap.getColorBoundsRect(maskColor, color, false);
if (colorBoundsRect.width == 0 && colorBoundsRect.height == 0){
trace("empty"); // rect contains no visible pixels
}
Assuming the places where it's not filled are transparent, a simple hitTestPoint should do the trick:
myObj.hitTestPoint( 400.0, 400.0, true ); // true means we use the pixels of the shape and not the bounding box
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestPoint()