I am trying to capture a still frame from an (any) external swf file, by using my own flash movie as a proxy to load it and hand information regarding the Stage onto javascript. I want to keep it as wide compatible as possible, so I went with AS2 / Flash 8 for now.
The script works fine in the Flash debugger, i.e. the
trace(flash2canvasScreenshot.getPixel(w, h).toString(16));
returns the correct pixel color, where as:
ExternalInterface.call("sendToJS",flash2canvasScreenshot.getPixel(w, h).toString(16));
in the published movie doesn't.
This method can obviously be quite slow for large flash (dimension wise) movies, as it iterates every single pixel. If someone has any better methods in mind, feel free to share, but as said, the problem I am facing is that I am getting differentiating results in debugging and publishing, with the pixel information not getting fetched when published.
import flash.display.BitmapData;
import flash.external.*;
var myLoader:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadInit = function(target_mc:MovieClip)
{
var stageW = Stage.width;
var flash2canvasScreenshot:BitmapData = new BitmapData(stageW, Stage.height, false, 0x00000000);
var pixels:Array = new Array();
flash2canvasScreenshot.draw(element);
for (w = 0; w <= stageW; w++)
{
trace(flash2canvasScreenshot.getPixel(w, h).toString(16)); // this gives correct color value for the pixels in the debugger
ExternalInterface.call("sendToJS",flash2canvasScreenshot.getPixel(w, h).toString(16)); // this just returns the bitmap default color, 0 in this case.
/*
for (h = 0; h <= Stage.height; h++)
{
var pixel = flash2canvasScreenshot.getPixel(w, h).toString(16);
pixels.push(pixel);
}
*/
}
//ExternalInterface.call("sendToJS",pixels.toString());*/
};
myLoader.addListener(mclListener);
myLoader.loadClip("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf", 0);
//myLoader.loadClip("https://s.ytimg.com/yt/swfbin/watch_as3-vflJjAza6.swf", 0);
//myLoader.loadClip(_level0.flash2canvasurl, _root.mc);
There are few problems with the snippet you posted:
like the one Joey mentioned, but the one that stands out from my
point of view is the element variable which isn't defined
anywhere, so that either is a type o, or you're trying to draw an
undefined object.
You're drawing as soon as the load is finished, but the animation you're loading might start slightly later. Maybe take the snapshot a bit after the load is complete.
Haven't touched as2 for some time and don't remember how security issue are handled, but if you're swf is loading another swf from a different domain, then the domain hosting the swf you're loading should also have a crossdomain.xml policy file allowing you to access the content of the loaded swf. If you simply load and display a swf from another domain, that's fine. However, if you're trying to draw the swf using BitmapData, you're actually attempting to access pixel data from the content of that swf, therefore you would need permissions. If you have no control over the crossdomain policy file, you might need to use a server side script to copy/proxy the file over to a domain that can grant your loaded swf access.
Here's a simplified version of your snippet that works (sans the external interface/pixel values part):
var myLoader:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadInit = function(target_mc:MovieClip)
{
var pixels:Array = new Array();
setTimeout(takeSnapshot,2000,target_mc);
}
myLoader.addListener(mclListener);
myLoader.loadClip("http://www.bbc.co.uk/science/humanbody/sleep/sheep/reaction_version5.swf",1);
//myLoader.loadClip("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf", 1);
//myLoader.loadClip("https://s.ytimg.com/yt/swfbin/watch_as3-vflJjAza6.swf", 0);
function takeSnapshot(target:MovieClip):Void {
var flash2canvasScreenshot:BitmapData = new BitmapData(150, 150, false, 0x00000000);//tiny sample
flash2canvasScreenshot.draw(target);
_level1._alpha = 20;//fade the loaded content
_level0.attachBitmap(flash2canvasScreenshot,0);//show the snapshop. sorry about using _root
}
Here's a quick zoomed preview of the 150x150 snap:
Here's an as3 snippet to illustrate the security sandbox handling issue:
var swf:Loader = new Loader();
swf.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderComplete);
swf.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,loaderSecurityError);
swf.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,loaderIOError);
swf.load(new URLRequest("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf"),new LoaderContext(true));
function loaderComplete(event:Event):void{
setTimeout(takeSWFSnapshot,2000);
}
function loaderSecurityError(event:SecurityErrorEvent):void {
trace('caught security error',event.errorID,event.text);
}
function loaderIOError(event:IOErrorEvent):void{
trace('caught I/O error',event.errorID,event.text,'\tattempting to load\t',swf.contentLoaderInfo.url);
}
function takeSWFSnapshot():void{
var clone:BitmapData = new BitmapData(swf.content.width,swf.content.height,false,0);
try{
clone.draw(swf.content);
}catch(e:SecurityError){
trace(e.name,e.message,e.getStackTrace());
}
addChild(new Bitmap(clone));
}
HTH
My approach to this would be:
-Use AS3 for the reason lukevanin commented:
Just remember that AS3 can load an AS2 SWF, but an AS2 SWF cannot load
an AS3 SWF, so you actually achieve greater compatibility (with your
content) if you publish AS3
-Use a proxy file to fetch the swf file to get around sandbox violation issues (although if the swf loads external resources and uses relative paths it might get a bit more complex)
-Take a snapshot of the frame ( see George Profenza's solution )
-Encode the image using base64 and send that** to a JS method, and then decode to get the image.
** I'm pretty sure there are no size limitations...
Related
I am using Google Apps Script to create a page, on which I would like to embed maps. The maps themselves would be static, but the map could be different depending on other parameters (it’s a genealogy page, and I’d like to display a map of birth and death locations, and maybe some other map points, based on a selected individual).
Using Google’s Maps service, I know that I can create a map, with a couple points built in.
Function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600,400)
.addMarker('Chicago, Illinois') // markers would be based on a passed parm; this is just test data
.addMarker('Pocatello, Idaho');
// *** This is where I am looking for some guidance
return(); // obviously, I'm not returning a blank for real
}
Within the map class, there are a number of things I can do with it at this point.
I could create a URL, and pass that back. That appears to require an API account, which at this point, I do not have (and ideally, would like to avoid, but maybe I’ll have to do that). It also appears that I will run into CORB issues with that, which I think is beyond my knowledge (so if that’s the solution, I’ll be back for more guidance).
I could create a blob as an image, and pass that back to my page. I have tried this using a few different examples I have found while researching this.
Server Side
function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600,400)
.addMarker('Chicago, Illinois')
.addMarker('Pocatello, Idaho');
var mapImage = map.getAs("image/png");
// OR
// var mapImage = map.getBlob();
return(mapImage);
}
Page side
<div id=”mapDiv”></div>
<script>
$(function() {
google.script.run.withSuccessHandler(displayMap).getMapImage();
}
function displayMap(mapImage) {
var binaryData = [];
binaryData.push(mapImage);
var mapURL = window.URL.createObjectURL(new Blob(binaryData, {type: "image/png"}))
var mapIMG = "<img src=\'" + mapURL + "\'>"
$('#mapDiv').html(mapIMG);
}
</script>
The page calls getMapImage() on the server, and the return data is sent as a parm to displayMap().
var mapIMG ends up resolving to <img src='blob:https://n-a4slffdg23u3pai7jxk7xfeg4t7dfweecjbruoa-0lu-script.googleusercontent.com/51b3d383-0eef-41c1-9a50-3397cbe83e0d'> This version doesn't create any errors in the console, which other options I tried did. But on the page, I'm just getting the standard 16x16 image not found icon.
I’ve tried a few other things based on what I’ve come across in researching this, but don’t want to litter this post with all sorts of different code snippets. I’ve tried a lot of things, but clearly not the right thing yet.
What’s the best / correct (dare I ask, simplest) way to build a map with Google’s Map class, and then serve it to a web page?
EDIT: I added a little more detail on how the server and page interact, in response to Tanaike's question.
Modification points:
I think that in your script, Blob is returned from Google Apps Script to Javascript using google.script.run. Unfortunately, in the current stage, Blob data cannot be directly sent from from Google Apps Script to Javascript. I think that this might be the reason of your issue.
In this case, I would like to propose to directly create the data URL at the Google Apps Script side. When your script is modified, it becomes as follows.
Modified script:
Google Apps Script side:
function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600, 400)
.addMarker('Chicago, Illinois')
.addMarker('Pocatello, Idaho');
var blob = map.getAs("image/png"); // or map.getBlob()
var dataUrl = `data:image/png;base64,${Utilities.base64Encode(blob.getBytes())}`;
return dataUrl;
}
Javascript side:
$(function() {
google.script.run.withSuccessHandler(displayMap).getMapImage();
});
function displayMap(mapURL) {
var mapIMG = "<img src=\'" + mapURL + "\'>"
$('#mapDiv').html(mapIMG);
}
In your Javascript side, $(function() {google.script.run.withSuccessHandler(displayMap).getMapImage();} is not enclosed by ). Please be careful this.
Note:
In my environment, when I saw <div id=”mapDiv”></div>, this double quote ” couldn't be used. So if in your environment, an error occurs by <div id=”mapDiv”></div>, please modify ” to " like <div id="mapDiv"></div>.
Reference:
base64Encode(data)
I want to download and play m3u8 file which is on server machine. I am using following code to read and send m3u8 file to web server.
Browser is displaying contents of file instead of downloading it.
So please let me know that, how to download it.
if ((exportHandle = fopen(v3FileName, "a+")) != NULL) {
long end = 0, start = 0, pos = 0;
char* m3u8FileDataBuff = NULL;
fseek(exportHandle, 0, SEEK_END);
end = ftell(exportHandle);
fseek(exportHandle, 0, SEEK_SET);
start = ftell(exportHandle);
pos = end - start;
m3u8FileDataBuff = (char *) malloc(pos);
end = 0;
start = 0;
fread(m3u8FileDataBuff, 1, pos, exportHandle);
pClienCommunication->writeBuffer(m3u8FileDataBuff, pos);
free(m3u8FileDataBuff);
fclose(exportHandle);
}
Client's web browser is displaying the content, because the MIME type of the response is either nil, or something like "text/plain". Set up the http response header properly to indicate mime type of m3u8 file (application/x-mpegURL or vnd.apple.mpegURL).
The piece of code you provided does not seem to set anything around response header, just content.
Check available API of pClienCommunication->, or place where that originates, what are your options to adjust response header.
Or maybe it's possible to work-around this also by some rule set up in the web server serving the response, to set the MIME type for certain URLs, or based on the response content (but applying such rules on web server level is usually more costly then adjusting the response while being created in the C++ part).
And why is this tagged C++, when the code itself is C-like with all the problems of it. In modern C++ you never do things like "fclose(..)", because that is done in the destructor of the file wrapper class, so you don't risk the fclose will be skipped in case of some exception raised in fread, etc.
So in modern C++ these things should look somewhat like this:
{
SomeFileClass exportFile(v3FileName, "a+");
if (exportFile.isOK()) {
SomeFileContentBuffer data = exportFile.read();
pClienCommunication->writeBuffer(data.asCharPtr(), data.size());
}
}
So you can't forget to release any file handle, or buffer memory (as the destructors of particular helper classes will handle that).
I'm developing some webGL project in Unity that has to load some external images from a directory, it runs all fine in the editor, however when I build it, it throws a Directory Not Found exception in web console. I am putting the images in Assets/StreamingAssets folder, that will become StreamingAssets folder in the built project (at root, same as index.html). Images are located there, yet browser still complains about not being able to find that directory. (I'm opening it on my own computer, no running web server)
I guess I'm missing something very obvious, but it seems like I could use some help, I've just started learning unity a week ago, and I'm not that great with C# or JavaScript (I'm trying to get better...) Is this somehow related to some javascript security issues?
Could someone please point me in the right direction, how I should be reading images(no writing need to be done) in Unity WebGL?
string appPath = Application.dataPath;
string[] filePaths = Directory.GetFiles(appPath, "*.jpg");
According to unity3d.com in webGL builds everything except threading and reflection is supported, so IO should be working - or so I thought:S
I was working around a bit and now I'm trying to load a text file containing the paths of the images (separated by ';'):
TextAsset ta = Resources.Load<TextAsset>("texManifest");
string[] lines = ta.text.Split(';');
Then I convert all lines to proper path, and add them to a list:
string temp = Application.streamingAssetsPath + "/textures/" + s;
filePaths.Add(temp);
Debug.Log tells me it looks like this:
file://////Downloads/FurnitureDresser/build/StreamingAssets/textures/79.jpg
So that seems to be allright except for all those slashes (That looks a bit odd to me)
And finally create the texture:
WWW www = new WWW("file://" + filePaths[i]);
yield return www;
Texture2D new_texture = new Texture2D(120, 80);
www.LoadImageIntoTexture(new_texture);
And around this last part (unsure: webgl projects does not seem easily debuggable) it tells me: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
Can someone please enlighten me what is happening? And most of all, what would be proper to solution to create a directory from where I can load images during runtime?
I realise this question is now a couple of years old, but, since this still appears to be commonly asked question, here is one solution (sorry, the code is C# but I am guessing the javascript implementation is similar). Basically you need to use UnityWebRequest and Coroutines to access a file from the StreamingAssets folder.
1) Create a new Loading scene (which does nothing but query the files; you could have it display some status text or a progress bar to let the user knows what is happening).
2) Add a script called Loader to the Main Camera in the Loading scene.
3) In the Loader script, add a variable to indicate whether the asset has been read successfully:
private bool isAssetRead;
4) In the Start() method of the Loading script:
void Start ()
{
// if webGL, this will be something like "http://..."
string assetPath = Application.streamingAssetsPath;
bool isWebGl = assetPath.Contains("://") ||
assetPath.Contains(":///");
try
{
if (isWebGl)
{
StartCoroutine(
SendRequest(
Path.Combine(
assetPath, "myAsset")));
}
else // desktop app
{
// do whatever you need is app is not WebGL
}
}
catch
{
// handle failure
}
}
5) In the Update() method of the Loading script:
void Update ()
{
// check to see if asset has been successfully read yet
if (isAssetRead)
{
// once asset is successfully read,
// load the next screen (e.g. main menu or gameplay)
SceneManager.LoadScene("NextScene");
}
// need to consider what happens if
// asset fails to be read for some reason
}
6) In the SendRequest() method of the Loading script:
private IEnumerator SendRequest(string url)
{
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
// handle failure
}
else
{
try
{
// entire file is returned via downloadHandler
//string fileContents = request.downloadHandler.text;
// or
//byte[] fileContents = request.downloadHandler.data;
// do whatever you need to do with the file contents
if (loadAsset(fileContents))
isAssetRead = true;
}
catch (Exception x)
{
// handle failure
}
}
}
}
Put your image in the Resources folder and use Resources.Load to open the file and use it.
For example:
Texture2D texture = Resources.Load("images/Texture") as Texture2D;
if (texture != null)
{
GetComponent<Renderer>().material.mainTexture = texture;
}
The directory listing and file APIs are not available in webgl builds.
Basically no low level IO operations are supported.
Recently I have started working on a simple top down tile based program where you can move a player character around the map and zoom in and out of the map.
It's been going well, I have a background drawn and now I want to start drawing some tiles.
Currently I have something that looks kind of like this:
var tileset1 = new Image();
tileset1.src = "Images/Tileset1.gif";
var tx = [];
var ty = [];
var txo = [];
var tyo = []; //Background tile x and y on the map and the x and y offset in the image for drawing
var tilesize = 32; //constant for each tiles width and height in pixels.
function map1data() {
"use strict";
tx[0] = 0;
ty[0] = 0;
txo[0] = 0;
tyo[0] = 0;
tx[1] = 32;
ty[1] = 0;
txo[1] = 32;
tyo[1] = 0;
}
map1data();
ctx.drawImage(tileset1, txo[i], tyo[i], tilesize, tilesize, tx[i], ty[i], tilesize, tilesize);
This works fine, but my main issue is with using arrays to draw the tiles and having to give the properties of each tile by hard coding it into the script.
If my map had 100 tiles in it, i would have to manually write 400 lines of code, not ideal.
So what I'm wondering is there a way to source a plain text file on the actual server the web page is hosted on (As in, in the same root file system as the index page?) and set a variable to the contents of that, like I did with the images? Rather than having to use DOM to request it from a specific servers url?
Is there a reason you are not wanting to use ajax? You can use PHP as follows (assume the following file is called myscript.php):
//place any opening javascript code here if necessary.
<?php
// open a file using the fopen function
// read each line of the file using the fgets function
// convert each line into your appropriate javascript code such as an array etc.
// echo the javascript code
//place any closing javascript code here if necessary.
Then you can include it just like including any other javascript file:
<script src="myscript.php"></script>
Also, since it is in a PHP script, you can reference files whether they are in the web root or outside of the web root.
You can use the XMLHttpRequest API. What this does is tell the browser to request the specified file from the server without loading a new page and presenting it to the user. You can then assign the returned data to a variable in your code and work with it from there.
If you don't mind using jQuery, you could use the .get() method, which has simpler syntax:
$.get( "tiles.txt", function( data ) {
// assign 'data' to an existing variable or pass into a function
});
You might want to look into storing the data as JSON or another similar format rather than plaintext (it'll be easier to manipulate).
I am going to implement a dynamic legend using JavaScript in Adobe Acrobat.
The document contains a lot of layers. Every layer has an own legend. The origin idea is to implement the legend so, that it contains the images in a dialog box for the visible layers.
I can only hide/show the layers by setting state to false or true (this.getOCGs()[i].state = false;) on document-level.
Question 1: Can I extract data from layer somehow for legend establishing? I think no, as we only have these function on layers: getIntent(), setIntent() and setAction(). Right? Therefore I decided to arrange it so, that all needed icons for every layer are saved in a folder with corresponding names. JavaScript should import the icons and I build the a dialog window with icons of visible Layers and place a text(description for this icon).
I tried all possibilities of image import described here: http://pubhelper.blogspot.com.au/2012/07/astuces-toolbar-icons-et-javascript.html. I got only one way (Convert the icons as hexadecimal strings). This way isn't good, as it is too much work to create with an other tool a hexadecimal string from a images and place it into a javascript code.
Unfortunately, I cannot import image using other methods:(. Since the security settings in Adobe are changed after version 7 or so, it is not possible to use functions like app.newDoc, app.openDoc, even app.getPath On document-level. I decided to implement the import on a folder level using trusted functions like this:
Variant 1:
var importImg = app.trustedFunction(function() {
app.beginPriv();
var myDoc = app.newDoc({
nWidth: 20,
nHeight: 20
});
var img = myDoc.importIcon("icon", "/icon.png", 0);
app.endPriv();
return img; });
var oIcon = importImg();
The settings in Preferences->JavaScript-> JavaScript Security are disabled (Enable menu item JS execution privileges, enable global object security policy)
NotAllowedError: Security settings prevent access to this property or method.
App.newDoc:109:Folder-Level:User:acrobat.js
Variant 2:
var importImg = app.trustedFunction(function() {
var appPath = var phPath = app.getPath({
cCategory: "user",
cFolder: "javascript"
});
try {
app.beginPriv();
var doc = app.openDoc({
cPath: phPath + "/icon.png",
bHidden: true
});
app.endPriv();
} catch (e) {
console.println("Could not open icon file: " + e);
return;
}
var oIcon = util.iconStreamFromIcon(doc.getIcon("icon"));
return oIcon;});
var oIcon = importImg();
Could not open icon file: NotAllowedError: Security settings prevent access to this property or method.
At least it allows the execution of all these functions like app.newDoc, but in the second variant it says, wrong range of content or so. Maybe is here the pdf from an image created false? I just took the image and printed it into a pdf.
I tried all these possibilities with .jpg, .png, .pdf. with different sizes(big images and 20x20), It doesn't work.
Could somebody help me, as I spent a lot of time with trying different possibilities. It would be actually better to implement the main goal described above on document level, is it possible?
Thank you and kind regards,
Alex
Do you have the Console fully activated in Acrobat? If not, do so and look for error messages you get.
The first variant does not work, because myDoc is not defined (unless you have done that before you call the importImg function).
If you want to import the image into the newly created file, you will have to make a reference to the Document Object you create with newDoc(). Actually, that would make the link to myDoc, as in
var myDoc = app.newDoc(1,1)
(are you sure you want to create a document measuring 1x1 pt?)
The next issue with the first variant is a bug in Acrobat, which discards "floating" Icon Objects when saving the document; you'd have to attach the Icon Object to a field to keep it; this field can be hidden, or even on a hidden Template page in the document.