I have an issue that may well not be possible to solve 'out of the box'. I'm running fireworks 8 and would like to to be able to run the:
Commands->Document->Split to layers
and have the resulting layers created using the name of the slice that it created the layer for. So for example, if I have 3 slices in my png, called 'Head', Shoulder' and 'Arm', I'd like that command to create the layer name that corresponds to the slice name. As it currently stands, when running this command, the default layer names created are sequentially named 'Layer 1', 'Layer 2', 'Layer 3' etc etc.
The reason for this requirement is due to the fact that I then wish to use the Export command to save the individual Layers out to named png files that use the 'Slice names ('Head.png' etc), rather than the default Layer names. Now I know I can manually rename the layers to match the Slices, and Export to a folder as required. However, in my real life scenario, I have over 50 Slices per document that require this treatment and I have 100's of documents at a time to 'batch' process. So my idea was that I would be able to run a command (or create some sort of macro) that would allow me to create the layers with the same name as the slice that they contained.
This would make my life SOO much simpler as I could then totally automate the process based on a set of source images located within a folder structure, rather than opening each file, running the above command, renaming each layer manually (error prone of course) and then running the Export function.
Can anyone offer advice on finding a solution to this?? I hope I'm not the only one to have come across this requirement.
I've added a line to the Split to Layers command here. If you save that as Distribute to Named Layers.jsf in the same folder as the original command (in CS5.5 I found it in Configuration/Commands/Document), I think that should do what you need.
That said, jsf is fairly unpredictable in my experience (for example, that command seems to miss the default name of things like Rectangles until they've been renamed), so I'm not certain if it will work 100% of the time. Also, the script skips over the Web Layer which contains slices in 5.5 - I can't remember if the set up is different in 8. Hopefully that gets you some of the way there though.
FYI - here's what the final programatic fix amounted to (with thanks to david mear)
// This command will take multiple objects and move them to indivdual layers
// and then prompt for a folder location to save the layers as named-layer.png
// files. This is ultra useful if you want to save slices out to individual
// files and wish to have total control over the resulting file names
var curDoc = fw.getDocumentDOM();
// Save the current frame in the document
var curFrameNum = curDoc.currentFrameNum;
// get the total layers minus the web layer
var numLayers = curDoc.layers.length - 1; // skip the web layer.
var curLayerNum;
// default to d:\ for now
var locFolder = fw.browseForFolderURL("select a folder", "file:///d|/");
// 23/3/2013 add dialog box for file
if (locFolder !== null) {
// loop through the current number of layers
for (curLayerNum = numLayers - 1; curLayerNum >= 0; curLayerNum--) {
// get the current layer
var curLayer = curDoc.layers[curLayerNum];
// get the elements on the current layer
var elements = curLayer.frames[curFrameNum].elements;
//if layer is locked cannot distribute so continue to next layer.
if (curLayer.frames[curFrameNum].locked == true)
continue;
// get the number of elements
var numElements = elements.length - 1;
var i;
// loop through the number of elements
for (i = 0; i < numElements; i++) {
// get the current layer number
if (i == 0) curDoc.currentLayerNum = curLayerNum;
// add layers for the number of elements
curDoc.addNewLayer(null, false);
}
// again loop through the number of elements
for (i = 0; i < numElements; i++) {
// set the current layer
curLayer = curDoc.layers[curLayerNum];
// get the elements on the current layer
elements = curLayer.frames[curFrameNum].elements;
// select none
curDoc.selectNone();
// create a new array that will hold the selection
var sel = new Array();
// populate the array
sel[0] = elements[elements.length - 2];
// EDIT - 25/3/2013 rename target layer if element has a name
curDoc.setLayerName(curLayerNum + i + 1, sel[0].name || "");
// select all of the elements of the array in Fireworks
fw.selection = sel;
// move the selection to its new layer
curDoc.moveSelectionToLayer(curLayerNum + i + 1, false, "none", -1);
}
}
// EDIT - 25/3/2013 set to png32 export option
set_export_as_png_32(curDoc);
fw.exportLayers(curDoc, locFolder);
}
function set_export_as_png_32(targetDoc) {
targetDoc.setExportOptions(
{
animAutoCrop: true,
animAutoDifference: true,
applyScale: false,
colorMode: "32 bit",
crop: false,
cropBottom: 0,
cropLeft: 0,
cropRight: 0,
cropTop: 0,
ditherMode: "none",
ditherPercent: 100,
exportFormat: "PNG",
frameInfo: [],
interlacedGIF: false,
jpegQuality: 80,
jpegSelPreserveButtons: false,
jpegSelPreserveText: true,
jpegSelQuality: 90,
jpegSelQualityEnabled: false,
jpegSmoothness: 0,
jpegSubsampling: 0,
localAdaptive: true,
lossyGifAmount: 0,
macCreator: "",
macFileType: "",
name: "PNG32",
numCustomEntries: 0,
numEntriesRequested: 0,
numGridEntries: 6,
optimized: true,
paletteEntries: null,
paletteInfo: null,
paletteMode: "adaptive",
paletteTransparency: "none",
percentScale: 100,
progressiveJPEG: false,
savedAnimationRepeat: 0,
sorting: "none",
useScale: true,
webSnapAdaptive: false,
webSnapTolerance: 14,
xSize: 0,
ySize: 0
}
);
}
Related
I have a part that is a rectangle of 1200mm x 400mm x 400mm, this part can be divided into 3 equal sizes, within these equal sizes I need to Dock different parts. I have set a Docking Range for every 400mm (which is fine) I have 3 style of parts that need to Dock into the 400mm gaps, so I have set on the main 1200 part 3 KEYS (bridgePos1InfillType, bridgePos2InfillType, bridgePos3InfillType) and currently when I dock a part inside these I set the TYPE that was docked...
"mask": "cubby",
"position": "{0, 0, 40}",
"stepEnd": "{800, 0, 0}",
"rotation": "{0, 0, 0}",
"condition": "(((configID=='v2')||(configLadderID=='v2'))&&(cubeHeight==400))",
"maxConnections": 1,
"stepX": 400,
"stepY": 0,
"stepZ": 0,
"assignmentScripts": {
"onDock": "index = connection.index;
if(index=='0'){bridgePos1InfillType='cubby'};
if(index=='1'){bridgePos2InfillType='cubby'};
if(index=='2'){bridgePos3InfillType='cubby'}",
"onUpdate" : "",
"onUnDock": "index = connection.index;
if(index=='0'){bridgePos1InfillType='blank'};
if(index=='1'){bridgePos2InfillType='blank'};
if(index=='2'){bridgePos3InfillType='blank'}"
}
But what I want to happen is when I then try to docking a different part (using Docking Range) it should not let me as the InFillType is not BLANK
this is my next part to dock but how do I check to see if the Docking Range Position in already taken or that the bridgePos1InFillType is not BLANK...
{
"mask": "cupboard400x400",
"position": "{0, 0, 40}",
"stepEnd": "{800, 0, 0}",
"rotation": "{0, 0, 0}",
"condition": "index = connection.index;
(((configID=='v2')||(configLadderID=='v2'))&&(cubeHeight==400))",
"maxConnections": 1,
"stepX": 400,
"stepY": 0,
"stepZ": 0
},
You can utilize internal value called condition in all condition statements, like this:
"condition": "
/* you probably want to check if you're in preview, otherwise you could delete it right after docking, if the condition result becomes false */
if (connection.isPreview) {
/* then checking against which internal var to check this */
if (connection.index == 1) { condition = bridgePos1InfillType == 'blank'; }
...
/* then you can do further checks like */
condition = condition && (!maximumLoadExceeded);
} else {
/* if it is already there, just don't worry & keep it */
condition = true;
}
"
There is connection.index or connection.position to check the current position in the range's array. For 2D ranges, I recommend approach of computing the indices from connection.position. For 1D range, connection.index works just fine. See https://docs.roomle.com/scripting/resources/200_80_dockingbasics.html#docking-ranges and https://docs.roomle.com/scripting/resources/200_140_advanceddockinglogic.html#docking-ranges
I also see that an array would be good for you. If you worry only about whether there is something already docked, you could do an array of booleans occupied = [0,0,0] and then access the values using get(self.occupied, connection.index) in condition and use the set function in assignment scripts. If you need to also know what is occupied, RoomleScript unfortunately only supports arrays of numbers. A possible solution would be to have a 1:1 constant numeric identifier for every type.
See also https://docs.roomle.com/scripting/resources/200_40_roomlescript.html#arrays
I am trying to find the answer in Google Slides API references for how to set the background color of a shape I have in my Google Slide. I have given it the title (using Alt Text feature) "rectangle1", so my intention is to write the code along the lines of "if shape's property "title" == "rectangle1", then set background color to red."
I can't see a single reference to "SetBackgroundFill" or SetBackgroundColor, or anything of that sort.
Is it possible?
This is another possible answer, using a so-called "container bound script", which is only accessible through the specific Slide's Tools/Script Editor menu (no other way, or else it won't work).
I found that this "container bound script" approach gives me more power over my slide, and it avoids these expensive calls to "batchUpdate", when using "stand alone" scripts as in my other "self-answer".
So, in a way, I recommend it to myself, but, perhaps, to someone else, my other approach would be a better choice.
For one thing, this approach has a much faster response time.
var hex_color = '#54BdeF';
function test1() {
var selection = SlidesApp.getActivePresentation().getSelection();
var currentPage = selection.getCurrentPage();
var selectionType = selection.getSelectionType();
var shapes = currentPage.getShapes();
for (i=0; i < shapes.length; i++) {
if (shapes[i].getTitle() == 'rectangle1') {
shape_fill = shapes[i].getFill();
shape_fill.setSolidFill(hex_color);
}
}
}
Again, as before, I would welcome any comments and suggestions.
To set background color, you need Element Operations.
The Slides API allows you to create and edit a variety of page
elements, including text boxes, images, tables, basic shapes, lines,
and embedded videos. The examples on this page show some common page
element operations that can be achieved with the API.
Following the steps specified here will do the changes in your specified shape or element. Check the example.
Well, here is my solution. If someone sees a way to improve it, I am all ears, but so far, it appears to work for me glitch-free.
First, I find the shape I am after using the following logic:
function ChangeColorMain()
{
ChangeShapeBackgroundColor('title', 'rectangle1', color_to_repl_r, color_to_repl_g, color_to_repl_b, alpha_value );
}
function ChangeShapeBackgroundColor(shape_property_name, shape_property_value, color_to_set_r, color_to_set_g, color_to_set_b) {
Logger.log( 'ChangeShapeBackgroundColor(shape_property_name=%s, shape_property_value=%s, color_to_set_r=%s, color_to_set_g=%s, color_to_set_b=%s) ',
shape_property_name, shape_property_value, color_to_set_r, color_to_set_g, color_to_set_b);
var presentation = Slides.Presentations.get(presentationId);
var slides = presentation.slides;
Logger.log('The presentation contains %s slides:', slides.length);
for (i = 0; i < slides.length; i++) {
for (j = 0; j < slides[i].pageElements.length; j++ ) {
if (shape_property_name == 'title' && shape_property_value == slides[i].pageElements[j].title) {
Logger.log('Found it');
//slides[i].pageElements[j].shape.shapeProperties.shapeBackgroundFill.solidFill.color.rgbColor.red = color_to_set_r;
SubmitRequest(slides[i].pageElements[j].objectId, color_to_set_r, color_to_set_g, color_to_set_b, alpha_value);
}
} //end of for that iterates through every element
}
}
So, you'll notice that I start my process by calling the function "ChangeColorMain" which also gets my global variables color_to_repl_r... which are defined in a different file of my google script project, but that's not important.
Once inside the ChangeShapeBackgroundColor(), I iterate through all "PageElements" on my slide (see the relevant for loops) and use if statements to check if I got to the shape I am looking for. Finally, once I have located it, I call the all important function SubmitRequest(), which is "expensive". You can't make too many calls in one day, or else Google blocks this function until the day ends. But not a problem if you are making less than 500 calls per day (this number might be wrong/might change).
Here are the details of "SubmitRequest()" which I was able to create by finally figuring out how to make sense of this reference page:
https://developers.google.com/slides/reference/rest/v1/presentations/request#UpdateShapePropertiesRequest
function SubmitRequest(shape_id, r, g, b, a) {
var rgb_color = {
red: r,
green: g,
blue: b
};
var opaque_color = {
rgbColor: rgb_color
};
var solid_fill = {
color: opaque_color,
alpha: a
};
var background_fill = {
solidFill: solid_fill
};
var shape_properties = {
shapeBackgroundFill: background_fill
};
var update_request = {
objectId: shape_id,
shapeProperties: shape_properties,
fields: "shapeBackgroundFill.solidFill.color"
};
var requests = [{
updateShapeProperties: update_request
}];
// Execute the request.
var batch_update_return = Slides.Presentations.batchUpdate({
requests: requests
}, presentationId);
Logger.log(
'This is what you get from Google after submitting batchUpdate request:\n%s', batch_update_return);
}
We supply tiles for levels 0-9. So when the user goes to a zoom level 10 or higher I want the URL to change back to the default values of Open Street Map.
I've tried this and it almost works. When level 10 or higher is selected I change the URL using the ol.source.OSM.setURLs() function. But in some cases - not all - the image is still set to our local URL. I'm assuming this is some kind of caching issue but not sure.
$scope.tilesource = new ol.source.OSM({
url : '/'+$scope.tileRoot+'/tiles/{z}/{x}/{y}.png',
wrapX : false
});
var raster = new ol.layer.Tile({
source : $scope.tilesource
});
$scope.tilesource.on('tileloadstart', function(arg) {
//console.log(arg.tile.src_);
if ($scope.tileLevelsSupported.search(arg.tile.tileCoord[0]) == -1) {
$scope.tilesource.setUrls(["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png", "https://b.tile.openstreetmap.org/{z}/{x}/{y}.png", "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png"]);
} else {
$scope.tilesource.setUrl('/'+$scope.tileRoot+'/tiles/{z}/{x}/{y}.png');
}
});
I've tried several methods on OSM and Tile but have had no luck. On those instances when the Tile URL is wrong I get the File Not Found 404 error (expected), but then it corrects itself and the tile gets loaded.
Thanks in advance.
Instead of changing the URL, you could use two different layers with the minResolution and maxResolution options:
var raster = new ol.layer.Tile({
source : $scope.tilesource,
minResolution: 200,
maxResolution: 10000000
});
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM(),
minResolution: 0,
maxResolution: 200
});
When you zoom in from level 9 to 10, the raster layer will become invisible and the osm layer will appear.
Background: I'm a dev that knows JS, but is relatively new to Three JS. I've done a few small projects that involve static scenes with basic repeating animation.
I'm currently working on a modified version of Google's Globe project http://workshop.chromeexperiments.com/globe/. Looking back, I probably should have just started from scratch, but it was a good tool to see the approach their dev took. I just wish I could now update ThreeJS w/o the whole thing falling apart (too many unsupported methods and some bugs I never could fix, at least not in the hour I attempted it).
In the original, they are merging all of the geometric points into one object to speed up FPS. For my purposes, I'm updating the points on the globe using JSON, and there will never be more than 100 (probably no more than 60 actually), so they need to remain individual. I've removed the "combine" phase so I can now individually assign data to the points and then TWEEN the height change animation.
My question is, how do I manually select a single point (which is a Cube Geometry) so that I can modify the height value? I've looked through Stack Overflow and Three JS on GitHub and I'm not sure I understand the process. I'm assigning an ID to make it directly relate to the data that is being passed into it (I know WebGL adds an individual name/ID for particles, but I need something that is more directly related to what I'm doing for the sake of simplicity). That seems to work fine. But again, as a JS dev I've tried .getElementById(id) and $('#'+id) in jQuery, and neither works. I realize that Geometry objects don't behave the same way as HTML DOM objects, so I guess that's where I'm having struggles.
Code to add a point of data to the globe:
function addPoint(lat, lng, size, color, server) {
geometry = new THREE.Cube(0.75, 0.75, 1, 1, 1, 1, null, false, { px: true,
nx: true, py: true, ny: true, pz: false, nz: true});
for (var i = 0; i < geometry.vertices.length; i++) {
var vertex = geometry.vertices[i];
vertex.position.z += 0.5;
}
var point = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial ({
vertexColors: THREE.FaceColors
}));
var phi = (90 - lat) * Math.PI / 180;
var theta = (180 - lng) * Math.PI / 180;
point.position.x = 200 * Math.sin(phi) * Math.cos(theta);
point.position.y = 200 * Math.cos(phi);
point.position.z = 200 * Math.sin(phi) * Math.sin(theta);
if($('#'+server).length > 0) {
server = server+'b';
}
point.id = server;
point.lookAt(mesh.position);
point.scale.z = -size;
point.updateMatrix();
for (var i = 0; i < point.geometry.faces.length; i++) {
point.geometry.faces[i].color = color;
}
console.log(point.id);
scene.addObject(point);
}
So now to go back, I know I can't use point.id because obviously that will only reference inside the function. But I've tried 'Globe.id', 'Globe.object.id', 'object.id', and nothing seems to work. I know it is possible, I just can't seem to find a method that works.
Okay, I found a method that works for this by playing with the structure.
Essentially, the scene is labeled "globe" and all objects are its children. So treating the scene as an array, we can successfully pass an object into a var using the following structure:
Globe > Scene > Children > [Object]
Using a matching function, we loop through each item and find the desired geometric object and assign it to a temporary var for animation/adjustment:
function updatePoints(server){
var p, lineObject;
$.getJSON('/JSON/'+server+'.json', function(serverdata) {
/* script that sets p to either 0 or 1 depending on dataset */
var pointId = server+p;
//Cycle through all of the child objects and find a patch in
for(var t = 3; t < globe.scene.children.length; t++) {
if(globe.scene.children[t].name === pointId) {
//set temp var "lineObject" to the matched object
lineObject = globe.scene.children[t];
}
}
/* Manipulation based on data here, using lineObject */
});
}
I don't know if this is something that anyone else has had questions on, but I hope it helps someone else! :)
EDIT: Just realized this isn't a keyed array so I can use .length to get total # of objects
Creating sprite sheets aka texture atlases rather than using many hundres of individual images is recommended everywhere. I have hundreds of images for a word learning game; but there are hundreds of words, no animation sequences. So having generated the data file and sprite sheet, i am looking for an example of how to create an image when needed from the original image file name (as stored in the sprite sheet data (lua code) file (both created with texture packer).
This much seems right:
local sprite = require("sprite")
local CN_70_tiles_corona = require("CN_70_tiles_corona")
local spriteDataCN = CN_70_tiles_corona.getSpriteSheetData()
local spriteSheet = sprite.newSpriteSheetFromData( "CN_70_tiles_corona.png", spriteDataCN )
before creating the sprite sheet, would create my image with something like this:
t1 = display.newImage(cnTiles[tileNO])
where cnTiles[1], for examples, is a value placed in an array from a sqlite table such as "sit_word100.png".
there is now an entry in my generate lua file below the 'getSpritSheetData' function something like this:
{
name = "sit_word100.png",
spriteColorRect = { x = 0, y = 0, width = 69, height = 69 },
textureRect = { x = 2, y = 2, width = 69, height = 69 },
spriteSourceSize = { width = 69, height = 69 },
spriteTrimmed = false,
textureRotated = false
},
i can see that ALL my image file names are now stored in the data to provide a way to refer to my image within the sprite sheet, but since i do NOT want to use "sprite sets", i can't find an example of just getting the one image when in eed it.
I want something that allows me to refer to my now spritesheet-ified image using the original image name. is this possible? e.g.
t1 = display.newImage(CN_70_tiles_corona.getSpriteSheetData(name = "sit_word100.png")
The easy way is to create sheets with TexturePacker and use SpriteGrabber to take the sprites your need.
It's an awesome add-on to Corona-SDK which can be found here:
http://developer.anscamobile.com/code/spritegrabber-spritesheets-two-lines