From c54b196f6a2ec5fa073872377ce2c7a2487326d7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 18 Apr 2018 23:58:38 -0400 Subject: [PATCH] Various updates * Layersets now have bounds. * TextItem is now writeable * Added flush function to writing, for faster debugging. --- ps.go | 8 +++-- scripts/getLayerSet.jsx | 20 +++++++++--- scripts/lib.js | 22 +++++++++++-- scripts/moveLayer.jsx | 7 +++++ scripts/test.jsx | 19 ++++++----- structs.go | 70 +++++++++++++++++++++++++++++++++++++++-- 6 files changed, 125 insertions(+), 21 deletions(-) diff --git a/ps.go b/ps.go index 2450b1d..93d7090 100644 --- a/ps.go +++ b/ps.go @@ -73,7 +73,7 @@ func SaveAs(path string) error { func DoJs(path string, args ...string) (out []byte, err error) { // Temp file for js to output to. outpath := filepath.Join(os.Getenv("TEMP"), "js_out.txt") - defer os.Remove(outpath) + // defer os.Remove(outpath) if !strings.HasSuffix(path, ".jsx") { path += ".jsx" } @@ -160,11 +160,15 @@ func ApplyDataset(name string) ([]byte, error) { // 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 // property of the layer, you'll have to trim the output before concatenating -func JSLayer(path string) string { +func JSLayer(path string, art ...bool) string { path = strings.TrimLeft(path, "/") pth := strings.Split(path, "/") js := "app.activeDocument" last := len(pth) - 1 + if len(art) > 0 { + pth = pth[:len(pth)-1] + last-- + } if last > 0 { for i := 0; i < last; i++ { js += fmt.Sprintf(".layerSets.getByName('%s')", pth[i]) diff --git a/scripts/getLayerSet.jsx b/scripts/getLayerSet.jsx index 313618a..0f43574 100644 --- a/scripts/getLayerSet.jsx +++ b/scripts/getLayerSet.jsx @@ -1,8 +1,8 @@ #include lib.js - var stdout = newFile(arguments[0]); var set = eval(arguments[1]); stdout.writeln('{"Name": "'+set.name+'", "ArtLayers":['); +stdout.flush(); for (var i = 0; i < set.artLayers.length; i++) { var lyr = set.artLayers[i]; stdout.write(('{"Name":"' + lyr.name + '", "Bounds": [[' + lyr.bounds[0] + ',' + @@ -15,13 +15,25 @@ for (var i = 0; i < set.artLayers.length; i++) { stdout.write("}") if (i != set.artLayers.length - 1) stdout.writeln(","); + stdout.flush(); } -stdout.write('], "LayerSets": [') +stdout.writeln("]"); +stdout.write(', "LayerSets": [') for (var i = 0; i < set.layerSets.length; i++) { var s = set.layerSets[i]; - stdout.write('{"Name": "'+ s.name +'", "Visible": '+s.visible+'}'); + stdout.write('{"Name":"' + s.name + '", "Visible": ' + s.visible + '}'); if (i < set.layerSets.length - 1) stdout.writeln(","); + stdout.flush() } -stdout.write("]}") +stdout.writeln(']') +// app.activeDocument.activeLayer=set; +// set.merge(); +// set=eval(arguments[2]); +stdout.write(', "Bounds": [[],[]]'); +// stdout.write((', "Bounds": [[' + set.bounds[0] + ',' + + // set.bounds[1] + '],[' + set.bounds[2] + ',' + + // set.bounds[3] + ']]').replace(/ px/g, "")); +stdout.write("}"); +// Undo(); stdout.close(); \ No newline at end of file diff --git a/scripts/lib.js b/scripts/lib.js index 99da88e..a409c0b 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -1,13 +1,21 @@ // Opens and returns a file, overwriting new data. function newFile(path) { var f = File(path) - if(f.exists) - f.remove() f.encoding = "UTF8" - f.open("e", "TEXT", "????") + f.open("w") return f } +File.prototype.flush = function() { + this.close() + this.open("a") +}; +function flush(file) { + file.close() + file.open("a") +} + + // Prints an error message. function err(e) { return 'ERROR: ' + e.message + ' at ' + e.fileName + ':' + e.line; @@ -19,6 +27,14 @@ function bounds(lyr) { lyr.bounds[3] + ']]').replace(/ px/g, ""); } +function Undo() { + var desc = new ActionDescriptor(); + var ref = new ActionReference(); + ref.putEnumerated( charIDToTypeID( "HstS" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Prvs" )); + desc.putReference(charIDToTypeID( "null" ), ref); + executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO ); +} + /** * The setFormatting function sets the font, font style, point size, and RGB color of specified * characters in a Photoshop text layer. diff --git a/scripts/moveLayer.jsx b/scripts/moveLayer.jsx index c3a4cf9..450a514 100644 --- a/scripts/moveLayer.jsx +++ b/scripts/moveLayer.jsx @@ -2,5 +2,12 @@ var stdout = newFile(arguments[0]); var lyr = eval(arguments[1]); lyr.translate((Number)(arguments[2]), (Number)(arguments[3])); +if (lyr.typename == 'LayerSet') { + alert(lyr.name + "\n" + lyr.typename) + alert(lyr) + // lyr.merge() + // lyr=eval(arguments[4]) + // Undo(); +} stdout.writeln('{' + bounds(lyr) + '}') stdout.close(); \ No newline at end of file diff --git a/scripts/test.jsx b/scripts/test.jsx index 7e2b9c5..bc18da5 100644 --- a/scripts/test.jsx +++ b/scripts/test.jsx @@ -1,12 +1,11 @@ #include lib.js -var saveFile = File(arguments[0]); -if(saveFile.exists) - saveFile.remove(); -saveFile.encoding = "UTF8"; -saveFile.open("e", "TEXT", "????"); -for (var i = 0; i < arguments.length; i++) { - saveFile.writeln(arguments[i]) -} -setFormatting(0,6, "Arial", "Bold"); -saveFile.close(); \ No newline at end of file +// var saveFile = File(arguments[0]); +var arg = 'app.activeDocument.layerSets.getByName("Indicators").layerSets.getByName("Deck")'; +alert(arg.replace(/[^(?:layerSets)]*(layerSets)/, "artLayers")) +// var doc=app.activeDocument +// doc.layerSets.getByName("ResolveGem").merge(); +// alert(doc.artLayers.getByName("ResolveGem").bounds); +// doc.activeHistoryState=doc.historyStates[doc.historyStates.length-2] +// setFormatting(0,6, "Arial", "Bold"); +// saveFile.close(); \ No newline at end of file diff --git a/structs.go b/structs.go index c8e36c2..cf6dc63 100644 --- a/structs.go +++ b/structs.go @@ -168,6 +168,7 @@ func (d *Document) Dump() { } // ArtLayer reflects certain values from an Art Layer in a Photoshop document. +// TODO: Make TextLayer a subclass of ArtLayer type ArtLayer struct { name string // The layer's name. Text *string // The contents of a text layer. @@ -197,6 +198,16 @@ type ArtLayerJSON struct { Text *string } +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 fulfills the json.Marshaler interface, allowing the ArtLayer to be // saved to disk in JSON format. func (a *ArtLayer) MarshalJSON() ([]byte, error) { @@ -444,6 +455,7 @@ func (a *ArtLayer) Refresh() error { type LayerSet struct { name string + bounds [2][2]int parent Group current bool // Whether we've checked this layer since we loaded from disk. visible bool @@ -453,6 +465,7 @@ type LayerSet struct { type LayerSetJSON struct { Name string + Bounds [2][2]int ArtLayers []*ArtLayer LayerSets []*LayerSet } @@ -460,6 +473,7 @@ type LayerSetJSON struct { func (l *LayerSet) MarshalJSON() ([]byte, error) { return json.Marshal(&LayerSetJSON{ Name: l.name, + Bounds: l.bounds, ArtLayers: l.artLayers, LayerSets: l.layerSets, }) @@ -471,6 +485,7 @@ func (l *LayerSet) UnmarshalJSON(b []byte) error { return err } l.name = tmp.Name + l.bounds = tmp.Bounds l.artLayers = tmp.ArtLayers for _, lyr := range l.artLayers { lyr.SetParent(l) @@ -544,6 +559,11 @@ func (l *LayerSet) LayerSet(name string) *LayerSet { return nil } +// Bounds returns the furthest corners of the LayerSet. +func (l *LayerSet) Bounds() [2][2]int { + return l.bounds +} + func (l *LayerSet) SetParent(c Group) { l.parent = c } @@ -562,9 +582,13 @@ func (l *LayerSet) Path() string { func NewLayerSet(path string, g Group) (*LayerSet, error) { path = strings.Replace(path, "//", "/", -1) byt, err := DoJs("getLayerSet.jsx", JSLayer(path)) + if err != nil { + log.Panic(err) + } var out *LayerSet err = json.Unmarshal(byt, &out) if err != nil { + log.Println(JSLayer(path)) log.Println(string(byt)) log.Panic(err) } @@ -597,12 +621,53 @@ func (l *LayerSet) SetVisible(b bool) { DoJs("compilejs.jsx", js) } +// SetPos snaps the given layerset boundry to the given point. +// Valid options for bound are: "TL", "TR", "BL", "BR" +// +// TODO: Test TR and BR +func (l *LayerSet) SetPos(x, y int, bound string) { + // if !l.visible || (x == 0 && y == 0) { + // return + // } + var lyrX, lyrY int + switch bound[:1] { + case "B": + lyrY = l.bounds[1][1] + case "T": + fallthrough + default: + lyrY = l.bounds[0][1] + } + switch bound[1:] { + case "R": + lyrX = l.bounds[1][0] + case "L": + fallthrough + default: + lyrX = l.bounds[0][0] + } + fmt.Println(JSLayer(l.Path()), fmt.Sprint(x-lyrX), fmt.Sprint(y-lyrY)) + byt, err := DoJs("moveLayer.jsx", JSLayer(l.Path()), fmt.Sprint(x-lyrX), + fmt.Sprint(y-lyrY), JSLayer(l.Path(), true)) + if err != nil { + fmt.Println("byte:", string(byt)) + panic(err) + } + var lyr LayerSet + err = json.Unmarshal(byt, &lyr) + if err != nil { + fmt.Println("byte:", string(byt)) + log.Panic(err) + } + l.bounds = lyr.bounds +} + func (l *LayerSet) Refresh() { var tmp *LayerSet - byt, err := DoJs("getLayerSet.jsx", JSLayer(l.Path())) + byt, err := DoJs("getLayerSet.jsx", JSLayer(l.Path()), JSLayer(l.Path(), true)) err = json.Unmarshal(byt, &tmp) if err != nil { - log.Println("Error in LayerSet.Refresh()", string(byt)) + log.Println("Error in LayerSet.Refresh() \"", string(byt), "\"", "for", l.Path()) log.Panic(err) } tmp.SetParent(l.Parent()) @@ -617,6 +682,7 @@ func (l *LayerSet) Refresh() { set.Refresh() } l.name = tmp.name + l.bounds = tmp.bounds l.visible = tmp.visible l.current = true }