Sunday, November 28, 2010

Blob data limit on Google Appengine with Android

Image files are pretty headache while I am posting data into datastore on Google Appengine as blob.
While I am searching solution, Google appengine java user group already had tons of discussion of it and different ways to resolve the issue since google app engine allows unto 1MB data store is allowed.
My solution was pretty simple although there are a few mistakes.
This was my first step that I overlooked the issue.

1. user takes photos
2. user send photos to appengine
3. appengine gets data and resize photos
4. store resize photos into datastore as blob and post data using Gdata API

step 3, resize was to prevent 1MB data limit and handle it properly. Unfortunately, when application can't resize if original photo data is greater 1MB already. Yes, I got this issue and pull my hairs to resolve it.
Believe or not, I didn't want to resize my data on client side app. but, this issue didn't give any choice so that I added addition step on before i post data into appengine.

1. user takes photos
2. application checks file size if file size is greater than 1MB, app resize image.
3. user send photos to appengine
4. appengine gets data and resize photos
5. store resize photos into datastore as blob and post data using Gdata API

Yes, this addition step resolved the issue. See the below code step to resolve the issue.

1. User takes photos
private function btn_onClickPhoto():void{
if (CameraUI.isSupported)
{
var cameraUI:CameraUI = new CameraUI();
cameraUI.addEventListener(MediaEvent.COMPLETE, function(event:MediaEvent):void {
i.source = event.data.file.url;
photoURL = event.data.file.url;
file = event.data.file;
});
cameraUI.launch(MediaType.IMAGE);
}
else
{
l.text = "CameraUI not supported";
}

2/3 Android application photo resize. Then, send to GOOGLE AppEngine
private function resizePhoto():File{
var bmpd:BitmapData = new BitmapData(2000,1800);
bmpd.draw(iTrack);
var jPEGEncoder:JPEGEncoder = new JPEGEncoder(80);
var imageByteArray:ByteArray = jPEGEncoder.encode(bmpd);


var fl:File = File.applicationStorageDirectory.resolvePath(photoURL);


var fs:FileStream = new FileStream();
try{
fs.open(fl,FileMode.WRITE);
fs.writeBytes(imageByteArray);
fs.close();
}catch(e:Error){
trace(e.message);
}


return fl;
}

private function btn_onClickGoogleUpload():void{
var uploadURL:URLRequest = new URLRequest();
uploadURL.url = "YOUR GOOGLE APPENGINE URL";
var filref:FileReference;


file = new File(photoURL);
if(file.size < 1000000){
filref = FileReference(file);
}
else{
filref = FileReference(resizePhoto());
}


filref.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,uploadCompleteDataHandler);
filref.addEventListener(Event.COMPLETE, completeHandler);
filref.addEventListener(Event.CANCEL, cancelHandler);

uploadURL.method = URLRequestMethod.GET;

filref.upload(uploadURL);
}

<s:Image id="iTrack" width="100%" height="100%" scaleMode="stretch" />

4 Google AppEngine application code to resize photos.

ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImage(contentBytes);

int width = oldImage.getWidth();
int height = oldImage.getHeight();

int MAZ_SIZE = 3000;

if(width > MAZ_SIZE || height > MAZ_SIZE){
width = (int) (width*0.5);
height= (int) (height*0.5);
}


Transform resize = ImagesServiceFactory.makeResize(width, height);
Image image = imagesService.applyTransform(resize, oldImage, ImagesService.OutputEncoding.JPEG);

4 Post to PICASA using GData API
private void addToPicasa(String blobKey, String id) {
ImagesService imagesService = ImagesServiceFactory.getImagesService();
BlobKey bk = new BlobKey(blobKey);
Image oldImage = ImagesServiceFactory.makeImageFromBlob(bk);
Transform resize = ImagesServiceFactory.makeResize(1024, 768);
Image image = imagesService.applyTransform(resize, oldImage, ImagesService.OutputEncoding.JPEG);


PicasawebService myService = new PicasawebService("PICTURESHOP");
try {
myService.setUserCredentials("mypicasaaccount@gmail.com", "my.password");
String albumid = "5495486978942507441";

URL albumPostUrl = 


PhotoEntry myPhoto = new PhotoEntry();
myPhoto.setTitle(new PlainTextConstruct(id));


MediaSource myMedia = new MediaByteArraySource(image.getImageData(), "image/jpeg");
myPhoto.setMediaSource(myMedia);


PhotoEntry returnedPhoto = myService.insert(albumPostUrl, myPhoto);            
} catch (Exception e) {
logger.error(e);
}
}

1 comments:

  1. your code is unique over the internet and very useful! thank you!

    ReplyDelete