Here's what I want to do. An image is loaded by default when the app is run. There is a way to load another image the user wants by specifying an url. When the user defined image is loaded, the default image is still in the background and there are some method that would be used to apply some filters on the image as a whole (I mean the resultant image with both the default and the user loaded image blended) and then I want to save the final image as jpg or png.
Now, I am still a beginner at Flex, and getting all confused with all the canvas, image control, bitmapdata etc. Where I want help is what's the best way to implement what I want? Should I load the default image into an Image with url/embed or should I load it as a BitmapData, how do I load the second user defined image? Whats the best way to blend the two images?
You can leave the default image as embedded one, and retrieve its BitmapData to work with further.
When the user-defined image is loaded, you retrieve its BitmapData, and draw the embedded image over the user-defined one:
/**
* An embedded image's class (your default image)
*/
[Embed(source="/assets/logo.png")]
public static var Logo:Class;
/**
* #param bitmapData: The user-defined BitmapData that you want to modify
* #param matrix: The transofrmation matrix applied to the resulting BitmapData
*/
public function getCustomBitmapData(bitmapData:BitmapData, matrix:Matrix):BitmapData
{
// Initialize and drawing the resulting BitmapData's first layer
var result:BitmapData = new BitmapData(bitmapData.height, bitmapData.width);
result.draw(bitmapData, matrix);
// Load the BitmapData of the embedded Logo image
var bitmapAsset:BitmapAsset = new Logo();
var logoBd:BitmapData = bitmapAsset.bitmapData;
// Draw the logo over the result with an alpha of 0.3
result.draw(logoBd, matrix, new ColorTransform(1, 1, 1, .3));
//TODO: You should play with the size of the images, apply filters, etc.
return result;
}
Then you can save the resulting BitmapData instace to the local file system:
/**
* Save the BitmapData to a local file
* #param bitmapData: the data to save
*/
public function saveBitmapData(bitmapData:BitmapData):void
{
// Initialize the encoder
var pngEncoder:PNGEncoder = new PNGEncoder();
// Encode the BitmapData and save its byte array
var imageBytes:ByteArray = pngEncoder.encode(bitmapData);
// Create a new FileReference:
var imageFile:FileReference = new FileReference();
// Save the file:
imageFile.save(imageBytes, "myimage.png");
}
Related
I have a page that displays data about an object. At the top of the page is room for an icon, showing a picture of that object. Tapping this icon brings up a new page that allows the user to take a new picture, and save it as a temporary new picture for the object (not put in database, but should persist for the session)
Initial page:
private var source:Object = new Object();
protected function onInitialize():void {
source = navigator.poppedViewReturnedObject;
}
When setting source for the image later...
if (source != null) {
pic.source = source.object;
}
else {
pic.source = "no_picture_available_image.png";
}
2nd Page (User can take picture, and view new picture):
[Bindable]
private var imageSource:Object = null;
<s:Image id="pic" width="90%" height="75%" horizontalCenter="0" source="{imageSource}" />
After taking picture...
protected function mediaPromiseLoaded(evt:Event):void {
var loaderInfo:LoaderInfo = evt.target as LoaderInfo;
imageSource = loaderInfo.loader;
}
This does show the picture just taken correctly on this page.
To get back to old page, i use navigator.popView, and use:
override public function createReturnObject():Object {
return imageSource;
}
Unfortunately, it doesn't work. The imageSource isn't null when it is read from navigator.poppedViewReturnedObject, but no image is shown.
Does the LoaderInfo not persist after popping the view? Are the camera pics not automatically saved? I can't find answers to any of these questions, and I can't debug using the phone in my current environment.
After thinking about this a bit, don't return LoaderInfo.loader as the poppedViewReturnedObject. If I remember correctly, a DisplayObject can only be set as the source of one Image. Instead, return LoaderInfo.loader.content.bitmapData. That BitmapData should be the raw data used to display the image. This data can be used repeatedly to create images and can be set as the source of an Image.
Problem turned out to be in my first page's image declaration - I didn't set a width. Seemingly, the object being displayed couldn't handle not having a specified width.
Note that passing back the loader did work fine.
I am working with a digital book application. I make use of swf loader to load swf pages created from pdf. I use TextSnapsot to draw inline text highlight on the pages. The highlight is thoroughly retained on the respective pages throughout the session and later it can be updated/deleted without any problem. Everything was working great till I made the following changes in the swf loading approach to enable page caching:
I am now loading swf loader object into application memory and while doing jumping from one page to other page I am just copying the content of the next page to the current swf loader which is on the display to the user. There are two sets of swf loaders - one for displaying the page and other to cache the next/previous page(s). On the caching side, I load the swf into application memory and after getting it loaded I pick all the contents of the loaded swf page (the children of it's movie clip) into an array collection. While changing the page I copy the cached content into the swf loader's movie clip which is displaying the page.
Now when I highlight on the page on display and navigate back/forth from the page and comeback again to the page where I did the highlighting: It shows the highlight I did. But as soon as I try to draw another highlight on that page, the previous highlight is instantly disappears from the page.
I suspect that the Textsnapshot object which draws highlight while navigating (to the target display page) is different from the one which redraws/update the highlight on the same page next time. Although the Textsnapshot object id for both the objects is same.
Here are some code snippet:
For copying the content from the swf loader object cached in application memory:
private function copyPageContent():void
{
var contentCollection:ArrayCollection = new ArrayCollection();
_pageContentVO = new PageContentVO();
_pageContentVO.contentHeight = MovieClip(_swfPageLoader.content).height;
_pageContentVO.contentWidth = MovieClip(_swfPageLoader.content).width;
var count:int = MovieClip(_swfPageLoader.content).numChildren;
for(var i:int=0;i<count;i++)
{
var dispObject:DisplayObject = MovieClip(_swfPageLoader.content).removeChildAt(0);
contentCollection.addItem(dispObject);
}
_pageContentVO.pageContentCollection = contentCollection;
_swfPageLoader = null;
}
For copying the content to the swf loader which is displaying the page:
private function copyContent(pageContentVo:PageContentVO):void
{
for(var i:int = 0;i<pageContentVo.pageContentCollection.length;i++)
{
var dispObject:DisplayObject = pageContentVo.pageContentCollection.getItemAt(i) as DisplayObject;
MovieClip(this.content).addChild(dispObject);
}
this.content.height = this.height;
this.content.width = this.width;
}
after this I dispatch swf loader's complete manually and in the handler of that event I take the text snap shot object.(highlightManager.as)
Code I use to draw highlight manually(using mouse drag on the page).
public function setHighlight():void
{
removeAll();
if(_textSnapShot!=null && _textSnapShot.getText(0,_textSnapShot.charCount)!="")
{
if(_isCoveredTextSelectedAtAnyInstance)
{
_textSnapShot.setSelected(_beginIndex,_endIndex+1,false); //this is the global variable to the class
}
else
{
_textSnapShot.setSelectColor(0xfff100);
_textSnapShot.setSelected(_beginIndex,_endIndex+1,true);
}
if(saveHighlight)
{
countHighlightedSegments();
}
}
}
Code I use to redraw previously drawn highlight when I return to the page:
public function showHighlights(textSnapShot:TextSnapshot,currentPageNum:int):void
{
if(currentPageNum >= 0)
{
textSnapShot.setSelected(0,textSnapShot.charCount,false);
var pageVO:PageVO = _model.eBookVO.eBookPagesVO.getItemAt(currentPageNum) as PageVO;
var objColl:ArrayCollection = new ArrayCollection();
objColl.source = pageVO.highLightSelection;
for(var i:int=0;i<objColl.length;i++)
{
var highlightVO:HighlightVO = new HighlightVO();
highlightVO.beginIndex = objColl.getItemAt(i).beginIndex;
highlightVO.endIndex = objColl.getItemAt(i).endIndex;
setHighlightedSegment(textSnapShot,highlightVO.beginIndex,highlightVO.endIndex);
}
}
}
private function setHighlightedSegment(textSnapShot:TextSnapshot,beginIndex:int,endIndex:int):void
{
textSnapShot.setSelectColor(0xfff100);
textSnapShot.setSelected(beginIndex,endIndex,true);
}
Looking forward to your support to resolve this issue.
Regards,
JS
What you're doing is not 'caching', it's preloading previous/next pages. Also, what you're doing is really bad practice. I'm not even sure why you're casting these things into MovieClips unless the SWFs are that; if they're Flex SWFs, they'll be UIComponents. I would recommend you rethink your approach. I wouldn't even bother copying the children or anything over. Once the browser loads a SWF, it is now part of the browser cache, meaning the next time it's requested, it won't actually download it.
If you want to 'cache' your SWFs for a quicker next/previous page flipping, I would recommend you use something like SWFLoader to just load the other SWFs without actually adding it to the display, then removing it from memory. That will cache the SWFs for you in the browser. Then when the user click previous/next, just change the url of the main swfloader of the currently displayed page and it will load it up really quickly. No downloading since it's already cached, it will just need to instantiate.
How can I copy or duplicate the bitmapdata from a mx:image component?
I need to display the same image in multiple screens of my application and don't want to have to download the image multiple times.
I could just use a urlrequest to download the image as a bitmap and copy that but I like the way you can can just set the source of the image component.
Image extends SWFLoader which has a content property that will contain the Bitmap object that was loaded. Wait for the image to load, cast the content to Bitmap and read its bitmapData
public function imageLoadCompleteHandler(e:Event):void
{
var bitmap:Bitmap = img.content as Bitmap;
if(bitmap == null) {
trace("loaded content is not an image");
return;
}
bmpData = bitmap.bitmapData;
//hurray..!
}
Actually after reading the message above (and trying stuff out) I think this is wrong. The Complete listener fires on my second image so I guess it is loading it twice. Oh well.
I couldn't place the whole Flex doc, but this seemed to work. I added this to the Application tag: applicationComplete="Run();"
The following is wrapped in a mx:Script tag:
import mx.controls.Image;
private function Run():void
{
var i:Image = new Image();
i.source = first.source;
addChild(i);
}
And this is just a Image outside of the script tag:
<mx:Image x="12" y="125" source="e53c04a51d5992fb77ab1e20c45ddc9f.jpeg" id="first" />
I also tried this after setting the i source:
first.source = null;
Just to see what happens, the i image keeps it's source
Is it possible to get the bitmap data from a component using ActionScript?
I dynamically load an image.
onComplete I create a Flex Image component and add the loaded image to the source
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void
{
var image:Image = new Image();
image.x = 0;
image.y = 0;
image.source = e.currentTarget.content;
canvas.addChild(image); // canvas is already added as an MXML element.
}
Later I want to create a new Image component and get the bitmapData from the first Image.
I have tried this
canvas.getChildAt(0)
Which seems to give me the Image, but I can not figure out how to get the bitmap data.
canvas.getChildAt(0).bitmapData;
gives me a compile error "... undefined property"
Does anyone know how ot get the bitmap data so I can use it in my new Image component?
Thanks in advance,
Ran
Check out ImageSnapshot.captureBitmapData()
http://livedocs.adobe.com/flex/3/langref/mx/graphics/ImageSnapshot.html
Cliff's answer will give you a screenshot of the Image; to get the underlying BitmapData for the image without doing a screenshot, you can try
Bitmap(image.content).bitmapData
This should avoid any filters as well.
This should do it.
var bd:BitmapData = new BitmapData(myComponent.width, myComponent.height, true, 0);
bd.draw(myComponent);
I've reviewed all the documentation and Google results surrounding this and I think I have everything setup correctly. My problem is that the symbol is not appearing in my app. I have a MovieClip symbol that I've embedded to my Flex Component. I need to create a new Image control for each item from my dataProvider and assign this embedded symbol as the Image's source. I thought it was simple but apparently not. Here's a stub of the code:
[Embed(source="../assets/assetLib.swf", symbol="StarMC")]
private var StarClass:Class;
protected function rebuildChildren():void {
iterator.seek( CursorBookmark.FIRST );
while ( !iterator.afterLast ) {
child = new Image();
var asset:MovieClipAsset = new StarClass() as MovieClipAsset;
(child as Image).source = asset;
}
}
I know the child is being created because I can draw a shape and and that appears. Am I doing something wrong? Thank you!
You should be able to simply set child.source to StarClass:
child = new Image();
child.source = StarClass;
See the MovieClipAsset Language Reference for more details:
you rarely need to create MovieClipAsset instances yourself
because image-related properties and
styles can be set to an
image-producing class, and components
will create instances as necessary.
For example, to set the application
background to this animation, you can
simply write the following:
<mx:Application backgroundImage="{backgroundAnimationClass}"/>