mirror of
https://github.com/sbrow/ps.git
synced 2025-12-29 18:47:38 -05:00
Merge branch 'release/v1.1'
This commit is contained in:
25
Variables.go
25
Variables.go
@@ -1,15 +1,6 @@
|
|||||||
package ps
|
package ps
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Colors enumerates some basic, commonly used colors.
|
|
||||||
var Colors map[string]Color = map[string]Color{
|
|
||||||
"Black": &RGB{0, 0, 0},
|
|
||||||
"Gray": &RGB{128, 128, 128},
|
|
||||||
"White": &RGB{255, 255, 255},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModeEnum determines how aggressively the package will attempt to sync with Photoshop.
|
// ModeEnum determines how aggressively the package will attempt to sync with Photoshop.
|
||||||
// Loading Photoshop files from scratch takes a long time, so the package saves
|
// Loading Photoshop files from scratch takes a long time, so the package saves
|
||||||
@@ -42,12 +33,8 @@ func (p *PSSaveOptions) String() string {
|
|||||||
return fmt.Sprint("", *p)
|
return fmt.Sprint("", *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PSSaveChanges saves changes before closing documents.
|
const (
|
||||||
const PSSaveChanges PSSaveOptions = 1
|
PSSaveChanges PSSaveOptions = iota + 1 // Saves changes before closing documents.
|
||||||
|
PSDoNotSaveChanges // Closes documents without saving.
|
||||||
// PSDoNotSaveChanges closes documents without saving.
|
PSPromptToSaveChanges // Prompts whether to save before closing.
|
||||||
const PSDoNotSaveChanges PSSaveOptions = 2
|
)
|
||||||
|
|
||||||
// PSPromptToSaveChanges prompts the user whether to save each
|
|
||||||
// document before closing it.
|
|
||||||
const PSPromptToSaveChanges PSSaveOptions = 3
|
|
||||||
|
|||||||
22
colors.go
22
colors.go
@@ -1,8 +1,11 @@
|
|||||||
package ps
|
package ps
|
||||||
|
|
||||||
import (
|
import "encoding/hex"
|
||||||
"encoding/hex"
|
|
||||||
// "fmt"
|
var (
|
||||||
|
ColorBlack Color = RGB{0, 0, 0}
|
||||||
|
ColorGray Color = RGB{128, 128, 128}
|
||||||
|
ColorWhite Color = RGB{255, 255, 255}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Color is an interface for color objects, allowing colors to be
|
// Color is an interface for color objects, allowing colors to be
|
||||||
@@ -14,7 +17,7 @@ type Color interface {
|
|||||||
Hex() []uint8 // The color in hexadecimal format.
|
Hex() []uint8 // The color in hexadecimal format.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare determines which of two colors is "brighter".
|
// Compare returns the brighter of a and b.
|
||||||
func Compare(a, b Color) Color {
|
func Compare(a, b Color) Color {
|
||||||
A := a.RGB()
|
A := a.RGB()
|
||||||
B := b.RGB()
|
B := b.RGB()
|
||||||
@@ -26,7 +29,7 @@ func Compare(a, b Color) Color {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// RGB is a color in RGB format. It implements the Color interface.
|
// RGB is a color format. It implements the Color interface.
|
||||||
type RGB struct {
|
type RGB struct {
|
||||||
Red int
|
Red int
|
||||||
Green int
|
Green int
|
||||||
@@ -38,9 +41,10 @@ func (r RGB) RGB() [3]int {
|
|||||||
return [3]int{r.Red, r.Green, r.Blue}
|
return [3]int{r.Red, r.Green, r.Blue}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement RGB.Hex()
|
|
||||||
func (r RGB) Hex() []uint8 {
|
func (r RGB) Hex() []uint8 {
|
||||||
return make([]uint8, 6)
|
src := []byte([]uint8{uint8(r.Red), uint8(r.Green), uint8(r.Blue)})
|
||||||
|
hex := make([]byte, hex.EncodedLen(len(src)))
|
||||||
|
return []uint8(hex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hex is a color in hexadecimal format. It implements the Color interface.
|
// Hex is a color in hexadecimal format. It implements the Color interface.
|
||||||
@@ -65,7 +69,3 @@ type Stroke struct {
|
|||||||
Size float32
|
Size float32
|
||||||
Color
|
Color
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (s *Stroke) String() string {
|
|
||||||
// return fmt.Sprintf("%vpt %v", s.Size, s.Color.RGB())
|
|
||||||
// }
|
|
||||||
|
|||||||
10
examples_test.go
Normal file
10
examples_test.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package ps
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func ExampleJSLayer() {
|
||||||
|
// The path of a layer inside a top level group.
|
||||||
|
path := "/Group 1/Layer 1"
|
||||||
|
fmt.Println(JSLayer(path))
|
||||||
|
// Output: app.activeDocument.layerSets.getByName('Group 1').artLayers.getByName('Layer 1');
|
||||||
|
}
|
||||||
170
ps.go
170
ps.go
@@ -2,6 +2,8 @@
|
|||||||
// The interaction between the two is implemented using Javascript/VBScript.
|
// The interaction between the two is implemented using Javascript/VBScript.
|
||||||
//
|
//
|
||||||
// Currently only supports Photoshop CS5 Windows x86_64.
|
// Currently only supports Photoshop CS5 Windows x86_64.
|
||||||
|
//
|
||||||
|
// TODO: Creatue a Photoshop struct to hold program values and functions.
|
||||||
package ps
|
package ps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,7 +11,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
// "log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -34,11 +35,16 @@ func init() {
|
|||||||
case "darwin":
|
case "darwin":
|
||||||
scmd = "osacript"
|
scmd = "osacript"
|
||||||
}
|
}
|
||||||
|
// update.Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start opens Photoshop.
|
// ApplyDataset fills out a template file with information
|
||||||
func Start() error {
|
// from a given dataset (csv) file. It is important to note that running this
|
||||||
_, err := run("start")
|
// function will change data in the Photoshop document, but will not update
|
||||||
|
// data in the Go Document struct- you will have to implement syncing
|
||||||
|
// them yourself.
|
||||||
|
func ApplyDataset(name string) error {
|
||||||
|
_, err := DoJs("applyDataset.jsx", name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,28 +54,14 @@ func Close(save PSSaveOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a Photoshop document with the specified path.
|
// DoAction runs the Photoshop Action "name" from the Action Set "set".
|
||||||
// If Photoshop is not currently running, it is started before
|
func DoAction(set, name string) error {
|
||||||
// opening the document.
|
_, err := run("action", set, name)
|
||||||
func Open(path string) error {
|
|
||||||
_, err := run("open", path)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quit exits Photoshop with the given saving option.
|
|
||||||
func Quit(save PSSaveOptions) error {
|
|
||||||
_, err := run("quit", save.String())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAs saves the Photoshop document to the given location.
|
|
||||||
func SaveAs(path string) error {
|
|
||||||
_, err := run("save", path)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoJs runs a Photoshop Javascript script file (.jsx) from the specified location.
|
// DoJs runs a Photoshop Javascript script file (.jsx) from the specified location.
|
||||||
// It can't directly return output, so instead the script must write their output to
|
// The script can't directly return output, so instead it writes output to
|
||||||
// a temporary file ($TEMP/js_out.txt), whose contents is then read and returned.
|
// a temporary file ($TEMP/js_out.txt), whose contents is then read and returned.
|
||||||
func DoJs(path string, args ...string) (out []byte, err error) {
|
func DoJs(path string, args ...string) (out []byte, err error) {
|
||||||
// Temp file for js to output to.
|
// Temp file for js to output to.
|
||||||
@@ -97,68 +89,6 @@ func DoJs(path string, args ...string) (out []byte, err error) {
|
|||||||
return cmd, err
|
return cmd, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait prints a message to the console and halts operation until the user
|
|
||||||
// signals that they are ready (by pushing enter).
|
|
||||||
//
|
|
||||||
// Useful for when you need to do something by hand in the middle of an
|
|
||||||
// otherwise automated process. (i.e. loading a dataset).
|
|
||||||
func Wait(msg string) {
|
|
||||||
fmt.Print(msg)
|
|
||||||
var input string
|
|
||||||
fmt.Scanln(&input)
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
// run handles running the script files, returning output, and displaying errors.
|
|
||||||
func run(name string, args ...string) ([]byte, error) {
|
|
||||||
var ext string
|
|
||||||
var out bytes.Buffer
|
|
||||||
var errs bytes.Buffer
|
|
||||||
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
ext = ".vbs"
|
|
||||||
case "darwin":
|
|
||||||
ext = ".applescript"
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(name, ext) {
|
|
||||||
name += ext
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(name, "dojs") {
|
|
||||||
args = append([]string{opts, filepath.Join(pkgpath, "scripts", name)},
|
|
||||||
args[0],
|
|
||||||
fmt.Sprintf("%s", strings.Join(args[1:], ",")),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
args = append([]string{opts, filepath.Join(pkgpath, "scripts", name)}, args...)
|
|
||||||
}
|
|
||||||
cmd := exec.Command(scmd, args...)
|
|
||||||
cmd.Stdout = &out
|
|
||||||
cmd.Stderr = &errs
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil || len(errs.Bytes()) != 0 {
|
|
||||||
return out.Bytes(), errors.New(string(errs.Bytes()))
|
|
||||||
}
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoAction runs the Photoshop Action "name" from the Action Set "set".
|
|
||||||
func DoAction(set, name string) error {
|
|
||||||
_, err := run("action", set, name)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyDataset fills out a template file with information
|
|
||||||
// from a given dataset (csv) file. It is important to note that running this
|
|
||||||
// function will change data in the Photoshop document, but will not update
|
|
||||||
// data in the Go Document struct- you will have to implement syncing
|
|
||||||
// them yourself.
|
|
||||||
func ApplyDataset(name string) error {
|
|
||||||
_, err := DoJs("applyDataset.jsx", name)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSLayer "compiles" Javascript code to get an ArtLayer with the given path.
|
// JSLayer "compiles" Javascript code to get an ArtLayer with the given path.
|
||||||
// The output always ends with a semicolon, so if you want to access a specific
|
// The output always ends with a semicolon, so if you want to access a specific
|
||||||
// property of the layer, you'll have to trim the output before concatenating.
|
// property of the layer, you'll have to trim the output before concatenating.
|
||||||
@@ -183,3 +113,75 @@ func JSLayer(path string, art ...bool) string {
|
|||||||
}
|
}
|
||||||
return js + ";"
|
return js + ";"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open opens a Photoshop document with the specified path.
|
||||||
|
// If Photoshop is not currently running, it is started before
|
||||||
|
// opening the document.
|
||||||
|
func Open(path string) error {
|
||||||
|
_, err := run("open", path)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit exits Photoshop using the given save option.
|
||||||
|
func Quit(save PSSaveOptions) error {
|
||||||
|
_, err := run("quit", save.String())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// run handles running the script files, returning output, and displaying errors.
|
||||||
|
func run(name string, args ...string) ([]byte, error) {
|
||||||
|
var ext string
|
||||||
|
var out bytes.Buffer
|
||||||
|
var errs bytes.Buffer
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
ext = ".vbs"
|
||||||
|
case "darwin":
|
||||||
|
ext = ".applescript"
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(name, ext) {
|
||||||
|
name += ext
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(name, "dojs") {
|
||||||
|
args = append([]string{opts, filepath.Join(pkgpath, "scripts", name)},
|
||||||
|
args[0],
|
||||||
|
fmt.Sprintf("%s", strings.Join(args[1:], ",,")),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
args = append([]string{opts, filepath.Join(pkgpath, "scripts", name)}, args...)
|
||||||
|
}
|
||||||
|
cmd := exec.Command(scmd, args...)
|
||||||
|
cmd.Stdout = &out
|
||||||
|
cmd.Stderr = &errs
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil || len(errs.Bytes()) != 0 {
|
||||||
|
return out.Bytes(), errors.New(string(errs.Bytes()))
|
||||||
|
}
|
||||||
|
return out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAs saves the Photoshop document to the given location.
|
||||||
|
func SaveAs(path string) error {
|
||||||
|
_, err := run("save", path)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start opens Photoshop.
|
||||||
|
func Start() error {
|
||||||
|
_, err := run("start")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait prints a message to the console and halts operation until the user
|
||||||
|
// signals that they are ready to continue (by pushing enter).
|
||||||
|
//
|
||||||
|
// Useful for when you need to do something by hand in the middle of an
|
||||||
|
// otherwise automated process. (i.e. importing a dataset).
|
||||||
|
func Wait(msg string) {
|
||||||
|
fmt.Print(msg)
|
||||||
|
var input string
|
||||||
|
fmt.Scanln(&input)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|||||||
43
ps_test.go
43
ps_test.go
@@ -1,3 +1,4 @@
|
|||||||
|
// TODO: Update package tests.
|
||||||
package ps
|
package ps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -122,14 +123,14 @@ func TestLayerSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLayer(t *testing.T) {
|
func TestLayer(t *testing.T) {
|
||||||
_, err := Layer("Border/Inner Border")
|
_, err := layer("Border/Inner Border")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMove(t *testing.T) {
|
func TestMove(t *testing.T) {
|
||||||
lyr, err := Layer("Group 1/Layer 1")
|
lyr, err := layer("Group 1/Layer 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -182,15 +183,10 @@ func TestColor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyDataset(t *testing.T) {
|
func TestApplyDataset(t *testing.T) {
|
||||||
out := []byte("done!\r\n")
|
err := ApplyDataset("Anger")
|
||||||
ret, err := ApplyDataset(" Anger")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if string(ret) != string(out) {
|
|
||||||
fail := fmt.Sprintf("TestJS failed.\ngot:\t\"%s\"\nwant:\t\"%s\"", ret, out)
|
|
||||||
t.Fatal(fail)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDocumentLayerSet(t *testing.T) {
|
func TestDocumentLayerSet(t *testing.T) {
|
||||||
@@ -248,6 +244,37 @@ func TestDoJs_HideLayer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTextItem(t *testing.T) {
|
||||||
|
// err := Open("F:\\GitLab\\dreamkeepers-psd\\Template009.1.psd")
|
||||||
|
// if err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
d, err := ActiveDocument()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, lyr := range d.ArtLayers() {
|
||||||
|
if lyr.Name() == "Text" {
|
||||||
|
lyr.SetText("Butts")
|
||||||
|
// lyr.FmtText(0, 5, "Arial", "Regular")
|
||||||
|
// lyr.FmtText(0, 3, "Arial", "Bold")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* byt := []byte(`{"Name": "lyr", "TextItem": {"Contents": "lyr", "Size": 12.000, "Font": "ArialItalic"}}`)
|
||||||
|
lyr := &ArtLayer{}
|
||||||
|
// byt := []byte(`{"Name": "lyr"}`)
|
||||||
|
// lyr := &TextItem{}
|
||||||
|
err := lyr.UnmarshalJSON(byt)
|
||||||
|
fmt.Printf("%+v\n", lyr)
|
||||||
|
fmt.Println(lyr.TextItem)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkDoc_Go(b *testing.B) {
|
func BenchmarkDoc_Go(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := ActiveDocument()
|
_, err := ActiveDocument()
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ Set appRef = CreateObject("Photoshop.Application")
|
|||||||
if wScript.Arguments.Count = 0 then
|
if wScript.Arguments.Count = 0 then
|
||||||
wScript.Echo "Missing parameters"
|
wScript.Echo "Missing parameters"
|
||||||
else
|
else
|
||||||
|
' wScript.Echo wScript.Arguments(0)
|
||||||
|
' wScript.Echo wScript.Arguments(1)
|
||||||
path = wScript.Arguments(0)
|
path = wScript.Arguments(0)
|
||||||
args = wScript.Arguments(1)
|
args = wScript.Arguments(1)
|
||||||
error = appRef.DoJavaScriptFile(path, Split(args, ","))
|
error = appRef.DoJavaScriptFile(path, Split(args, ",,"))
|
||||||
if Not error = "true" and Not error = "[ActionDescriptor]" and Not error = "undefined" Then
|
if Not error = "true" and Not error = "[ActionDescriptor]" and Not error = "undefined" Then
|
||||||
Err.raise 1, "dojs.vbs", error
|
Err.raise 1, "dojs.vbs", error
|
||||||
end if
|
end if
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
if(app.activeDocument.activeLayer.kind == LayerKind.TEXT){
|
||||||
|
var activeLayer = app.activeDocument.activeLayer;
|
||||||
|
if(activeLayer.kind == LayerKind.TEXT){
|
||||||
var start = parseInt(arguments[1]);
|
var start = parseInt(arguments[1]);
|
||||||
var end = parseInt(arguments[2]);
|
var end = parseInt(arguments[2]);
|
||||||
var fontName = arguments[3];
|
var fontName = arguments[3];
|
||||||
var fontStyle = arguments[4];
|
var fontStyle = arguments[4];
|
||||||
var colorArray = [0, 0, 0];
|
|
||||||
if(app.activeDocument.activeLayer.kind == LayerKind.TEXT){
|
|
||||||
var activeLayer = app.activeDocument.activeLayer;
|
|
||||||
var fontSize = activeLayer.textItem.size;
|
var fontSize = activeLayer.textItem.size;
|
||||||
if(activeLayer.kind == LayerKind.TEXT){
|
var colorArray = [0, 0, 0];
|
||||||
if((activeLayer.textItem.contents != "")&&(start >= 0)&&(end <= activeLayer.textItem.contents.length)){
|
if((activeLayer.textItem.contents != "")&&(start >= 0)&&(end <= activeLayer.textItem.contents.length)){
|
||||||
var idsetd = app.charIDToTypeID( "setd" );
|
var idsetd = app.charIDToTypeID( "setd" );
|
||||||
var action = new ActionDescriptor();
|
var action = new ActionDescriptor();
|
||||||
|
|||||||
@@ -3,25 +3,8 @@ var stdout = newFile(arguments[0]);
|
|||||||
var doc = app.activeDocument;
|
var doc = app.activeDocument;
|
||||||
stdout.writeln(('{"Name": "'+doc.name+'", "Height":'+doc.height+
|
stdout.writeln(('{"Name": "'+doc.name+'", "Height":'+doc.height+
|
||||||
', "Width":'+doc.width+', "ArtLayers": [').replace(/ px/g, ""));
|
', "Width":'+doc.width+', "ArtLayers": [').replace(/ px/g, ""));
|
||||||
function layers(lyrs) {
|
|
||||||
if (typeof lyrs === 'undefined')
|
stdout.writeln(layers(doc.artLayers))
|
||||||
return;
|
|
||||||
for (var i = 0; i < lyrs.length; i++) {
|
|
||||||
var lyr = lyrs[i];
|
|
||||||
stdout.write(('{"Name":"' + lyr.name + '", "Bounds": [[' + lyr.bounds[0] + ',' +
|
|
||||||
lyr.bounds[1] + '],[' + lyr.bounds[2] + ',' +
|
|
||||||
lyr.bounds[3] + ']], "Visible": ' + lyr.visible+', "Text":').replace(/ px/g, ""));
|
|
||||||
if (lyr.kind == LayerKind.TEXT)
|
|
||||||
stdout.write('"'+lyr.textItem.contents+'"');
|
|
||||||
else
|
|
||||||
stdout.write("null");
|
|
||||||
stdout.write("}")
|
|
||||||
if (i+1 != lyrs.length)
|
|
||||||
stdout.write(',');
|
|
||||||
stdout.writeln();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layers(doc.artLayers)
|
|
||||||
stdout.writeln('], "LayerSets": [');
|
stdout.writeln('], "LayerSets": [');
|
||||||
function lyrSets(sets, nm) {
|
function lyrSets(sets, nm) {
|
||||||
if (typeof sets === 'undefined')
|
if (typeof sets === 'undefined')
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
app.displayDialogs=DialogModes.NO
|
app.displayDialogs=DialogModes.NO
|
||||||
var stdout = newFile(arguments[0]);
|
var stdout = newFile(arguments[0]);
|
||||||
var lyr = eval(arguments[1]);
|
var lyr = eval(arguments[1]);
|
||||||
|
var lyrs = [lyr];
|
||||||
|
stdout.writeln(layers(lyrs))
|
||||||
|
/*
|
||||||
stdout.write(('{"Name":"' + lyr.name + '","Bounds":[[' + lyr.bounds[0] + ',' +
|
stdout.write(('{"Name":"' + lyr.name + '","Bounds":[[' + lyr.bounds[0] + ',' +
|
||||||
lyr.bounds[1] + '],[' + lyr.bounds[2] + ',' +
|
lyr.bounds[1] + '],[' + lyr.bounds[2] + ',' +
|
||||||
lyr.bounds[3] + ']],"Visible":' + lyr.visible+',"Text":').replace(/ px/g, ""));
|
lyr.bounds[3] + ']],"Visible":' + lyr.visible+',"Text":').replace(/ px/g, ""));
|
||||||
@@ -12,3 +15,4 @@ else
|
|||||||
stdout.write(null)
|
stdout.write(null)
|
||||||
stdout.writeln('}')
|
stdout.writeln('}')
|
||||||
stdout.close();
|
stdout.close();
|
||||||
|
*/
|
||||||
@@ -3,6 +3,10 @@ var stdout = newFile(arguments[0]);
|
|||||||
var set = eval(arguments[1]);
|
var set = eval(arguments[1]);
|
||||||
stdout.writeln('{"Name": "'+set.name+'", "Visible": '+ set.visible +', "ArtLayers":[');
|
stdout.writeln('{"Name": "'+set.name+'", "Visible": '+ set.visible +', "ArtLayers":[');
|
||||||
stdout.flush();
|
stdout.flush();
|
||||||
|
var str = layers(set.artLayers);
|
||||||
|
str = str.replace(/\r/g, "\\r");
|
||||||
|
stdout.writeln(str);
|
||||||
|
/*
|
||||||
for (var i = 0; i < set.artLayers.length; i++) {
|
for (var i = 0; i < set.artLayers.length; i++) {
|
||||||
var lyr = set.artLayers[i];
|
var lyr = set.artLayers[i];
|
||||||
stdout.write(('{"Name":"' + lyr.name + '", "Bounds": [[' + lyr.bounds[0] + ',' +
|
stdout.write(('{"Name":"' + lyr.name + '", "Bounds": [[' + lyr.bounds[0] + ',' +
|
||||||
@@ -17,6 +21,7 @@ for (var i = 0; i < set.artLayers.length; i++) {
|
|||||||
stdout.writeln(",");
|
stdout.writeln(",");
|
||||||
stdout.flush();
|
stdout.flush();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
stdout.writeln("]");
|
stdout.writeln("]");
|
||||||
stdout.write(', "LayerSets": [')
|
stdout.write(', "LayerSets": [')
|
||||||
for (var i = 0; i < set.layerSets.length; i++) {
|
for (var i = 0; i < set.layerSets.length; i++) {
|
||||||
@@ -27,13 +32,6 @@ for (var i = 0; i < set.layerSets.length; i++) {
|
|||||||
stdout.flush()
|
stdout.flush()
|
||||||
}
|
}
|
||||||
stdout.writeln(']')
|
stdout.writeln(']')
|
||||||
// app.activeDocument.activeLayer=set;
|
|
||||||
// set.merge();
|
|
||||||
// set=eval(arguments[2]);
|
|
||||||
stdout.write(', "Bounds": [[],[]]');
|
stdout.write(', "Bounds": [[],[]]');
|
||||||
// stdout.write((', "Bounds": [[' + set.bounds[0] + ',' +
|
|
||||||
// set.bounds[1] + '],[' + set.bounds[2] + ',' +
|
|
||||||
// set.bounds[3] + ']]').replace(/ px/g, ""));
|
|
||||||
stdout.write("}");
|
stdout.write("}");
|
||||||
// Undo();
|
|
||||||
stdout.close();
|
stdout.close();
|
||||||
@@ -98,3 +98,25 @@ function setFormatting(start, end, fontName, fontStyle, fontSize, colorArray) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function layers(lyrs) {
|
||||||
|
if (typeof lyrs === 'undefined')
|
||||||
|
return;
|
||||||
|
var str = "";
|
||||||
|
for (var i = 0; i < lyrs.length; i++) {
|
||||||
|
var lyr = lyrs[i];
|
||||||
|
str += ('{"Name":"' + lyr.name + '", "Bounds": [[' + lyr.bounds[0] + ',' +
|
||||||
|
lyr.bounds[1] + '],[' + lyr.bounds[2] + ',' +
|
||||||
|
lyr.bounds[3] + ']], "Visible": ' + lyr.visible+', "TextItem": ').replace(/ px/g, "");
|
||||||
|
if (lyr.kind == LayerKind.TEXT) {
|
||||||
|
str += ('{"Contents": "'+lyr.textItem.contents+'",').replace(/\r/g, '\\r');
|
||||||
|
str += (' "Size": '+lyr.textItem.size+',').replace(/ pt/g, '');
|
||||||
|
str += ' "Font": "'+lyr.textItem.font+'"}\n'
|
||||||
|
} else
|
||||||
|
str += "null";
|
||||||
|
str += "}";
|
||||||
|
if (i+1 != lyrs.length)
|
||||||
|
str += ',';
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
#include lib.js
|
#include lib.js
|
||||||
|
|
||||||
// var saveFile = File(arguments[0]);
|
// var saveFile = File(arguments[0]);
|
||||||
var arg = 'app.activeDocument.layerSets.getByName("ResolveGem");';
|
var arg = "app.activeDocument.layerSets.getByName('Text').artLayers.getByName('short').textItem.contents='When another sandman is discarded from a lane,';";
|
||||||
var set = eval(arg);
|
var set = eval(arg);
|
||||||
set.visible=false;
|
// set.textItem.size=10;
|
||||||
alert(set.visible)
|
|
||||||
// var doc=app.activeDocument
|
// var doc=app.activeDocument
|
||||||
// doc.layerSets.getByName("ResolveGem").merge();
|
// doc.layerSets.getByName("ResolveGem").merge();
|
||||||
// alert(doc.artLayers.getByName("ResolveGem").bounds);
|
// alert(doc.artLayers.getByName("ResolveGem").bounds);
|
||||||
|
|||||||
164
structs.go
164
structs.go
@@ -72,6 +72,10 @@ func (d *Document) Name() string {
|
|||||||
return d.name
|
return d.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) Parent() Group {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// The height of the document, in pixels.
|
// The height of the document, in pixels.
|
||||||
func (d *Document) Height() int {
|
func (d *Document) Height() int {
|
||||||
return d.height
|
return d.height
|
||||||
@@ -100,9 +104,6 @@ func (d *Document) LayerSet(name string) *LayerSet {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) Parent() Group {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (d *Document) SetParent(g Group) {}
|
func (d *Document) SetParent(g Group) {}
|
||||||
|
|
||||||
func (d *Document) Path() string {
|
func (d *Document) Path() string {
|
||||||
@@ -178,21 +179,21 @@ func (d *Document) Dump() {
|
|||||||
f.Write(byt)
|
f.Write(byt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtLayer reflects certain values from an Art Layer in a Photoshop document.
|
// ArtLayer reflects some values from an Art Layer in a Photoshop document.
|
||||||
//
|
//
|
||||||
// TODO: Make TextLayer a subclass of ArtLayer.
|
// TODO: (2) Make TextLayer a subclass of ArtLayer.
|
||||||
type ArtLayer struct {
|
type ArtLayer struct {
|
||||||
name string // The layer's name.
|
name string // The layer's name.
|
||||||
Text *string // The contents of a text layer.
|
bounds [2][2]int // The corners of the layer's bounding box.
|
||||||
bounds [2][2]int // The layers' corners.
|
|
||||||
parent Group // The LayerSet/Document this layer is in.
|
parent Group // The LayerSet/Document this layer is in.
|
||||||
visible bool // Whether or not the layer is visible.
|
visible bool // Whether or not the layer is visible.
|
||||||
current bool // Whether we've checked this layer since we loaded from disk.
|
current bool // Whether we've checked this layer since we loaded from disk.
|
||||||
Color // The layer's color overlay.
|
Color // The layer's color overlay effect (if any).
|
||||||
*Stroke // The layer's stroke.
|
*Stroke // The layer's stroke effect (if any).
|
||||||
|
*TextItem // The layer's text, if it's a text layer.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds returns the furthest corners of the ArtLayer.
|
// Bounds returns the coordinates of the corners of the ArtLayer's bounding box.
|
||||||
func (a *ArtLayer) Bounds() [2][2]int {
|
func (a *ArtLayer) Bounds() [2][2]int {
|
||||||
return a.bounds
|
return a.bounds
|
||||||
}
|
}
|
||||||
@@ -207,23 +208,12 @@ type ArtLayerJSON struct {
|
|||||||
Color [3]int
|
Color [3]int
|
||||||
Stroke [3]int
|
Stroke [3]int
|
||||||
StrokeAmt float32
|
StrokeAmt float32
|
||||||
Text *string
|
TextItem *TextItem
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArtLayer) SetText(txt string) {
|
|
||||||
lyr := strings.TrimRight(JSLayer(a.Path()), ";")
|
|
||||||
js := fmt.Sprintf("%s.textItem.contents='%s';", lyr, txt)
|
|
||||||
_, err := DoJs("compilejs.jsx", js)
|
|
||||||
if err != nil {
|
|
||||||
a.Text = &txt
|
|
||||||
}
|
|
||||||
a.Refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface, allowing the ArtLayer to be
|
// MarshalJSON implements the json.Marshaler interface, allowing the ArtLayer to be
|
||||||
// saved to disk in JSON format.
|
// saved to disk in JSON format.
|
||||||
func (a *ArtLayer) MarshalJSON() ([]byte, error) {
|
func (a *ArtLayer) MarshalJSON() ([]byte, error) {
|
||||||
// txt := strings.Replace(*a.Text, "\r", "\\r", -1)
|
|
||||||
return json.Marshal(&ArtLayerJSON{
|
return json.Marshal(&ArtLayerJSON{
|
||||||
Name: a.name,
|
Name: a.name,
|
||||||
Bounds: a.bounds,
|
Bounds: a.bounds,
|
||||||
@@ -231,7 +221,7 @@ func (a *ArtLayer) MarshalJSON() ([]byte, error) {
|
|||||||
Color: a.Color.RGB(),
|
Color: a.Color.RGB(),
|
||||||
Stroke: a.Stroke.RGB(),
|
Stroke: a.Stroke.RGB(),
|
||||||
StrokeAmt: a.Stroke.Size,
|
StrokeAmt: a.Stroke.Size,
|
||||||
Text: a.Text,
|
TextItem: a.TextItem,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,11 +235,11 @@ func (a *ArtLayer) UnmarshalJSON(b []byte) error {
|
|||||||
a.Color = RGB{tmp.Color[0], tmp.Color[1], tmp.Color[2]}
|
a.Color = RGB{tmp.Color[0], tmp.Color[1], tmp.Color[2]}
|
||||||
a.Stroke = &Stroke{tmp.StrokeAmt, RGB{tmp.Stroke[0], tmp.Stroke[1], tmp.Stroke[2]}}
|
a.Stroke = &Stroke{tmp.StrokeAmt, RGB{tmp.Stroke[0], tmp.Stroke[1], tmp.Stroke[2]}}
|
||||||
a.visible = tmp.Visible
|
a.visible = tmp.Visible
|
||||||
if tmp.Text != nil {
|
|
||||||
// s := strings.Replace(*tmp.Text, "\\r", "\r", -1)
|
|
||||||
a.Text = tmp.Text
|
|
||||||
}
|
|
||||||
a.current = false
|
a.current = false
|
||||||
|
a.TextItem = tmp.TextItem
|
||||||
|
if a.TextItem != nil {
|
||||||
|
a.TextItem.parent = a
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +247,11 @@ func (a *ArtLayer) Name() string {
|
|||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parent returns the Document or LayerSet this layer is contained in.
|
||||||
|
func (a *ArtLayer) Parent() Group {
|
||||||
|
return a.parent
|
||||||
|
}
|
||||||
|
|
||||||
// X1 returns the layer's leftmost x value.
|
// X1 returns the layer's leftmost x value.
|
||||||
func (a *ArtLayer) X1() int {
|
func (a *ArtLayer) X1() int {
|
||||||
return a.bounds[0][0]
|
return a.bounds[0][0]
|
||||||
@@ -363,26 +358,10 @@ func (a *ArtLayer) SetStroke(stk Stroke, fill Color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArtLayer) Parent() Group {
|
|
||||||
return a.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArtLayer) Path() string {
|
func (a *ArtLayer) Path() string {
|
||||||
return fmt.Sprintf("%s%s", a.parent.Path(), a.name)
|
return fmt.Sprintf("%s%s", a.parent.Path(), a.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Documentation for Format()
|
|
||||||
func (a *ArtLayer) Format(start, end int, font, style string) {
|
|
||||||
if !a.Visible() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err := DoJs("fmtText.jsx", fmt.Sprint(start), fmt.Sprint(end),
|
|
||||||
font, style)
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layer returns an ArtLayer from the active document given a specified
|
// Layer returns an ArtLayer from the active document given a specified
|
||||||
// path string.
|
// path string.
|
||||||
func layer(path string) (ArtLayer, error) {
|
func layer(path string) (ArtLayer, error) {
|
||||||
@@ -419,8 +398,6 @@ func (a *ArtLayer) Visible() bool {
|
|||||||
|
|
||||||
// SetPos snaps the given layer boundry to the given point.
|
// SetPos snaps the given layer boundry to the given point.
|
||||||
// Valid options for bound are: "TL", "TR", "BL", "BR"
|
// Valid options for bound are: "TL", "TR", "BL", "BR"
|
||||||
//
|
|
||||||
// TODO: Test TR and BR
|
|
||||||
func (a *ArtLayer) SetPos(x, y int, bound string) {
|
func (a *ArtLayer) SetPos(x, y int, bound string) {
|
||||||
if !a.visible || (x == 0 && y == 0) {
|
if !a.visible || (x == 0 && y == 0) {
|
||||||
return
|
return
|
||||||
@@ -462,7 +439,10 @@ func (a *ArtLayer) Refresh() error {
|
|||||||
tmp.SetParent(a.Parent())
|
tmp.SetParent(a.Parent())
|
||||||
a.name = tmp.name
|
a.name = tmp.name
|
||||||
a.bounds = tmp.bounds
|
a.bounds = tmp.bounds
|
||||||
a.Text = tmp.Text
|
a.TextItem = tmp.TextItem
|
||||||
|
if a.TextItem != nil {
|
||||||
|
a.TextItem.parent = a
|
||||||
|
}
|
||||||
a.parent = tmp.Parent()
|
a.parent = tmp.Parent()
|
||||||
a.visible = tmp.visible
|
a.visible = tmp.visible
|
||||||
a.current = true
|
a.current = true
|
||||||
@@ -721,3 +701,95 @@ func (l *LayerSet) Refresh() {
|
|||||||
l.visible = tmp.visible
|
l.visible = tmp.visible
|
||||||
l.current = true
|
l.current = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TextItem struct {
|
||||||
|
contents string
|
||||||
|
size float64
|
||||||
|
// color Color
|
||||||
|
font string
|
||||||
|
parent *ArtLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextItemJSON struct {
|
||||||
|
Contents string
|
||||||
|
Size float64
|
||||||
|
// Color [3]int
|
||||||
|
Font string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TextItem) Contents() string {
|
||||||
|
return t.contents
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TextItem) Size() float64 {
|
||||||
|
return t.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface, allowing the TextItem to be
|
||||||
|
// saved to disk in JSON format.
|
||||||
|
func (t *TextItem) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(&TextItemJSON{
|
||||||
|
Contents: t.contents,
|
||||||
|
Size: t.size,
|
||||||
|
// Color: t.color.RGB(),
|
||||||
|
Font: t.font,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TextItem) UnmarshalJSON(b []byte) error {
|
||||||
|
tmp := &TextItemJSON{}
|
||||||
|
if err := json.Unmarshal(b, &tmp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.contents = tmp.Contents
|
||||||
|
t.size = tmp.Size
|
||||||
|
// t.color = RGB{tmp.Color[0], tmp.Color[1], tmp.Color[2]}
|
||||||
|
t.font = tmp.Font
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TextItem) SetText(txt string) {
|
||||||
|
if txt == t.contents {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lyr := strings.TrimRight(JSLayer(t.parent.Path()), ";")
|
||||||
|
bndtext := "[[' + lyr.bounds[0] + ',' + lyr.bounds[1] + '],[' + lyr.bounds[2] + ',' + lyr.bounds[3] + ']]"
|
||||||
|
js := fmt.Sprintf(`%s.textItem.contents='%s';var lyr = %[1]s;stdout.writeln(('%[3]s').replace(/ px/g, ''));`,
|
||||||
|
lyr, txt, bndtext)
|
||||||
|
byt, err := DoJs("compilejs.jsx", js)
|
||||||
|
var bnds *[2][2]int
|
||||||
|
json.Unmarshal(byt, &bnds)
|
||||||
|
if err != nil || bnds == nil {
|
||||||
|
log.Println("text:", txt)
|
||||||
|
log.Println("js:", js)
|
||||||
|
fmt.Printf("byt: '%s'\n", string(byt))
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
t.contents = txt
|
||||||
|
t.parent.bounds = *bnds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TextItem) SetSize(s float64) {
|
||||||
|
if t.size == s {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lyr := strings.TrimRight(JSLayer(t.parent.Path()), ";")
|
||||||
|
js := fmt.Sprintf("%s.textItem.size=%f;", lyr, s)
|
||||||
|
_, err := DoJs("compilejs.jsx", js)
|
||||||
|
if err != nil {
|
||||||
|
t.size = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Documentation for Format(), make to textItem
|
||||||
|
func (t *TextItem) Fmt(start, end int, font, style string) {
|
||||||
|
var err error
|
||||||
|
if !t.parent.Visible() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = DoJs("fmtText.jsx", fmt.Sprint(start), fmt.Sprint(end),
|
||||||
|
font, style)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user