Flipping a PNG with Matrix - actionscript-3

I'm having an issue flipping a png in AS3. The issue I'm having is that when I flip the image it is not keeping its transparency.
preApply = new BitmapData (Canvas.Bmp.width, Canvas.Bmp.height,true);
preApply.draw(Canvas.Bmp,myMatrix, null, null, null, true);
Any suggestions? The flip works its just it gives it a white background. I was able to run filters on the same image and that doesn't seem to give it a white background.
Update: Something strange I just found if I set the color for the BitmapData it keeps the transparency.
preApply = new BitmapData (Canvas.Bmp.width, Canvas.Bmp.height,true,0x0000FFFF);
Now my question kind of changes any idea why this might work?

That's easy, the default value for the fourth parameter of a bitmapData is what you want it to be initially filled with. So when you don't specify it as transparent (which is 0x000000FF or apparently 0x0000FFFF in this case also works) then it defaults to white, and when you draw your already transparent image onto this new opaque, white-filled image the alpha channel is overwritten by the white. This is because the draw command does not overwrite whatever is in the existing bitmapData with alpha channel information, only RGB values.

Related

Flash color transform

I'm having difficulty with transforming colour in Flash. It should be easy I think, but for some reason my code isn't working as expected.
I have a bitmap graphic consisting of a colour spectrum from red to yellow to green (you know, like you see in an audio level meter).
I simply want to sample a colour from that bitmap and then tint a movie clip on stage that sampled colour. (the effect I'll be going for is coloured progress - the closer you get to 100% green is displayed, the closer you are to 0% it's red - I haven't implemented that part yet, but I'm not worried about that).
Anyhow, I sample the colour just fine, and tint my clip, but no matter what I tint the clip it comes up a different colour than what I've sampled (the trace is a different colour than what I see on the clip). I can't see where I'm going wrong - I'm hoping it's a stupid mistake and someone can spot it easily.
import flash.display.BitmapData;
var bmd:BitmapData = new BitmapData(mc_colourbar.width, mc_colourbar.height);
bmd.draw(mc_colourbar);
var pixelvalue:uint = bmd.getPixel(0, 1);
trace(pixelvalue.toString(16));
var colourtransform:ColorTransform = mc_box.transform.colorTransform;
colourtransform.color = uint("0xff" + pixelvalue);
mc_box.transform.colorTransform = colourtransform ;
mc_box is the clip on stage I'm trying to tint - it's simply a white square.
Any help is appreciated, thanks in advance!
ColorTransform.color expects an RGB value, and it appears as though you're attempting to give it an ARGB value*.
Change the line:
colourtransform.color = uint("0xff" + pixelvalue);
to just:
colourtransform.color = pixelvalue;
and your code should work as expected.
*Though I don't think the way you're trying to do it here is correct.

Draw stroke on HTML canvas with different levels of opacity

The problem
I'm trying to create a brush tool with opacity jitter (like in Photoshop). The specific problem is:
Draw a stroke on an HTML canvas with different levels of opacity. Pixels with higher opacity should replace pixels with lower opacity; otherwise, pixels are left unchanged.
Transparency should not be lost in the process. The stroke is drawn on a separate canvas and merged with a background canvas afterwards.
The result should look like this. All code and the corresponding output can be found here (JSFiddle).
Because you can't stroke a single path with different levels of opacity (please correct me if I'm wrong) my code creates a path for each segment with different opacity.
Non-solution 1, Using the 'darken' blend mode
The darken blend mode yields the desired result when using opaque pixels but doesn't seem to work with transparency. Loosing transparency is a dealbreaker.
With opaque pixels:
With transparent pixels:
Non-solution 2, Using the 'destination-out' compositing operator
Before drawing a new stroke segment, subtract its opacity from subjacent pixels by using the 'destination-out' compositing operator. Then add the new stroke segment with 'source-over'. This works almost but it's a little bit off.
Looking for a solution
I want to avoid manipulating each pixel by hand (which I have done in the past). Am I missing something obvious? Is there a simple solution to this problem?
"Links to jsfiddle.net must be accompanied by code."
Because you can't stroke a single path with different levels of opacity (please correct me if I'm wrong)
You're wrong =)
When you use globalCompositeOperation = 'destination-out' (which you are in lineDestinationOut) you need to set the strokeStyle opacity to 1 to remove everything.
However, simply changing that in your fiddle doesn't have the required effect due to the order of your path build. Build the 10% transparent one first, the whole length, then delete and draw the two 40% transparent bits.
Here's a jsfiddle of the code below
var canvas = document.getElementById('canvas');
var cx = canvas.getContext('2d');
cx.lineCap = 'round';
cx.lineJoin = 'round';
cx.lineWidth = 40;
// Create the first line, 10% transparency, the whole length of the shape.
cx.strokeStyle = 'rgba(0,0,255,0.1)';
cx.beginPath();
cx.moveTo(20,20);
cx.lineTo(260,20);
cx.lineTo(220,60);
cx.stroke();
cx.closePath();
// Create the first part of the second line, first by clearing the first
// line, then 40% transparency.
cx.strokeStyle = 'black';
cx.globalCompositeOperation = 'destination-out';
cx.beginPath();
cx.moveTo(20,20);
cx.lineTo(100,20);
cx.stroke();
cx.strokeStyle = 'rgba(0,0,255,0.4)';
cx.globalCompositeOperation = 'source-over';
cx.stroke();
cx.closePath();
// Create the second part of the second line, same as above.
cx.strokeStyle = 'black';
cx.globalCompositeOperation = 'destination-out';
cx.beginPath();
cx.moveTo(180,20);
cx.lineTo(260,20);
cx.stroke();
cx.strokeStyle = 'rgba(0,0,255,0.4)';
cx.globalCompositeOperation = 'source-over';
cx.stroke();
cx.closePath();
Use two layers to draw to:
First calculate the top layer opacity 40% - 10% and set this as alpha on top layer
Set bottom layer to 10%
Set top layer with dashed lines (lineDash) (calculate the dash-pattern size based on size requirements)
Draw lines to both layers and the bottom layer will be a single long line, the top layer will draw a dashed line on top when stroked.
Copy both layers to main canvas when done.
#HenryBlyth's answer is probably the best you're going to get; there's no native API to do what you're being asked to do (which, in my opinion, is kinda weird anyways... opacity isn't really supposed to replace pixels).
To spell out the solution in one paragraph: Split up your "stroke" into individual paths with different opacities. Draw the lowest opacity paths as normal. Then, draw the higher opacities with "desitination-out" to remove the low-opacity paths that overlap. Then, draw the high opacity paths as usual, with "source-over", to create the effect desired.
As suggested in the comments to that answer, #markE's comment about making each path an object that is pre-sorted before drawing is a great suggestion. Since you want to perform manual drawing logic that the native API can't do, turning each path into an object and dealing with them that way will be far easier than manually manipulating each pixel (though that solution would work, it could also drive you mad.)
You mention that each stroke is being done on another canvas, which is great, because you can record the mouseevents that fire as that line is being drawn, create an object to represent that path, and then use that object and others in your "merged" canvas without having to worry about pixel manipulation or anything else. I highly recommend switching to an object-oriented approach like #markE suggested, if possible.

as3 image over another using bitmap

Ok so im trying to load a bitmap image as a background using this:
screenBitmapData.copyPixels(tilesBitmapData,new Rectangle(sourceX,sourceY,tileSize,tileSize),new Point(destX,destY));
screenBitmap = new Bitmap(screenBitmapData);
addChild(screenBitmap);
This load my tiled map correctly and display it on the screen.
Now i want to add another image which will be used as my character and the frame displaying it contain my character movement and then display the image as follow:
screenBitmapData.copyPixels(playerSheetBitmapData, new Rectangle(currentSpriteColumn * CHAR_SPRITE_WIDTH, currentSpriteRow * CHAR_SPRITE_HEIGHT, CHAR_SPRITE_WIDTH, CHAR_SPRITE_HEIGHT), new Point(xPos, yPos), null, null,true);
I setted the alpha channel on my character image and this is the result when im moving around my map with it:
http://snag.gy/L2uuR.jpg
As you can see, the background image doesnt refresh. And i simply dont know how to do this. Im pretty new with flash and as3 and ive been trying for days to make it work. I know it have something to do with the copypixel or redrawing the background before i draw the sprite again... Any ideas?
You need to redraw the entire scene. All you're doing at the moment is drawing the player ontop of the result of your previous draw.
All you need to do in your case is draw the entire background each frame before you draw the character. It could look like this:
function renderScene():void
{
// Draw the background, which will replace all the current graphics
// on the Bitmap.
screenBitmapData.copyPixels(tilesBitmapData,new Rectangle(sourceX,sourceY,tileSize,tileSize),new Point(destX,destY));
// Then draw the player.
screenBitmapData.copyPixels(playerSheetBitmapData, new Rectangle(currentSpriteColumn * CHAR_SPRITE_WIDTH, currentSpriteRow * CHAR_SPRITE_HEIGHT, CHAR_SPRITE_WIDTH, CHAR_SPRITE_HEIGHT), new Point(xPos, yPos), null, null,true);
}
To actually clear the Bitmap though, you can just use fillRect() to fill it with a color (e.g. black):
// Fill the Bitmap with black.
screenBitmapData.fillRect( screenBitmapData.rect, 0x000000 );

Masking in ActionScript3

I am trying to understand masks in actionscript..Everything seems to make sense to me but one part of the code
function mouseM(event:MouseEvent):void {
if (mouseclick == 1) {
mask_mc.graphics.beginFill(0x000000);
mask_mc.graphics.drawEllipse(mouseX, mouseY, 70, 60);
mask_mc.graphics.endFill();
}
}
I am not sure how to exactly ask this question but here it goes. why does the mask have "begin fill" with a black color? wouldn't that paint the the image in black (I know it doesn't, it just reveals it)? what is the exact function of beginfill (besides revealing the image lool)? like how does it exactly work? sorry if it sounds ridiculously off.. but that part of the code was really screwing me up in understanding masks
What you are doing is drawing a shape to be used as a mask. In this case, a circle.
It doesn't matter what colour it is as Flash is only interested in the shape of the mask, not the colour.
Once the circle is drawn, Flash checks what part of the circle overlap the object you're masking so that every pixel the circle is not covering will be invisible. I guess it should really be called an anti-mask as the circle dictates which parts of your image wont be masked but it's just become the general convention to call the circle (or whatever shape you use) the mask.
Again, you're just creating a shape to be used as a mask. Setting the colour is just so the object can essentially exist.. because you can't exactly have a transparent circle.
Feel free to change the colour to anything and you'll see it makes no difference, the shape is all that matters.

Actionscript 3.0 drawRect works weird

I have a BitmapData object named myBitmapData. It was loaded of PNG of size 104x104. This PNG represents a red circle on the transparent background.
There is also a Sprite object named myBackground. I want render that red circle into myBackground.
myBackground.graphics.beginBitmapFill(myBitmapData);
myBackground.graphics.drawRect(0, 0, myBitmapData.width, myBitmapData.height);
myBackground.graphics.endFill();
addChild(myBackground);
Everything is fine. I see a red circle in the left top of myBackground.
But when I change the third line to
myBackground.graphics.drawRect(0, 52, myBitmapData.width, myBitmapData.height);
and expect my circle to be translated 52 pixels down, I actually obtain something strange (for me :)): there are two red half-circles (they form like hourglass).
So, the question is: how do I render myBitmapData into the random position of myBackground?
P.S.
In the case of
myBackground.graphics.drawRect(0, 104, myBitmapData.width, myBitmapData.height);
it is circle again :)
This is caused by beginBitmapFill's default repeat = true parameter. There's an example in the docs. Disabling the repetition won't work though, you'd just get a half circle then.
There are several ways to fix this:
Use a Matrix with a translation (displacement) as argument in beginBitmapFill.
Draw the rectangle at 0,0 on another Sprite, and move that sprite to where you want it on the background.
Don't draw directly to the background, but to another bitmap using copyPixels. Then fill the background with that bitmap.