Find and replace text problem in Photoshop - photoshop

In photoshop, let's say I have a few texts layers with contents like this:
Text layer 1: 1##text01##abc
Text layer 2: 2##text02##cef
Text layer 3: 3##text03##hgi
I would like to replace all the layers texts (the content of each text layer inside the artboard, not the layer panel's names) starting with the first# and the end#, that is ##text..## to ## so that results will be:
Text layer 1: 1##abc
Text layer 2: 2##cef
Text layer 3: 3##hgi
Hoe can I achieve this?
Thank you.

You need to do basically 3 operations:
traverse through the layers and select them one by one;
replace a part of the layer name using a regular expression pattern;
rename the layer with the new name;
A basic* version of this could look like this:
var layer;
// looping through top layers
for (var i = 0; i < activeDocument.layers.length; i++) {
layer = activeDocument.layers[i]; // for ease of read
activeDocument.activeLayer = layer; // making the layer active
layer.name = layer.name.replace(/#.*#/,'##'); // replacing the layer name. #.*# regex pattern will select anything between two # symbols
}
Update: replacing the layer text contents.
Basically the same thing with some additions. You need to check if layer.kind is LayerKind.TEXT and instead of changing layer.name you need to change layer.textItem.contents
*. note that activeDocument.layers collection contains only top level layers. If your document has groups (aka folders) or artboards you'll need to go through nested layers with a different function: something like this

I tried myself with the script below, it does works, but don't know if there is any structure I missed:
var layer;
// looping through top layers
for (var i = 0; i < activeDocument.layers.length; i++) {
layer = activeDocument.layers[i]; // for ease of read
activeDocument.activeLayer = layer; // making the layer active
layer.name = layer.name.replace(/#.*#/,''); // replacing the layer name. #.*# regex pattern will select anything between two # symbols
layer.textItem.contents = layer.textItem.contents.replace(/#.*#/,''); // replacing the layer name. #.*# regex pattern will select anything between two # symbols
}

Related

Get layer ID from Photoshop layer

Not sure if I'm doing this right. I'm trying to locate a layer. I can normally do that by group name & layer name. However that does present problems if there are duplicate names. So instead I'll try and find their unique layer ID.
I think this is correct:
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
for (var i = numOfLayers -1; i >= 0 ; i--)
{
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), i);
var layerDesc = executeActionGet(ref);
var layerID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var currentLayer = srcDoc.layers[i].name;
alert(layerID + " " + currentLayer);
}
... Only I expected the ID to be a larger random string, not a int. Firstly, have I got this right? And secondly is there a way to get the layer ID from the activeLayer?
IDs are interegers in PS and they are unique for a document only: they always start at 1 and then new layers and layer operations change ID counter by +1 so it's normal to have IDs in hundreds after a while.
To get an id of the active layer, change the reference to target:
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt')); // reference is active layer
var layerDesc = executeActionGet(ref);
var layerID = layerDesc.getInteger(stringIDToTypeID('layerID'));
alert(layerID);
P.S. this will work only with one active layer. For multiple layers you'll have you use a function I posted here: Get selected layers
P.P.S. note that your original code won't work with groups: indices of DOM and indices of AM aren't the same. You need to traverse layers in AM list to get proper indices.

Loading data into a texture defined as a MTLTextureType1DArray

I'm trying to set up some compute kernels that require interpolating some radial profiles of Fourier coefficients. Essentially I need to be discreet in one index but interpolating in the other. I figured that implementing these a 1D texture array would allow me to use the built in interpolation functions of my GPU. Looking through the Metal docs, it seems like a MTLTextureType1DArray with a MTLPixelFormatR32Float would be the right setup for this.
I'm setting up my texture description as
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
textureDescriptor.pixelFormat = MTLPixelFormatR32Float;
textureDescriptor.textureType = MTLTextureType1DArray;
textureDescriptor.width = numRadialPoints;
textureDescriptor.height = 1;
textureDescriptor.depth = 1;
textureDescriptor.arrayLength = numArrays;
textureDescriptor.mipmapLevelCount = 1;
textureDescriptor.sampleCount = 1;
textureDescriptor.resourceOptions = MTLResourceCPUCacheModeWriteCombined | MTLResourceStorageModeManaged;
textureDescriptor.cpuCacheMode = MTLCPUCacheModeWriteCombined;
textureDescriptor.storageMode = MTLStorageModeManaged;
textureDescriptor.usage = MTLTextureUsageShaderRead;
What I can't figure out is how to now load the texture data. My first attempt was to
_texture = [device newTextureWithDescriptor:textureDescriptor];
[_texture replaceRegion:MTLRegionMake2D(0, 0, numRadialPoints, numArrays) mipmapLevel:0 withBytes:floatbuffer bytesPerRow:4*numRadialPoints];
But this results in an error since heights don't match.
_validateReplaceRegion:144: failed assertion `(origin.y + size.height)(163) must be <= height(1).'
How do I load data into a MTLTextureType1DArray?
You need to use multiple calls to -replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:, once for each element of the array. You specify the array index with the slice parameter.
The region parameter needs to be 1-dimensional.

What are the advantages of using tf.train.SequenceExample over tf.train.Example for variable length features?

Recently I read this guide on undocumented featuers in TensorFlow, as I needed to pass variable length sequences as input. However, I found the protocol for tf.train.SequenceExample relatively confusing (especially due to lack of documentation), and managed to build an input pipe using tf.train.Example just fine instead.
Are there any advantages to using tf.train.SequenceExample? Using the standard example protocol when there is a dedicated one for variable length sequences seems like a cheat, but does it bear any consequence?
Here are the definitions of the Example and SequenceExample protocol buffers, and all the protos they may contain:
message BytesList { repeated bytes value = 1; }
message FloatList { repeated float value = 1 [packed = true]; }
message Int64List { repeated int64 value = 1 [packed = true]; }
message Feature {
oneof kind {
BytesList bytes_list = 1;
FloatList float_list = 2;
Int64List int64_list = 3;
}
};
message Features { map<string, Feature> feature = 1; };
message Example { Features features = 1; };
message FeatureList { repeated Feature feature = 1; };
message FeatureLists { map<string, FeatureList> feature_list = 1; };
message SequenceExample {
Features context = 1;
FeatureLists feature_lists = 2;
};
An Example contains a Features, which contains a mapping from feature name to Feature, which contains either a bytes list, or a float list or an int64 list.
A SequenceExample also contains a Features, but it also contains a FeatureLists, which contains a mapping from list name to FeatureList, which contains a list of Feature. So it can do everything an Example can do, and more. But do you really need that extra functionality? What does it do?
Since each Feature contains a list of values, a FeatureList is a list of lists. And that's the key: if you need lists of lists of values, then you need SequenceExample.
For example, if you handle text, you can represent it as one big string:
from tensorflow.train import BytesList
BytesList(value=[b"This is the first sentence. And here's another."])
Or you could represent it as a list of words and tokens:
BytesList(value=[b"This", b"is", b"the", b"first", b"sentence", b".", b"And", b"here",
b"'s", b"another", b"."])
Or you could represent each sentence separately. That's where you would need a list of lists:
from tensorflow.train import BytesList, Feature, FeatureList
s1 = BytesList(value=[b"This", b"is", b"the", b"first", b"sentence", b"."])
s2 = BytesList(value=[b"And", b"here", b"'s", b"another", b"."])
fl = FeatureList(feature=[Feature(bytes_list=s1), Feature(bytes_list=s2)])
Then create the SequenceExample:
from tensorflow.train import SequenceExample, FeatureLists
seq = SequenceExample(feature_lists=FeatureLists(feature_list={
"sentences": fl
}))
And you can serialize it and perhaps save it to a TFRecord file.
data = seq.SerializeToString()
Later, when you read the data, you can parse it using tf.io.parse_single_sequence_example().
The link you provided lists some benefits. You can see how parse_single_sequence_example is used here https://github.com/tensorflow/magenta/blob/master/magenta/common/sequence_example_lib.py
If you managed to get the data into your model with Example, it should be fine. SequenceExample just gives a little more structure to your data and some utilities for working with it.

How to handle text file with multiple spaces as delimiter

I have a source data set which consists of text files where the columns are separated by one or more spaces, depending on the width of the column value. The data is right adjusted, i.e. the spaces are added before the actual data.
Can I use one of the built-in extractors or do I have to implement a custom extractor?
#wBob's solution works if your row fits into a string (128kB). Otherwise, write your custom extractor that does fixed with extraction. Depending on what information you have on the format, you can write it by using input.Split() to split into rows and then split the rows based on your whitespace rules as shown below (full example for Extractor pattern is here) or you could write one similar to the one described in this blog post.
public override IEnumerable<IRow> Extract(IUnstructuredReader input, IUpdatableRow outputrow)
{
foreach (Stream current in input.Split(this._row_delim))
{
using (StreamReader streamReader = new StreamReader(current, this._encoding))
{
int num = 0;
string[] array = streamReader.ReadToEnd().Split(new string[]{this._col_delim}, StringSplitOptions.None).Where(x => !String.IsNullOrWhiteSpace(x)));
for (int i = 0; i < array.Length; i++)
{
// Now write your code to convert array[i] into the extract schema
}
}
yield return outputrow.AsReadOnly();
}
}
}
You could create a custom extractor or more simply, import the data as one row then split and clean and it using c# methods available to you within U-SQL like Split and IsNullOrWhiteSpace, something like this:
My right-aligned sample data
// Import the row as one column to be split later; NB use a delimiter that will NOT be in the import file
#input =
EXTRACT rawString string
FROM "/input/input.txt"
USING Extractors.Text(delimiter : '|');
// Add a row number to the line and remove white space elements
#working =
SELECT ROW_NUMBER() OVER() AS rn, new SqlArray<string>(rawString.Split(' ').Where(x => !String.IsNullOrWhiteSpace(x))) AS columns
FROM #input;
// Prepare the output, referencing the column's position in the array
#output =
SELECT rn,
columns[0] AS id,
columns[1] AS firstName,
columns[2] AS lastName
FROM #working;
OUTPUT #output
TO "/output/output.txt"
USING Outputters.Tsv(quoting : false);
My results:
HTH

Stata: for loop for storing values of Gini coefficient

I have 133 variables on income (each variable represents a group). I want the Gini coefficients of all these groups, so I use ineqdeco in Stata. I can't compute all these coefficients by hand so I created a for loop:
gen sgini = .
foreach var of varlist C07-V14 {
forvalue i=1/133 {
ineqdeco `var'
replace sgini[i] = $S_gini
}
}
Also tried changing the order:
foreach var of varlist C07-V14 {
ineqdeco `var'
forvalue i=1/133 {
replace sgini[i] = $S_gini
}
}
And specifying i beforehand:
gen i = 1
foreach var of varlist C07-V14 {
ineqdeco `var'
replace sgini[i] = $S_gini
replace i = i+1
}
}
I don't know if this last method works anyway.
In all cases I get the error: weight not allowed r(101). I don't know what this means, or what to do. Basically, I want to compute the Gini coefficient of all 133 variables, and store these values in a vector of length 133, so a single variable with all the coefficients stored in it.
Edit: I found that the error has to do with the replace command. I replaced this line with:
replace sgini = $S_gini in `i'
But now it does not "loop", so I get the first value in all entries of sgini.
There is no obvious reason for your inner loop. If you have no more variables than observations, then this might work:
gen sgini = .
gen varname = ""
local i = 1
foreach var of varlist C07-V14 {
ineqdeco `var'
replace sgini = $S_gini in `i'
replace varname = "`var'" in `i'
local i = `i' + 1
}
The problems evident in your code (seem to) include:
Confusion between variables and local macros. If you have much experience with other languages, it is hard to break old mental habits. (Mata is more like other languages here.)
Not being aware that a loop over observations is automatic. Or perhaps not seeing that there is just a single loop needed here, the twist being that the loop over variables is easy but your concomitant loop over observations needs to be arranged with your own code.
Putting a subscript on the LHS of a replace. The [] notation is reserved for weights but is illegal there in any case. To find out about weights, search weights or help weight.
Note that with this way of recording results, the Gini coefficients are not aligned with anything else. A token fix for that is to record the associated variable names alongside, as done above.
A more advanced version of this solution would be to use postfile to save to a new dataset.