Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Views
Replies
Total Likes
Hi,
I'm also having problems with the complex object transfer – any advice/help would be great!
I’m following the AFCS ComplexObjectTransfer example, stripping out what I don’t need and making small additions. I want to save a complex object ('HCOT_DataClass’) that contains a String, a Date, and a BitmapData. The strings and dates serialize properly; the BitmapData does not. I've tried the following cases. Can anyone suggest how this is supposed to work, or what else I might be missing or might need to try? Thanks!
1) in the HCOT_DataClass object: (SEE NOTE BELOW)
public var bmd:BitmapData;
public var date:Date;
public var str:String;
when registering the object
registerBodyClass(HCOT_DataClass);
in onClick():
var bmd1:BitmapData = new BitmapData(100, 100, true, 0x00000000);
data = new HCOT_DataClass(date, creator, bmd1);
in onItemReceive():
var data:HCOT_DataClass = p_evt.item.body as HCOT_DataClass;
--> in this case, when the object is received, data.bmd is null.
2) same as #1, but when registering the object
registerBodyClass(HCOT_DataClass);
registerBodyClass(BitmapData);
--> in this case, when the object is received, data is null.
3) in the HCOT_DataClass object:
public var bmd:HCOT_ImageClass;
public var date:Date;
public var str:String;
in the HCOT_ImageClass object:
public var image:BitmapData;
when registering the object
registerBodyClass(HCOT_DataClass);
registerBodyClass(HCOT_BmdClass);
in onClick():
var bmd1:BitmapData = new BitmapData(100, 100, true, 0x00000000);
var image:HCOT_ImageClass = new HCOT_ImageClass(bmd1);
data = new HCOT_DataClass(date, creator, image);
in onItemReceive():
var data:HCOT_DataClass = p_evt.item.body as HCOT_DataClass;
--> in this case, when the object is received, data is valid, and bmd.image is null.
4) same as #3, but when registering the object
registerBodyClass(HCOT_DataClass);
registerBodyClass(HCOT_BmdClass);
registerBodyClass(BitmapData);
--> in this case, when the object is received, data is null.
NOTE: My HCOT_DataClass looks like:
[Bindable] public class HCOT_DataClass extends EventDispatcher
because I need to store this in an arraycollection (for use in a display grid), and because I was getting warnings about not being able to convert objects (and I found something about needing to make the class an extension of EventDispatcher).
Views
Replies
Total Likes
We'd hit this issue as well, building the Collab Pic Viewer example. As it turns out, BitmapData is not de/serializable by the Flash Player to/from AMF. See this article for more details, it's not specific to AFCS, and there are workarounds.
nigel
Views
Replies
Total Likes
Hi,
The BitMapData contains within in the Rectangle class and that has Point class. Unfortunately, when you try to get the data onItemReceive , you get a byteArray which if you assign as BitMapData will return as null as seen by you.
One of the ways is to pass the width and height of the bitmapdata along with the byteArray object by calling getPixels(), and recreate it on the receiving client side by using the width, height and the byteArray.
In one of our examples. the collabpicviewer in examples folder , if you look at the CollabPictureViewer.mxml file , you can get some help.
I can copying one relevant example I ran by modifying the ComplexObjectTransfer example locally for your problem , This might help you in showing ways to send the BitMapData.
Hope this helps.
Thanks
Hironmay Basu
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
xmlns:rtc="AfcsNameSpace">
<mx:Script>
<![CDATA[
import com.adobe.rtc.messaging.MessageItem;
import com.adobe.rtc.events.CollectionNodeEvent;
import com.adobe.rtc.sharedModel.CollectionNode;
import flash.display.BitmapData;
private var collectionNode:CollectionNode ;
private var bitdata:BitmapData ;
public var mydata:UserProfile ;
private function onCreationComplete():void
{
//Creating and subscribing the collection node to pass the message
collectionNode = new CollectionNode();
collectionNode.sharedID = "complexObject6" ;
collectionNode.connectSession = cSession ;
//collectionNode.subscribe();
collectionNode.addEventListener(CollectionNodeEvent.SYNCHRONIZATION_CHANGE,onSyncChange);
collectionNode.addEventListener(CollectionNodeEvent.ITEM_RECEIVE,onItemReceive);
collectionNode.subscribe() ;
/********Important*****************/
//Registering all the complex object classes using MessageItem.registerBodyClass(p_class:Class) method
MessageItem.registerBodyClass(UserProfile);
MessageItem.registerBodyClass(BitmapData);
MessageItem.registerBodyClass(Rectangle);
MessageItem.registerBodyClass(Point);
bitdata = new BitmapData(100, 100, true, 0x00000000);
mydata = new UserProfile();
mydata.width = 10 ;
mydata.height = 10 ;
mydata.bitdata = bitdata.getPixels(bitdata.rect); ;
}
/**
* Handler for synchronization change.
*/
private function onSyncChange(p_evt:CollectionNodeEvent):void
{
if ( collectionNode.isSynchronized ) {
if ( !collectionNode.isNodeDefined("complexObjectNode")) {
collectionNode.createNode("complexObjectNode");
}
}
}
/**
* Publishes the UserProfile object within the message by registering the objects as described above.
* We have to no longer use createValueObject and readValueObject for passing complex objects.
*/
private function publish():void
{
collectionNode.publish Item(new MessageItem("complexObjectNode",mydata));
}
/**
* When we receive the item, update the user interface.
*/
private function onItemReceive(p_evt:CollectionNodeEvent):void
{
var userProf:UserProfile = p_evt.item.body as UserProfile ;
var bitMapData:BitmapData=new BitmapData(userProf.width, userProf.height);
var byteArray:ByteArray = userProf.bitdata as ByteArray;
var bitMap:Bitmap=new Bitmap(toBitmapData(bitMapData.width, bitMapData.height, byteArray));
}
protected function toBitmapData(p_width:Number, p_height:Number, p_byteArray:ByteArray):BitmapData
{
var bitMapData:BitmapData=new BitmapData(p_width, p_height);
p_byteArray.position=0;
for(var i:uint=0; i < bitMapData.width; i++) {
for(var j:uint=0; j < bitMapData.height; j++) {
bitMapData.setPixel(i, j, p_byteArray.readUnsignedInt());
}
}
return bitMapData;
}
/**
* Clicking on the Send User Data button creates the object and calls publish() to publish the data.
*/
private function onClick(p_evt:MouseEvent):void
{
publish();
}
]]>
</mx:Script>
<!--
You would likely use external authentication here for a deployed application;
you would certainly not hard code Adobe IDs here.
-->
<rtc:AdobeHSAuthenticator
id="auth"
userName="hironmay_b@yahoo.com"
password="hiruana80" />
<rtc:ConnectSessionContainer id="cSession" authenticator="{auth}" width="100%"
height="100%" roomURL="http://connect.acrobat.com/cocomobasu/myfourthroom" creationComplete="onCreationComplete()" >
<mx:VBox>
<mx:HBox width="100%" paddingTop="20">
<mx:Spacer width="100" />
<mx:Button label="Enter User Data" click="onClick(event)" />
</mx:HBox>
</mx:VBox>
</rtc:ConnectSessionContainer>
</mx:Application>
-------------------------------------------------
And The Userrofile class is
// ActionScript file
package
{
import flash.utils.ByteArray;
/**
* UserProfile describes the user's profile details.
*
*/
public class UserProfile
{
public var bitdata:ByteArray ;
public var width:Number ;
public var height:Number ;
}
}
Views
Replies
Total Likes
Hi Nigel, Hironmay
Thanks for your quick, excellent responses, this is very helpful. I can now see how to do this.
I have some follow-up questions. What I'd *really* prefer to do is used the SharedCollection as the basis for what I'm doing. That is, I'd like to use AFCS to store a collection of objects, which include Date, String, and (now) a serialized version of the BitmapData. Users would login, and see a list of images (with descriptions) that others had previously created. Right now, I'm basing off of ComplexObjectType and trying to keep a local ArrayCollection, which is less desirable and less efficient.
In SharedCollection.as, it notes that class types aren't preserved (which led me to ComplexObjectType in the first place).
However, there is a cryptic follow-on (well, at least to me) there:
"However, by specifying the <code class="property">itemClass</code> property of the SharedCollection, the collection will automatically create instances of the appropriate class and transfer any properties from the received item to the typed objects."
My questions:
1) What does this mean, as far as implementation?
2) Should I go that route, or should I just try to serialize to ByteArray, and then to String, and then base things off of the SharedCollection example. It looks (from using the AFCS viewer) like the AFCS 'prefers' String, Number, Boolean, and combinations of those.
3) Or, is there a better way?
Regards,
- Chris
Views
Replies
Total Likes
Hi,
Yes , you can use shared collection's arrayCollection to store your objects containing byteArray, Numbers and Strings. In fact, the collabpicviewer example exactly does that. The CollabPicViewer.mxml file has the revelant code where it uses the sharedcollection to store and send data.SharedCollection basically extends a ListCollectionView and whatever you assign to its dataProvider will be kept and you can use it for storing your objects instead of maintaining one yourself.
For String, Numbers, Boolean if you have them inside a class in general, you just need to do MessageItem.registerBodyClass(ClassName) and you don't need to do anything seperattely. I will say take a look at the example and run it and see how sharedCollection is used to store and retrieve data. It will answer lot of your queries. In fact , lot of the code I pasted in my last reply was taken from it.
Hope this helps.
Thanks
Hironmay Basu
Views
Replies
Total Likes
Hi Hironmay,
Got it, sorry for not looking more deeply into this at first. I hadn't paged through 0.92 yet when I replied. I have now, and I've integrated CollabPicViewer, and most things are working very nicely now, thanks.
The final issue I'm having is one with uploading (as a shared file) a Bitmap that I've created (e.g. from a UIComponent). Using fileReference, I don't see any good way to create a "temp" file, unless I present the user a savedialog, which I really really don't want to do. Essentially, I want to directly share a Bitmap that I have created within the application - not one from the upload() / onFileselect() / onFileComplete() / byteImageLoaded() sequence.
I tried short-circuiting all this, here's a simple test example:
/*** Test function, just for uploading bitmapdata. ***/
public function uploadImage():void
{
var bmpd:BitmapData = new BitmapData(100, 100, true, 0x00000000);
var rect:Rectangle = new Rectangle(20, 20, 40, 40);
bmpd.fillRect(rect, 0xFF0000FF);
// Fixme: something along these lines, with a save dialog for the PNG file, could work for AIR…
//var pngenc:PNGEncoder = new PNGEncoder();
//var imgByteArray:ByteArray = pngenc.encode(bmpd);
//var fl:FileReference = new FileReference();
_fileReference = new FileReference(); // sure would like a way to ask for a 'sandbox temp file'
_fileReference.name = "test.bmp";
_filePublisher.uploadFileReference(_fileReference, _fileReference.name);
_sharedCollectionObject = new Object();
_sharedCollectionObject["fileName"] = _fileReference.name;
var actualImage:ByteArray = new ByteArray();
//Explore alternative ways to create a Thumbnail
var sourceBMP:Bitmap = new Bitmap(bmpd);
var thumbNailBitMapData:BitmapData = new BitmapData(128,80);
var matrix:Matrix = new Matrix();
var date:Date = new Date(); // get current date
//make the thumbnail 128px X 80px
matrix.scale(128/sourceBMP.width,80/sourceBMP.height);
thumbNailBitMapData.draw(sourceBMP.bitmapData,matrix);
_sharedCollectionObject["width"] = 128;
_sharedCollectionObject["height"] = 80;
_sharedCollectionObject["bitMapData"] = toByteArray(thumbNailBitMapData);
_sharedCollectionObject["date"] = date.toLocaleString();
// Dump the Thumbnail info into the shared Collection
_sharedCollection.addItem(_sharedCollectionObject);
_sharedCollectionObject = null;
}
This 'works'; I get a bitmap displayed within the app (e.g. coverflow container). Unfortunately, double-clicking on this bitmap gives an error in updateSharedValue, at
var fileDescriptor:FileDescriptor=getFileDescriptor(fileName);
since fileDescriptor is null.
I could move to AIR, and create a local file from my clip, and then upload that. But under AIR, the collabPicViewer app doesn't seem to work.
I could go back to the approach you originally suggested, but then it seems like I will lose all of the file-based functionality, which is very nice. This collabPicViewer functionality is exactly what I'm looking for.
Any suggestions? Is there a way to patch up getFileDescriptor and the _fileDescriptors?
Thanks,
- Chris
Views
Replies
Total Likes
You may want to use the BinaryPublisher instead of FilePublisher.
It works the same way but instead of passing a file reference object you pass a file name (whatever name you want your bitmap to be called) and a bytearray (the bits in your bitmap).
On the receiveing side you can use a BinarySubscriber, that will return you the bytearray.
Views
Replies
Total Likes
Unfortunately, you are correct that you need user action to begin a file upload - I haven't found any way around it. Show a dialog w/ a button or something, have the user click it to begin upload.
nigel
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies