AE Extendscript layered source file - adobe

I'm working on a script that does find/replace for missing items in your project. Unfortunately I'm running into a situation detecting and then replacing layered image sources (psd, ai, etc.).
1) I see no way of detecting if a AvItem is a layer within a layered image other than parsing the item.name, which is unreliable because a user can always rename items in the project panel.
2) Once I do know that it is a part of a layered image I cannot figure out how to re-link it to the correct image without replacing the layer with the merged image. item.replace(new_path) will replace that item with the whole image, not the layer within the image. For example:
var item = app.project.item(3); //assuming this is the 'layer' we want to replace
item.replace(new_path);
So is there a secret property somewhere which will reliably tell me if an item is a part of a layered image, and if so is there a way to relink it without replacing the layer with the entire merged image?
EDIT
Here's a function to guess if a layer is part of a layered image. It's not bullet-proof but it should work as long as the user does not rename the item:
function isSourceLayered (av_item) {
// check if there is a "/"
if (av_item.name.indexOf("/") != -1) {
// check if it is in a "layers" folder
if (av_item.parentFolder.name.indexOf("Layers") != -1) {
return true;
}
}
return false;
}

I just asked the same question on the Adobe extendscript forum. Unless there's undocumented features (and I spent a bit of time looking with Extendscript Toolkit's data browser) the fileSource object doesn't seem to have any attributes or methods to do this.
There is a kind of a workaround, you can import the file using ImportOptions.importAs(ImportAsType.COMP) This will import a comp, and you can loop through the layers matching the name, get the source of that layer and use that as your new source. But as you say, it doesn't work if the source has been renamed.
I've written this into a function, it's available on github Edit: I forgot that I changed the way that function works. It doesn't re-import layer sources because of this problem, it just uses the Duplicate menu command.

Related

How can you extend the default behavior of Tridion.Cme.Commands.Open.prototype._execute()?

I have written a GUI extension which adds an additional tab to many of the Item views in the SDL Tridion CME (e.g. Component, Page and Schema etc.). I have also written some JavaScript which loads that tab directly if when the view is loaded with a tab name is specified in the URL.
The result is that if a page is loaded with the tab name added as follows:
http://localhost/WebUI/item.aspx?tcm=64#id=tcm:1-48-64&tab=InfoTab
Rather than the default of
http://localhost/WebUI/item.aspx?tcm=64#id=tcm:1-48-64
The Info Tab will be loaded on top, instead of the General Tab. This is performed with the following code snippet and works very well:
$evt.addEventHandler($display, "start", onDisplayStarted);
// This callback is called when any view has finished loading
function onDisplayStarted() {
$evt.removeEventHandler($display, "start", onDisplayStarted);
var tabname = $url.getHashParam("tab");
if (tabname != '') {
var tabControl = $controls.getControl($("#MasterTabControl"), "Tridion.Controls.TabControl");
tabControl.selectItem(tabname);
}
}
Now I would like to make a context menu item to open items and link to the tabs using my new functionality. My first thought was to construct the Item URL myself and simply open a new window in my execute method. So I looked at the default functionality in the standard Open.prototype_execute() functionality of the GUI. This is stored in the navigation.js file of the CME, and is performed by the Tridion.Cme.Commands.Open.prototype._execute method. The code is a lot more complicated than I had anticipated as it deals with shared items, and permissions etc.
Rather than just copying all of this code to my own function, I was wondering if there is a way to elegantly extend the existing Open.prototype_execute() function and append my “&tab=MyTab” to the $cme.Popups.OPEN_ITEM_OPTIONS.URL constant for my own functions.
Any advice would be greatly appreciated.
At the end the Open command uses $config.getEditorUrl(item_type) to get the url for the item view (item_type - $const.ItemType.COMPONENT, etc). There are no extension points for this part of the functionality, but you could always try to overwrite it on your own risk.

Double clicking a google earth treeview node does not 'flyto' the placemark

I am using the plugin in a desktop application (Visual Studio C#). I am creating a placemark using the following code:
// Create a new coordinate object based on the lat/lon of the device
// TODO :: add lat/lon once data is available
FC.GEPluginCtrls.Geo.Coordinate Coord =
new FC.GEPluginCtrls.Geo.Coordinate(0, 0, 0, AltitudeMode.RelativeToGround);
// Create a placemark and put it in the tree.
kmlTreeView.ParseKmlObject(KmlHelpers.CreatePlacemark(
ge,
Coord,
((Device)DeviceList[i]).sSerialNum, // ID
((Device)DeviceList[i]).sNickname, // Name - shown in tree
((Device)DeviceList[i]).sName)); // Description - shown in bubble
In the TreeView the new nodes show up and when I double-click on them the bubble pops up with information in it but the view does not change. I attempted to verify the property "public bool FlyToOnDoubleClickNode" as shown in the documentation but that property apparently does not exist in the version I am using (1.010).
When I was loading a KML file the double click worked as expected but ever since I've been manually adding the placemarks it does not work.
Any thoughts?
Thanks!
Have you tried manually assigning a <LookAt> or <Camera> ?
That should work
Edit: Well the FlyToOnDoubleClickNode is turned on by default, so your problems lie elsewhere
I do not know why you are having troubles with setting multiple LookAts. Have you tried assigning 'ids' to your LookAt ? Depending on what you are actually doing, that might help.
Otherwise, have you seen setFlyToView()
I am not sure that will help you though, since it relates to KMLs loaded via NetworkLinks
Thats about me for ideas - good luck!
It appears that the coordinates 0,0 are somehow significant. If the coordinates are changed to something else the "FlyTo" works (0.1 and 0.1 work).

Google maps API v3 - externally controlling radius on distanceWidget

this seems pretty specific to ask - but there was no other alternative to the expertbase of stackoverflow!
I'm stuck in a problem where I need to control the radius of the circle by an external means such as a dropdown or a textbox.
I had a hard time doing the circle and had to copy stuff from the Twitter search example on:
http://code.google.com/apis/maps/articles/mvcfun/twittersearch.html
Ideally, I would like to know how to bind an external even to the radiusWidget, the problem is - the sizer inside the radiusWidget seems a private entity.
It would be awesome if someone could hit me in the face with a bang!
Thx
distanceWidget.set('distance', XXX) should work. If you read the MVC article you can see how the binding is bi-directional.
You can look at the source of the Twitter example by downloading it to your computer, as you likely already did. When you have the source you can adapt it to your purposes as you like. The software usage rights (terms of usage, license, etc), if they are any, have to be respected of course.
In the case of the RadiusWidget you would just do:
function RadiusWidget(opt_distance) {
// ...
this.sizer = this.addSizer_(); // sizer is now accessible in RadiusWidget
}
RadiusWidget.prototype.addSizer_ = function() {
var sizer = ...
// ...
return sizer;
}

Loader for functions?

I am attempting to monitor the progress of an image scroller I've built and all of the images (thumbs) load separately. What would be the best way of figuring out what the total progress of the images that are loading?
I was thinking it would be cool to use a generic loader and apply it to a function such as
myScroller.loadImages();
But I haven't seen any examples of that.
I did come across this thread:
but I'm not sure if it really addresses the issue I'm up against or not.
Thanks for any thoughts or expertise.
jml
Hey there, I would lean towards the 3rd. option mentioned by maxmc. I'd have an XML with the info. of all the images I want to load (e.g. name, size, etc); this way I will know ahead how many images are going to be loaded, if I want to measure the overall progess based on the number of the remaining images, but also the total bytes I have to load in case I want to monitor the overall progress in terms of remaining bytes to load.
This XML of course could be created on demand; you just need to create a script that gets, from flash, the folder or location which you want to load images from, so it reads it, get the necessary info about the images and returns to flash the result as XML so it can proceed with the load images process.
the problem is that you only know the size of an image if you start loading it so there are three options i guess:
1) start loading each of the image and stop immediately after you get the size. the disadvantage is that you double the requests.
2) when you start to load the first image, multiply it's size with the number of images. disadvantage is that this is inprecise.
3) if you define the images somewhere outside your app for instance in an xml you could add some kind of filesize attribute and when you compile your app inject the sizes via some custom ant task into the xml.
i favour option 3.
Depending on the scale of your app you could look into the bulkloader library. It's not exactly lightweight, about 16kb I think, but if you're loading quite a few images then that shouldn't be too much of an impact. Check the site for detailed instructions but you do something like this:
private var $loader : Bulkloader = new BulkLoader( "ExampleLoader" );
private function startLoad() : void
{
$loader.add( "image1.jpg", { id : "image1", type : "image" });
$loader.add( "image2.jpg", { id : "image2", type : "image" });
$loader.add( "image3.jpg", { id : "image3", type : "image" });
$loader.addEventListener( BulkLoaderEvent.COMPLETE, loadComplete )
$loader.start();
}
private function loadComplete( e : BulkLoader ) : void
{
var thumbNail : ThumbNail = new ThumbNail( $loader.getBitmap( "image1" ) );
}
Not sure if that's exactly right but you should get the idea.
Rich

Flex: Dynamically create a preview image for a video

I'm using the VideoDisplay to play flv's, mov's, and mp4's and everything is working great. They are all being loaded via progressive download and are not being streamed. What I'd like to do is to grab a single specified frame (like whatever is being shown at the 10 second mark), convert it to a bitmap and use that bitmap as the preview image for the video. I'd like to do this at runtime so I don't have to create a preview image for every video that would be shown.
Any idea's on how to do this? I'd rather not fake it by playing it - seeking for that specific frame and then pausing it but I may have no other choice?
Ryan and James are correct -- the right way's probably to extract frames at upload/transcode-time. But if that's not an option, you could opt for using some sort of a default/placeholder image of your own (something generic or somehow suitable for all videos whose thumbs haven't yet been captured), and just use VideoDisplay's DisplayObject-ness to grab and then upload a frame to your server, e.g.:
<mx:Script>
<![CDATA[
var captured:Boolean;
private function creationCompleteHandler(event:Event):void
{
videoDisplay.source = "http://yourserver/yourvideo.flv";
}
private function videoDisplay_playheadUpdate(event:VideoEvent):void
{
if (!captured && videoDisplay.playheadTime >= 10)
capture();
}
private function capture():void
{
var bmpData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bmpData.draw(videoDisplay);
captured = true;
// Now just upload the byte array to your server for the next user
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
// ... etc.
}
]]>
</mx:Script>
<mx:VideoDisplay id="videoDisplay" playheadUpdate="videoDisplay_playheadUpdate(event)" />
Again, it's perhaps not the most elegant solution, but it certainly works. This way, the first user sees the generic image, but every user thereafter gets the generated thumbnail. (Which, of course, you'll have uploaded and properly associated by then.) Make sense?
I'm pretty sure this isn't possible. It may well be... but don't think so. I think the only way to load in video is to use the NetStream and NetConnection object, which as you know just kicks off the loading of the video.
If this is user generated video i think the best bet is to have some serever side script that generates the preview image. Have no idea how this is done but think this is how most clip sites work.
If all the videos are in your control it may be possible to write a script for one of the video editing programs to automate generating the image for a specific frame from a list of files. I think this is probably your best route as alternative that you could get up and running quickly.
Sorry for the vague answer... it may point you in the right direction if you need a quick solution.
I agree with James, the only way to really do this would be to do it with a server side script and pull certain frames out of the video. Even if you could do this with flex, you really would not want to put the burden to do this (which would be processor intensive I would think) on the client machine. Not to mention it will be much more efficient to create the image before hand than to have flex determine the thumbnail to show every time it is loaded.

Resources