Apply merge layers on multiple images without losing layers - gimp

My problem:
I want to make a lot of images that differ only in three text layers. I have already figured out, how to make the text changes with the Python-Fu Console. My next step is to put this text change code into a loop and add a png.file-save-png(...) to save the picture. In order to save as a PNG I have to merge all my layers (for each image), which is no problem with single_layer = pdb.gimp-image-merge-visible-layers(image,0). In order to keep working from here, I would need to to an undo, to get my old layers back.
Do I need to apply an UNDO Operation in GIMP from a script?
I couldn't find any hint on this feature. Maybe anyone knows how to do this, or has a workaround.

After a night of sleep, I figured out a workaround:
I reopened the base image file for each card in the loop, where all layers and text layers stayed intact. That prevented me from needing the undo.
By the way, here is my script for creating 4 * 13 playing cards (from ones own base_card.xcf):
basefile = "/home/[...]/base_card.xcf"
basesave = "/home/[...]/"
color_blue = [ (32.0 /255.0, 74.0/255.0,135.0/255.0,1.0),
(52.0 /255.0,101.0/255.0,164.0/255.0,1.0)]
color_red = [ (164.0/255.0, 0.0/255.0, 0.0/255.0,1.0),
(204.0/255.0, 0.0/255.0, 0.0/255.0,1.0)]
color_yellow = [ (196.0/255.0,160.0/255.0, 0.0/255.0,1.0),
(237.0/255.0,212.0/255.0, 0.0/255.0,1.0)]
color_green = [ ( 78.0/255.0,154.0/255.0, 6.0/255.0,1.0),
(115.0/255.0,210.0/255.0, 22.0/255.0,1.0)]
def createCard(color_list, color_name, number):
pdb.gimp_context_set_foreground(color_list[1])
image = pdb.gimp_file_load(basefile, basefile)
textlayers = image.layers[0:3]
for layer in textlayers:
pdb.gimp_text_layer_set_text(layer, number)
pdb.gimp_text_layer_set_color(layer, color_list[0])
layer = image.layers[3]
pdb.gimp_edit_bucket_fill(layer, 0, 0, 100, 0, 0, 30, 30)
layer = pdb.gimp_image_merge_visible_layers(image, 0)
savename = "%s%s_%s.png" % (basesave, color_name, number)
pdb.file_png_save(image, layer, savename, savename, 0, 0, 0, 0, 0, 0, 0)
image = None
for c in range(1,14):
createCard(color_blue, "BLUE", c)
for c in range(1,14):
createCard(color_yellow, "YELLOW", c)
for c in range(1,14):
createCard(color_red, "RED", c)
for c in range(1,14):
createCard(color_green, "GREEN", c)

Related

How to change color based on random number

I want to make a part that will change color depending on the seed.
Example:
if seed = 1 then
part.Color3 = red
end
which is like this, but with randomization
Nothing, im really dont know to make or try this
Make a list of the items, then use the math.random function to pick one out of the list.
-- create a list of colors
local colors = {
Color3.fromRGB(255, 0, 0), --red
Color3.fromRGB(0, 255, 0), --green
Color3.fromRGB(0, 0, 255), --blue
}
-- select a random number based on the length of the list
local index = math.random(#colors)
-- choose a color from the list
local rndColor = colors[index]
-- locate the part
local part = script.Parent
-- assign the color to the part
part.Color3 = rndColor

How to crop/resize texture array in Metal

Say I have a N-channel MPSImage or texture array that is based on MTLTexture.
How do I crop a region from it, copying all the N channels, but changing "pixel size"?
I'll just address the crop case, since the resize case involves resampling and is marginally more complicated. Let me know if you really need that.
Let's assume your source MPSImage is a 12 feature channel (3 slice) image that is 128x128 pixels, that your destination image is an 8 feature channel image (2 slices) that is 64x64 pixels, and that you want to copy the bottom-right 64x64 region of the last two slices of the source into the destination.
There is no API that I'm aware of that allows you to copy from/to multiple slices of an array texture at once, so you'll need to issue multiple blit commands to cover all the slices:
let sourceRegion = MTLRegionMake3D(64, 64, 0, 64, 64, 1)
let destOrigin = MTLOrigin(x: 0, y: 0, z: 0)
let firstSlice = 1
let lastSlice = 2 // inclusive
let commandBuffer = commandQueue.makeCommandBuffer()
let blitEncoder = commandBuffer.makeBlitCommandEncoder()
for slice in firstSlice...lastSlice {
blitEncoder.copy(from: sourceImage.texture,
sourceSlice: slice,
sourceLevel: 0,
sourceOrigin: sourceRegion.origin,
sourceSize: sourceRegion.size,
to: destImage.texture,
destinationSlice: slice - firstSlice,
destinationLevel: 0,
destinationOrigin: destOrigin)
}
blitEncoder.endEncoding()
commandBuffer.commit()
I'm not sure why you want to crop, but keep in mind that the MPSCNN layers can work on a smaller portion of your MPSImage. Just set the offset and clipRect properties and the layer will only work on that region of the source image.
In fact, you could do your crops this way using an MPSCNNNeuronLinear. Not sure if that is any faster or slower than using a blit encoder but it's definitely simpler.
Edit: added a code example. This is typed from memory so it may have small errors, but this is the general idea:
// Declare this somewhere:
let linearNeuron = MPSCNNNeuronLinear(a: 1, b: 0)
Then when you run your neural network, add the following:
let yourImage: MPSImage = ...
let commandBuffer = ...
// This describes the size of the cropped image.
let imgDesc = MPSImageDescriptor(...)
// If you're going to use the cropped image in other layers
// then it's a good idea to make it a temporary image.
let tempImg = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: imgDesc)
// Set the cropping offset:
linearNeuron.offset = MPSOffset(x: ..., y: ..., z: 0)
// The clip rect is the size of the output image.
linearNeuron.clipRect = MTLRegionMake(0, 0, imgDesc.width, imgDesc.height)
linearNeuron.encode(commandBuffer: commandBuffer, sourceImage: yourImage, destinationImage: tempImg)
// Here do your other layers, taking tempImg as input.
. . .
commandBuffer.commit()

Creating layers named after slices

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
}
);
}

Creating an image from a sprite sheet using the original images file name

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

Batch process photoshop layer with each saved layer having a specific filename

I have a layer that is a 250x250px circle.
I have an action set up to duplicate this circle layer and reduce the size by 99.2% (-2px).
I now need to be able to save this layer as a png file with the filename specific to the dimension of each layer - ie circle_248x248.png , circle_246x246.png and so on...
I can batch save but the tricky bit is making it save with the filename specific to the dimension of the layer..
Any suggestions??
Thanks in advance!
You could use Adobe ExtendScript to give you more control over the script and name the files programmatically. There is no way to do this with Actions.
You could use the GD library if you have access to a PHP server and write a simple script to create all your images, since it's such a simple operation.
for($i = 250; $i > 100; $i = $i - 2) {
$im = imagecreatetruecolor($i, $i);
imageantialias($im, true);
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilltoborder($im, 0, 0, $white, $white);
imagefilledellipse($im, $i/2, $i/2, $i, $i, $black);
imagepng($im, "circle_".$i."x".$i.".png);
}
Sorry to immediately take the problem out of Photoshop, but this is stackoverflow...

Resources