I'm trying to develop an app for iOS using flash CS6. I have imported an image using a loader. I now want to be able to create a duplicate instance of the loaders bitmap data and have been trying:
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("cats.jpg"));
my_loader.scaleX = 0.2;
my_loader.scaleY = 0.2;
addChild(my_loader);
var duplicationBitmap:Bitmap = new Bitmap(Bitmap(my_loader.content).bitmapData);
duplicationBitmap.x = 300;
duplicationBitmap.y = 300;
addChild(duplicationBitmap);
Unfortunately when I test the code it doesn't work. I get the initial loaded image but not the duplicate, I also get an output error of:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main()
Any ideas would be greatly appreciated.
Bitmap(my_loader.content) is a DisplayObject, not neccessary a Bitmap, that gives you the nullpointer error.
For copying bitmapData, you should use BitmapData.clone().
You can draw the loader on to a BitmapData object when the loader initializes, then simply use it to create as many Bitmap objects as you need when the loader completes.
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
var loaderBitmapData:BitmapData;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, loaderInitEventHandler);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteEventHandler);
loader.load(new URLRequest("eXO-01.png"));
function loaderInitEventHandler(event:Event):void
{
loader.contentLoaderInfo.removeEventListener(Event.INIT, loaderInitEventHandler);
loaderBitmapData = new BitmapData(event.target.width, event.target.height);
loaderBitmapData.draw(event.target.loader as Loader);
}
function loaderCompleteEventHandler(event:Event):void
{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderCompleteEventHandler);
createBitmaps();
}
function createBitmaps():void
{
var image1:Bitmap = new Bitmap(loaderBitmapData);
image1.scaleX = image1.scaleY = 0.2;
var image2:Bitmap = new Bitmap(loaderBitmapData);
image2.scaleX = image2.scaleY = 0.4;
image2.x = image2.y = 100;
addChild(image1);
addChild(image2);
}
Related
It's not going into the .then afterwards, and it's not throwing any error.
Here's my calling code:
function loadPage(base64Data, pageIndex) {
var pdfData = base64ToUint8Array(base64Data);
// this gets hit
PDFJS.getDocument(pdfData).then(function (pdf) {
// never gets here
pdf.getPage(pageIndex).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('pdfPage');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({ canvasContext: context, viewport: viewport });
});
});
}
function base64ToUint8Array(base64) {
var raw = atob(base64); // convert base 64 string to raw string
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
At one point it worked. When I step through it in the debugger, I can step into PDFJS.getDocument but that's way over my head.
My base64Data looks like JVBERi0x...g==. It's a base64 encoded pdf document.
To solve this, I had to add
PDFJS.disableWorker = true;
to the beginning of my loadPage function.
From View PDF files directly within browser using PDF.js,
PDF.js uses Web Workers concept of HTML5 internally to process the
request. If this statement is set to false, it creates an instance of
Web workers. Web Workers run in an isolated thread. For more
information on web workers; please refer
http://www.html5rocks.com/en/tutorials/workers/basics/
Promise is missing in your code. Here how i fixed this probelm:
PDFJS.getDocument(pdfData).promise.then(function (pdf) {
// do your stuff
});
I'm trying to create a box on canvas that reacts to MouseClick events using Dart and StageXL. My code is as follows:
import 'dart:html' as html;
import 'package:stagexl/stagexl.dart' as sxl;
void main() {
var canvas = html.querySelector('#canvas');
setCanvasFullScreen(canvas);
var stage = new sxl.Stage(canvas);
var renderLoop = new sxl.RenderLoop();
renderLoop.addStage(stage);
var rect = new sxl.Shape();
rect.graphics.rect(80, 50, 100, 100);
rect.graphics.fillColor(sxl.Color.Crimson);
// rect.on(sxl.MouseEvent.CLICK).listen(react);
rect.addEventListener(sxl.MouseEvent.CLICK, react);
stage.addChild(rect);
}//end main
void react(sxl.MouseEvent event){
var w = html.window;
w.alert("I'm clicked!");
}//end onClick
void setCanvasFullScreen(canv) {
var w = html.window;
// w.alert("Holla!!!");
int _width = w.innerWidth as int;
int _height = w.innerHeight as int;
canv.setAttribute('width', '$_width');
canv.setAttribute('height', '$_height');
}
I've tried both on(MouseEvent.CLICK).listen(react); and addEventListener(MouseEvent.CLICK, react); without success there is no reaction. I'm using Dart Editor & SDK version 1.8.5 and debugging on the default Dartium browser.
Any help is appreciated.
After some search on the internet I found this link on StageXL forum that properly explained why it did not work. So I've changed the line:
var rect = new sxl.Shape();
to:
var rect = new sxl.Sprite();
and it reacts nicely.
Hope this is helpful to someone.
I have an app that is built from Flash CS5.5, exported using AIR3.1 and distributed through the Enterprise setup from Apple (allows me to bypass appstore approval).
I'm now trying to have a PDF (generated using AlivePDF) exported somehow into the iPad, either into iBooks or just have it opened in Safari.
This is what I'm using for my desktop version of the app. Although the scripting is very messy it gets the job done. I just don't know how to convert this over and make it work on an iPad
//Populate listbox component from array
function noEmpty(item:*, index:int, array:Array):Boolean{
return item != undefined;
}
for(var i:int = 0; i < MovieClip(root).selectedProducts.length; i++) {
if(MovieClip(root).selectedProducts[i] != undefined){
selectedProductsText.dataProvider.addItem({label: MovieClip(root).selectedProducts[i]});
}
}
var myTextFormat:TextFormat = new TextFormat();
myTextFormat.size = 20;
myTextFormat.font = "Arial";
myTextFormat.color = 0x000000;
myTextFormat.leftMargin = 30;
selectedProductsText.rowHeight = 40;
selectedProductsText.setRendererStyle("textFormat", myTextFormat);
//AlivePDF, generate PDF
import org.alivepdf.pdf.PDF;
import org.alivepdf.layout.Orientation;
import org.alivepdf.layout.Size;
import org.alivepdf.layout.Unit;
import org.alivepdf.display.Display;
import org.alivepdf.saving.Method;
import org.alivepdf.fonts.FontFamily;
import org.alivepdf.fonts.Style;
import org.alivepdf.colors.RGBColor;
import com.adobe.images.*;
function convertString(_value:String):String
{
var returnString:String = "";
var _chr:String = String.fromCharCode(13);
var tempArray:Array = _value.split(_chr);
for(var i:uint = 0; i < tempArray.length; i++)
{
returnString += tempArray[i] + "\n";
}
return returnString;
}
var pdf:PDF = new PDF();
pdf.setDisplayMode (Display.REAL);
pdf.addPage();
pdf.writeText(7, convertString( MovieClip(root).selectedProducts.filter(noEmpty).join('\n') ));
var buffer:ByteArray = pdf.save(Method.LOCAL);
var file:FileReference = new FileReference();
//save PDF button
btnPdf.addEventListener( MouseEvent.CLICK, generatePDF );
function generatePDF ( e:MouseEvent )
{
file.save(buffer, "Product Selection List.pdf");
}
Having done some work with AIR for iOS I would say your issue will be that you need to change how the file is saved and stored on the device.
You need to save the file to the apps storage directory with something like this that I used to store a jpg image:
f = File.documentsDirectory.resolvePath(imagename+".jpg");
stream = new FileStream();
stream.open(f, FileMode.WRITE);
j = new JPGEncoder(80);
bytes = new ByteArray();
bytes = j.encode(snapShot.bitmapData);
stream.writeBytes(bytes, 0, bytes.bytesAvailable);
stream.close();
I'm not sure how or if it's even possible through AIR to send the pdf to iBooks. You could use StageWebView within your app though to display the PDF.
I'm loading an SWF animation and want to display it in multiple places concurrently, but the only way I could figure out how to do that is to load it every time I display it, as seen here:
private function playSounds():void {
for (var i:Number = 0; i < 14; i++)
{
for (var a:Number = 0; a < 16; a++)
{
if (boxes[i][a].x == linePos && boxes[i][a].selected == true && played[i][a] == false)
{
played[i][a] = true;
MovieClip();
var swf:URLRequest = new URLRequest("../assets/glow2.swf")
var glow:Loader = new Loader()
glow.load(swf)
glow.x = boxes[i][a].x - 25*0.7;
glow.y = boxes[i][a].y - 27*0.7;
glow.scaleX = 0.7;
glow.scaleY = 0.7;
this.addChild(glow);
glows.push(glow)
glowTime.push(0)
var sc:SoundChannel = new SoundChannel();
sc = (sounds[i] as Sound).play();
}
}
}
}
This is very very slow when it's being displayed more than, say, 5 times at once so I'm wondering if there's a way to only have to load it once and use it in multiple places.
You have the content property of the Loader.
Thus, load once, use the content many times.
edit: you may want to add a listener to know when the loading completes, before you use the loaded content:
addEventListener(Event.COMPLETE, completeHandler);
edit2:
var mc1:MovieClip = new MovieClip();
var mc2:MovieClip = new MovieClip();
var my_Loader:Loader = new Loader();
mc1.addChild(my_Loader);
mc2.addChild(my_Loader);
(haven't tried though).
One quick workaround is to create a second loader and pass the loaded bytes to that via the loadBytes() method:
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE,ready);
l.load(new URLRequest("../assets/glow2.swf"));
function ready(event:Event):void{
var mc:MovieClip = event.currentTarget.content as MovieClip;
var clone:Loader = new Loader();
clone.loadBytes(event.currentTarget.bytes);
addChild(mc);
addChild(clone);
clone.x = 100;
}
This will work in most cases. In some cases you should be able to get away with something as simple as:
var clone:MovieClip = MovieClip(new mc.constructor());
And there is also a 3rd option: 'blitting' your moviclip, which means you'll store one or more (depending how many MoveClip frames you need to cache) of BitmapData objects in memory which will draw() from the source MovieClip you want to draw (in multiple locations at the same time).
The loadBytes approach achieves what the question suggests: creates a copy of the Loader, so it re-uses the bytes loaded, but initializes new content, so uses memory for that.
If this is not what you need, caching the MovieClip using BitmapData is your best bet.
i use the following code:
protected function videoDisplay_playheadUpdateHandler(event:mx.events.VideoEvent):void
{
if(!captured && videoDisplay.playheadTime>=0){
capture();
}
}
private function capture():void
{
var bmpData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bmpData.draw(videoDisplay);
captured = true;
store(...); //????????
}
in order to capture a frame from a videoDisplay object
1) is it correct or am i doing something wrong?
2) what can i do to store the bmpData as .jpg at my computer?
i am using flex4.5 and it is an air app...
any ideas??
Thanks in advance!!
The following code should help you
var jpegEncoder:JPEGEncoder = new JPEGEncoder(90);
var jpgSource:BitmapData = new BitmapData(videoDisplay.width,videoDisplay.height);
jpgSource.draw(this);
var fileReference:FileReference = new FileReference();
fileReference.save(jpegEncoder.encode(jpgSource),"videoImage.jpg");
To use jpeg encode you need to have to import
import mx.graphics.codec.JPEGEncoder;
The above changes should be enough to allow the user to take a snapshot of a running video.
Please note, that with this the user will be prompted to select the location of the file.
Incase you want a silent save, let me know, I will put up the required code.
Somewhere in your application keep an image tag as follows.Most apt place should be just below the video.
<mx:Image scaleContent="true" width="150" height="120" maintainAspectRatio="false" id="myScaledSnapshot"/>
Now with this done, do the following changes in your code:
private function capture(filename:String):void
{
var bitmapData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bitmapData.draw(videoDisplay,new Matrix());
var bitmap : Bitmap = new Bitmap(bitmapData);
var jpg:JPEGEncoder = new JPEGEncoder();
var ba:ByteArray = jpg.encode(bitmapData);
myImageSnapshot.source=ba;
var jpegEncoder:JPEGEncoder = new JPEGEncoder(50);
var imageSnapshot:ImageSnapshot = ImageSnapshot.captureImage(this.myImageSnapshot,90,jpegEncoder);
var imageByteArray:ByteArray = imageSnapshot.data;
var newImage:File = File.desktopDirectory.resolvePath("KioskThumbs/"+filename+".jpg");
fileStream = new FileStream();
fileStream.open(newImage, FileMode.UPDATE);
fileStream.writeBytes(imageByteArray);
fileStream.close();
captured = true;
}
The above code really doesnt do anything special.
Its just using an image 'component' from flex, making it do the work for scaling the Video image, then taking the snapshot of this resized image component, and then writing it into a file.
My capture at last is:
private function capture(filename:String):void
{
var bitmapData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bitmapData.draw(videoDisplay,new Matrix());
var bitmap : Bitmap = new Bitmap(bitmapData);
var jpg:JPEGEncoder = new JPEGEncoder();
var ba:ByteArray = jpg.encode(bitmapData);
var newImage:File = File.desktopDirectory.resolvePath("KioskThumbs/"+filename+".jpg");
fileStream = new FileStream();
fileStream.open(newImage, FileMode.UPDATE);
fileStream.writeBytes(ba);
fileStream.close();
captured = true;
}
it works fine except the fact that i want to scale the photo lets say to 150 width 120height and not BitmapData(videoDisplay.width,videoDisplay.height); what can i do to solve that?
Thanks a lot all of you!