The PhotoLine Scripted Actions Toolkit


Some operations do not have native scripting support, but may be recorded as actions.  An action may be scripted by passing its binary data in the form of a hexadecimal or Base64 string.  If you know the location of a parameter in the data, you can construct a string containing a custom parameter, and thus have scripting control over the operation.

The tools below enable you to find the parameters in an action’s hex string, and convert scripting parameters to the appropriate hex format.  The string is then constructed by concatenating the fixed code blocks with the parameters.  See two examples at the bottom of the page.


The hex string comparator

Create two actions with different parameters.  Right-click each action and select Copy Base64.  You may copy the entire action or a single step.

Paste the copied texts into the two fields below, then click “compare.”  The texts will be converted to hex and the differences will be highlighted, byte by byte.  Note the length of the changed blocks, such as six bytes for a floating point number; some bytes in different numbers may be the same.  Note also that curve presets are at least three pairs of floating point numbers.  You may want to limit the script to curves with the same number of points, and the same curve type (most of the simple ones are three-point Bezier).

Ignore changes in the title of the action at the end.  It may be less confusing to give the actions names with the same length (such as Emboss045, Emboss135).

For multiple parameters, first locate each parameter by changing them one-by-one, then change them all at once to get the fixed blocks.

Copy and paste fixed blocks into the formatter below and click “format” to get code strings.

If you do not want to edit the code and prefer a more compact string, just use the Base64 string.  (It is in .vbs format; for .js, change “& _” to “+”.)


"UGhvdG8gTGluZSBBY3Rpb25zAAAAAQAAAAABAP+bAAAADEdyb3VwQWN0aW9uAAIAAAAAAAAAAT4C" & _ "AQAAAAEAAAAEAAAAAQAAAAMAAAEkAAAAAQD/mwAAAA1FbWJvc3NBY3Rpb24AAQEAAAAAAAAAEgIB" & _ "AAAAAQAAAAQAAAAB/////wAAAAEAAADkAAEAAAAAAAAAAAACAAAAAAABAAAAjAEAAAAABQAAAAIA" & _ "AAAAAAAAAAAGMkP2wAAAAAAAAQAAAAY1ndQA//4AAAACAAAABiAAAAAABQAAAAMAAAAEAAAACAAA" & _ "AAQAAAA+AQAAAAAAAAAAAgABAAAAAQAAACYAAwAAAAAAACAAAAAAASr+C8D//y99vQD//yAAAAAA" & _ "AQAAAAAAAP//////////AAAAAgAAADYBAAAAAAAAAAACAAMAAAABAAAABjJD9sAAAAAAAAIAAAAE" & _ "AAAAAwAAAAMAAAAEAAAACv////////////////////8AAAABAAAAEP+bAAAACkVtYm9zczA0NQAA" & _ "AAACAAAABAAAABz/////"
"UGhvdG8gTGluZSBBY3Rpb25zAAAAAQAAAAABAP+bAAAADEdyb3VwQWN0aW9uAAIAAAAAAAAAAT4C" & _ "AQAAAAEAAAAEAAAAAQAAAAMAAAEkAAAAAQD/mwAAAA1FbWJvc3NBY3Rpb24AAQEAAAAAAAAAEgIB" & _ "AAAAAQAAAAQAAAAB/////wAAAAEAAADkAAEAAAAAAAAAAAACAAAAAAABAAAAjAEAAAAABQAAAAIA" & _ "AAAAAAAAAAAGJbL5AAACAAAAAQAAAAY1ndQA//4AAAACAAAABiAAAAAABQAAAAMAAAAEAAAACAAA" & _ "AAQAAAA+AQAAAAAAAAAAAgABAAAAAQAAACYAAwAAAAAAACAAAAAAASr+C8D//y99vQD//yAAAAAA" & _ "AQAAAAAAAP//////////AAAAAgAAADYBAAAAAAAAAAACAAMAAAABAAAABjJD9sAAAAAAAAIAAAAE" & _ "AAAAAwAAAAMAAAAEAAAACv////////////////////8AAAABAAAAEP+bAAAACkVtYm9zczEzNQAA" & _ "AAACAAAABAAAAB7/////"
compare  |  clear


The string formatter

Paste a fixed block from one of the fields above and click “format.”   

format  |  clear


Floating point hex string calculators

PhotoLine actions encode floating point numbers in a normalized format:
  - the mantissa (>= 0.5 and < 1) multiplied by 2^30 as a 4-byte (big endian) integer;
  - an exponent with base 2 as a 2-byte (big endian) integer, negative exponents counting down from ff ff.
So the resulting float from the saved values is (mantissa / 2^30) * 2^exponent.
Example:  30 00 00 00 00 04 = (805306368 / 1073741824) * 16 = 12


Convert a floating point number to a hex string, with an optional conversion factor:

×  

convert float to hex

 


Convert a hex string to a floating point number (12 hex characters; spaces o.k.; may be multiple.
Fewer than 12 characters will be converted to an integer.
Example:  00 00 00 00 00 00 20 00 00 00 00 01 2a fe 0b c0 ff ff 2f 7d bd 00 ff ff 20 00 00 00 00 01 00 00 00 00 00 00 ):

convert hex to float

 


Some actions save degrees as radians, and percent values normalized to a 0-1 range, so a conversion factor may be needed.
Calculate the conversion factor (example:  35 9d d4 00 ff fe, supposed to be 12):

Actual hex number:    
Supposed to be decimal number:  

calculate conversion factor

 


Note:  0.01745329 is 3.14159265358979/180, degrees to radians.
Something like 0.00999999977 indicates a percent multiplied by 0.01.



Examples

emboss.js

emboss(135, 12, 8, 16, 5, 0);



function emboss(direction, height, width, intensity, curveShape, mode) {
// emboss PhotoLine script by Russell Cottrell
// direction:  0-360
// height:  5-90
// width:  0-100
// intensity:  0-100
// curveShape:  0-7 as below
// mode:  0 = Unsharp, 1 = Shade
// pattern is Create From Intensity

var pl = new ActiveXObject("PhotoLine.Application");
var doc = pl.ActiveDocument;
var hexStr;

direction = floatToHex(direction * (3.14159265358979/180));

height = floatToHex(height * (3.14159265358979/180));

width = byteToHex(width);

intensity = floatToHex(intensity);

switch(curveShape) {
  case 0:
    curveShape = "000000000000000000000000200000000000200000000000200000000001200000000001"; // straight
    break;
  case 1:
    curveShape = "0000000000000000000000002afe0bc0ffff284121800000200000000001200000000001"; // straight raised
    break;
  case 2:
    curveShape = "00000000000000000000000029c55fc00000314ce400ffff200000000001200000000001"; // straight lowered
    break;
  case 3:
    curveShape = "000000000000200000000001200000000000200000000000200000000001000000000000"; // reversed
    break;
  case 4:
    curveShape = "00000000000020000000000129c55fc0000027598e000000200000000001000000000000"; // reversed raised
    break;
  case 5:
    curveShape = "0000000000002000000000012afe0bc0ffff2f7dbd00ffff200000000001000000000000"; // reversed lowered
    break;
  case 6:
    curveShape = "000000000000000000000000207d11800000200000000001200000000001000000000000"; // arch
    break;
  case 7:
    curveShape = "000000000000200000000001207d11800000000000000000200000000001200000000001"; // U
    break;
}

mode = byteToHex(mode);

hexStr = "50686f746f204c696e6520416374696f6e7300000001000000000100ff9b0000000d456d" +
  "626f7373416374696f6e00010100000000000000120201000000010000000400000001ff" +
  "ffffff00000001000000e40001000000000000000000020000000000010000008c010000" +
  "0000050000000200" +
  mode +
  "0000000000000006" +
  direction +
  "0000000100000006" +
  height +
  "0000000200000006" +
  intensity +
  "0000000300000004000000" +
  width +
  "000000040000003e01000000000000000002000100000001000000260003" +
  curveShape +
  "ffffffffffffffff00000002000000360100000000000000000200030000000100000006" +
  "3243f6c0000000000002000000040000000300000003000000040000000affffffffffff" +
  "ffffffffffff";

doc.DoOperation("Action", "Data", hexStr);

}



function floatToHex(num) {

var hexStr, s, exp, expStr, len, man, manStr;

if (num == 0)
  hexStr = "000000000000";

else {

  s = (num < 0 ? -1 : 1);
  num = Math.abs(num);

  exp = Math.floor(Math.log(num) / Math.log(2)) + 1;
  expStr = exp;
  if (expStr < 0)
    expStr += 0x10000;
  expStr = expStr.toString(16);
  len = expStr.length;
  for (var i=0; i<4-len; i++)
    expStr = "0" + expStr;

  man = Math.floor(s * (num / Math.pow(2, exp)) * Math.pow(2, 30));
  if (s < 0)
    man += 0x100000000;

  manStr = man.toString(16);

  hexStr = manStr + expStr;

}

return hexStr;

}



function byteToHex(num) {

var str = "00" + Math.round(num).toString(16);
return str.substr(str.length - 2);

}

layerToRGB.js

layerToRGB();



function layerToRGB() {
// Converts the active layer to an 8-bit RGB layer.

var pl = new ActiveXObject("PhotoLine.Application");
var doc = pl.ActiveDocument;
var base64Str;

base64Str = "UGhvdG8gTGluZSBBY3Rpb25zAAAAAQAAAAABAP+bAAAADkNvbnZlcnRBY3Rpb24AAgAAAAAA" +
  "AAAAEgIBAAAAAQAAAAQAAAAB/////wAAAAEAAAACAAEAAAACAAAABAAAAAD/////";

doc.DoOperation("Action", "Data", base64Str);

}


An Introduction to Photo Editing with PhotoLine | scripting