Setup repo to be backwards compatible with go 1.10

This commit is contained in:
Unknown
2018-07-25 15:00:56 -04:00
50 changed files with 186 additions and 69 deletions

1
go.mod
View File

@@ -1 +0,0 @@
module github.com/sbrow/ps

Binary file not shown.

View File

View File

View File

@@ -1,5 +1,5 @@
![logo](logo.png)
# ps
[![GoDoc](https://godoc.org/github.com/sbrow/ps?status.svg)](https://godoc.org/github.com/sbrow/ps) [![Build Status](https://travis-ci.org/sbrow/ps.svg?branch=master)](https://travis-ci.org/sbrow/ps) [![Coverage Status](https://coveralls.io/repos/github/sbrow/ps/badge.svg?branch=master)](https://coveralls.io/github/sbrow/ps?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/sbrow/ps)](https://goreportcard.com/report/github.com/sbrow/ps)
`import "github.com/sbrow/ps"`
@@ -39,12 +39,10 @@ $ go get -u github.com/sbrow/ps
`sbrow:` (2) Make TextLayer a subclass of ArtLayer.
`sbrow:` Reduce cylcomatic complexity of ActiveDocument().
`sbrow:` Reduce cyclomatic complexity of ActiveDocument().
`sbrow:` refactor Close to Document.Close
`sbrow:` get rid of the semicolon at the end of JSLayer.
## <a name="pkg-doc">Documentation</a>
For full Documentation please visit https://godoc.org/github.com/sbrow/ps
- - -

View File

@@ -4,9 +4,8 @@ import (
"encoding/json"
"fmt"
"log"
"strings"
"github.com/sbrow/ps/runner"
"github.com/sbrow/ps/v2/runner"
)
// ArtLayer reflects some values from an Art Layer in a Photoshop document.
@@ -211,8 +210,7 @@ func (a *ArtLayer) SetVisible(b bool) error {
case false:
log.Printf("Hiding %s", a.name)
}
js := fmt.Sprintf("%s.visible=%v;",
strings.TrimRight(JSLayer(a.Path()), ";"), b)
js := fmt.Sprintf("%s.visible=%v;", JSLayer(a.Path()), b)
if byt, err := DoJS("compilejs.jsx", js); err != nil {
log.Println(string(byt))
return err

View File

@@ -22,9 +22,9 @@ type Color interface {
func Compare(a, b Color) Color {
A := a.RGB()
B := b.RGB()
Aavg := (A[0] + A[1] + A[2]) / 3
Bavg := (B[0] + B[1] + B[2]) / 3
if Aavg > Bavg {
avgA := (A[0] + A[1] + A[2]) / 3
avgB := (B[0] + B[1] + B[2]) / 3
if avgA > avgB {
return a
}
return b
@@ -42,7 +42,7 @@ func (r RGB) RGB() [3]int {
return [3]int{r.Red, r.Green, r.Blue}
}
// Hex returns the color coverted to hexidecimal format.
// Hex returns the color converted to hexadecimal format.
func (r RGB) Hex() []uint8 {
src := []uint8{uint8(r.Red), uint8(r.Green), uint8(r.Blue)}
hex := make([]byte, hex.EncodedLen(len(src)))

View File

@@ -1,7 +1,10 @@
//go:generate sh -c "godoc2md -template ./.doc.template github.com/sbrow/ps/v2 > README.md"
// Package ps is a rudimentary API between Adobe Photoshop CS5 and Golang.
// The interaction between the two is implemented using Javascript/VBScript.
//
// Use it to control Photoshop, edit documents, and perform batch operations.
//
// Currently only supports Photoshop CS5 Windows x86_64.
package ps
//
package ps // import "github.com/sbrow/ps/v2"

View File

@@ -2,17 +2,19 @@ package ps
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
)
// Document represents a Photoshop document (PSD file).
type Document struct {
name string
fullName string
height int
width int
artLayers []*ArtLayer
@@ -23,6 +25,7 @@ type Document struct {
// allows Documents to be saved to and loaded from JSON.
type DocumentJSON struct {
Name string
FullName string
Height int
Width int
ArtLayers []*ArtLayer
@@ -31,7 +34,7 @@ type DocumentJSON struct {
// MarshalJSON returns the Document in JSON format.
func (d *Document) MarshalJSON() ([]byte, error) {
return json.Marshal(&DocumentJSON{Name: d.name, Height: d.height,
return json.Marshal(&DocumentJSON{Name: d.name, FullName: d.fullName, Height: d.height,
Width: d.width, ArtLayers: d.artLayers, LayerSets: d.layerSets})
}
@@ -42,6 +45,7 @@ func (d *Document) UnmarshalJSON(b []byte) error {
return err
}
d.name = tmp.Name
d.fullName = tmp.FullName
d.height = tmp.Height
d.width = tmp.Width
d.artLayers = tmp.ArtLayers
@@ -61,6 +65,11 @@ func (d *Document) Name() string {
return d.name
}
// FullName returns the absolute path to the current document file.
func (d *Document) FullName() string {
return d.fullName
}
// Parent returns the Group that contains d.
func (d *Document) Parent() Group {
return nil
@@ -118,7 +127,7 @@ func (d *Document) LayerSet(name string) *LayerSet {
//
// TODO(sbrow): Reduce cyclomatic complexity of ActiveDocument().
func ActiveDocument() (*Document, error) {
log.Println("Loading ActiveDoucment")
log.Println("Loading ActiveDocument")
d := &Document{}
byt, err := DoJS("activeDocName.jsx")
@@ -127,7 +136,7 @@ func ActiveDocument() (*Document, error) {
}
d.name = strings.TrimRight(string(byt), "\r\n")
if Mode != Safe {
err = d.Restore(d.Filename())
err = d.Restore(d.DumpFile())
switch {
case os.IsNotExist(err):
log.Println("Previous version not found.")
@@ -165,7 +174,7 @@ func ActiveDocument() (*Document, error) {
// Restore loads document data from a JSON file.
func (d *Document) Restore(path string) error {
if path == "" {
path = d.Filename()
path = d.DumpFile()
}
byt, err := ioutil.ReadFile(path)
if err == nil {
@@ -185,26 +194,23 @@ func (d *Document) Path() string {
return ""
}
// Filename returns the path to the json file for this document.
func (d *Document) Filename() string {
_, dir, _, ok := runtime.Caller(0)
if !ok {
log.Panic("No caller information")
}
err := os.Mkdir(filepath.Join(filepath.Dir(dir), "data"), 0700)
// DumpFile returns the path to the json file where
// this document's data gets dumped. See Document.Dump
func (d *Document) DumpFile() string {
usr, err := user.Current()
if err != nil {
log.Println(err)
}
name := strings.TrimRight(d.name, "\r\n")
name = strings.TrimSuffix(name, ".psd")
return filepath.Join(filepath.Dir(dir), "data", name+".json")
path := filepath.Join(strings.Replace(d.fullName, "~", usr.HomeDir, 1))
return strings.Replace(path, ".psd", ".json", 1)
}
// Dump saves the document to disk in JSON format.
func (d *Document) Dump() {
log.Println("Dumping to disk")
log.Println(d.Filename())
f, err := os.Create(d.Filename())
log.Println(d.DumpFile())
defer d.Save()
f, err := os.Create(d.DumpFile())
if err != nil {
log.Fatal(err)
}
@@ -238,3 +244,10 @@ func (d *Document) MustExist(name string) Layer {
}
return set
}
// Save saves the Document in place.
func (d *Document) Save() error {
js := fmt.Sprintf("var d=app.open(File('%s'));\nd.save();", d.FullName())
_, err := DoJS("compilejs", js)
return err
}

106
v2/document_test.go Normal file
View File

@@ -0,0 +1,106 @@
package ps
import (
"log"
"os"
"path/filepath"
"reflect"
"runtime"
"testing"
)
// wd is the working directory
var wd string
func init() {
_, file, _, ok := runtime.Caller(0)
if !ok {
log.Fatal("runtime.Caller(0) returned !ok")
}
wd = filepath.Dir(file)
f, err := os.Create("test.log")
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
}
func TestDocument_Dump(t *testing.T) {
// Must be true for test to be valid.
Mode = Normal
tests := []struct {
name string
}{
{"Test"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Get rid of old Dump.
os.Remove(filepath.Join(wd, tt.name+".json"))
// Generate a fresh Doc (loaded slowly).
want, err := Open(filepath.Join(wd, tt.name+".psd"))
if err != nil {
t.Fatal(err)
}
// Dump the contents.
want.Dump()
// Grab a new version of the doc (loaded from json).
got, err := Open(filepath.Join(wd, tt.name+".psd"))
if err != nil {
t.Fatal(err)
}
got.layerSets[0].current = true
if !reflect.DeepEqual(got, want) {
t.Errorf("wanted: %+v\ngot: %+v", want, got)
}
})
}
}
func TestDocument_Save(t *testing.T) {
file := filepath.Join(wd, "Test.psd")
d, err := Open(file)
if err != nil {
t.Fatal(err)
}
layerName := "Group 1"
lyr := d.LayerSet(layerName)
if lyr == nil {
t.Fatalf("LayerSet '%s' was not found", layerName)
}
// Change a layer name.
_, err = DoJS(filepath.Join("SetName"), JSLayer(lyr.Path()), "Group 2")
if err != nil {
t.Error(err)
}
defer func() {
if err = DoAction("DK", "Undo"); err != nil {
t.Error(err)
}
err = d.Save()
if err != nil {
t.Fatal(err)
}
}()
err = d.Save()
if err != nil {
t.Fatal(err)
}
d2, err := Open(file)
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(d, d2) {
t.Errorf("wanted: %+v\ngot: %+v", d, d2)
}
}

View File

@@ -6,5 +6,5 @@ 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');
// Output: app.activeDocument.layerSets.getByName('Group 1').artLayers.getByName('Layer 1')
}

1
v2/go.mod Normal file
View File

@@ -0,0 +1 @@
module github.com/sbrow/ps/v2

View File

@@ -201,8 +201,7 @@ func (l *LayerSet) SetVisible(b bool) error {
if l.visible == b {
return nil
}
js := fmt.Sprintf("%s.visible=%v;", strings.TrimRight(
JSLayer(l.Path()), ";"), b)
js := fmt.Sprintf("%s.visible=%v;", JSLayer(l.Path()), b)
if _, err := DoJS("compilejs.jsx", js); err != nil {
return err
}
@@ -210,7 +209,7 @@ func (l *LayerSet) SetVisible(b bool) error {
return nil
}
// SetPos snaps the given layerset boundry to the given point.
// SetPos snaps the given layerset boundary to the given point.
// Valid options for bound are: "TL", "TR", "BL", "BR"
func (l *LayerSet) SetPos(x, y int, bound string) {
if !l.visible || (x == 0 && y == 0) {
@@ -297,10 +296,3 @@ func (l *LayerSet) Refresh() error {
l.current = true
return nil
}
func (l *LayerSet) Set(ll *LayerSet) {
if ll == nil {
panic("AHHHHHH")
}
l = ll
}

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,5 +1,3 @@
//go:generate sh -c "godoc2md -template ./.doc.template github.com/sbrow/ps > README.md"
package ps
import (
@@ -12,15 +10,15 @@ import (
"runtime"
"strings"
"github.com/sbrow/ps/runner"
"github.com/sbrow/ps/v2/runner"
)
// The full path to this directory.
var pkgpath string
var pkgPath string
func init() {
_, file, _, _ := runtime.Caller(0)
pkgpath = filepath.Dir(file)
pkgPath = filepath.Dir(file)
}
// ApplyDataset fills out a template file with information
@@ -40,9 +38,9 @@ func Close(save SaveOption) error {
return err
}
// DoAction runs the Photoshop Action with the given name from the Action Set "from".
func DoAction(action, from string) error {
_, err := runner.Run("action", action, from)
// DoAction runs the Photoshop Action with name 'action' from ActionSet 'set'.
func DoAction(set, action string) error {
_, err := runner.Run("action", set, action)
return err
}
@@ -72,8 +70,10 @@ func DoJS(path string, args ...string) ([]byte, error) {
args = append([]string{outpath.Name()}, args...)
// If passed a script by name, assume it's in the default folder.
if filepath.Dir(path) == "." {
path = filepath.Join(pkgpath, "runner", "scripts", path)
scripts := filepath.Join(pkgPath, "runner", "scripts")
b, err := filepath.Match(scripts, path)
if !b || err != nil {
path = filepath.Join(scripts, path)
}
args = append([]string{path}, args...)
@@ -99,8 +99,6 @@ func Init() 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.
//
// TODO(sbrow): get rid of the semicolon at the end of JSLayer.
func JSLayer(path string) string {
pth := strings.Split(path, "/")
js := "app.activeDocument"
@@ -113,7 +111,7 @@ func JSLayer(path string) string {
if pth[last] != "" {
js += fmt.Sprintf(".artLayers.getByName('%s')", pth[last])
}
return js + ";"
return js
}
// JSLayerMerge gets the Javascript code to get the Layer or LayerSet with this path
@@ -129,9 +127,11 @@ func JSLayerMerge(path string) string {
// 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 := runner.Run("open", path)
return err
func Open(path string) (*Document, error) {
if _, err := runner.Run("open", path); err != nil {
return nil, err
}
return ActiveDocument()
}
// Quit exits Photoshop, closing all open documents using the given save option.

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"testing"
"github.com/sbrow/ps/runner"
"github.com/sbrow/ps/v2/runner"
)
/*

View File

@@ -1,3 +1,4 @@
![logo](logo.png)
# runner
[![GoDoc](https://godoc.org/github.com/sbrow/ps/runner?status.svg)](https://godoc.org/github.com/sbrow/runner) [![Build Status](https://travis-ci.org/sbrow/runner.svg?branch=master)](https://travis-ci.org/sbrow/runner) [![Coverage Status](https://coveralls.io/repos/github/sbrow/runner/badge.svg?branch=master)](https://coveralls.io/github/sbrow/runner?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/sbrow/ps/runner)](https://goreportcard.com/report/github.com/sbrow/ps/runner)

View File

@@ -1,10 +1,10 @@
//go:generate sh -c "godoc2md -template ../.doc.template github.com/sbrow/ps/runner > README.md"
//go:generate sh -c "godoc2md -template ../.doc.template github.com/sbrow/ps/v2/runner > README.md"
// Package runner runs the non-go code that Photoshop understands,
// and passes it to back to the go program. Currently, this is
// primarily implemented through Adobe Extendscript, but hopefully
// in the future it will be upgraded to a C++ plugin.
package runner
package runner // import "github.com/sbrow/ps/v2/runner"
import (
"bytes"
@@ -51,7 +51,10 @@ func Run(name string, args ...string) ([]byte, error) {
cmd := exec.Command(std.Cmd, parseArgs(name, args...)...)
cmd.Stdout, cmd.Stderr = &out, &errs
if err := cmd.Run(); err != nil || len(errs.Bytes()) != 0 {
return out.Bytes(), fmt.Errorf("err: \"%s %s\"\nargs: \"%s\"\nout: \"%s\"", err, errs.String(), args, out.String())
return out.Bytes(), fmt.Errorf(`err: "%s"
errs.String(): "%s"
args: "%s"
out: "%s"`, err, errs.String(), args, out.String())
}
return out.Bytes(), nil
}

View File

@@ -0,0 +1,5 @@
#include lib.js
var stdout=newFile(arguments[0]);
var obj=eval(arguments[1]);
obj.name=arguments[2];
stdout.close();

View File

@@ -1,5 +1,6 @@
' Runs an action with the given name (Argument 1) from the given set (Argument 0).
set appRef = CreateObject("Photoshop.Application")
' No dialogs'
' No dialogs.
dlgMode = 3
set desc = CreateObject( "Photoshop.ActionDescriptor" )

View File

@@ -4,8 +4,6 @@ Set appRef = CreateObject("Photoshop.Application")
if wScript.Arguments.Count = 0 then
wScript.Echo "Missing parameters"
else
' wScript.Echo wScript.Arguments(0)
' wScript.Echo wScript.Arguments(1)
path = wScript.Arguments(0)
args = wScript.Arguments(1)
error = appRef.DoJavaScriptFile(path, Split(args, ",,"))

View File

@@ -1,7 +1,7 @@
#include lib.js
var stdout = newFile(arguments[0]);
var doc = app.activeDocument;
stdout.writeln(('{"Name": "'+doc.name+'", "Height":'+doc.height+
stdout.writeln(('{"Name": "'+doc.name+'", "FullName": "'+doc.fullName+'", "Height":'+doc.height+
', "Width":'+doc.width+', "ArtLayers": [').replace(/ px/g, ""));
stdout.writeln(layers(doc.artLayers))

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"log"
"strings"
)
// TextItem holds the text element of a TextLayer.
@@ -62,7 +61,7 @@ func (t *TextItem) SetText(txt string) {
return
}
var err error
lyr := strings.TrimRight(JSLayer(t.parent.Path()), ";")
lyr := 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)
@@ -87,7 +86,7 @@ func (t *TextItem) SetSize(s float64) {
if t.size == s {
return
}
lyr := strings.TrimRight(JSLayer(t.parent.Path()), ";")
lyr := JSLayer(t.parent.Path())
js := fmt.Sprintf("%s.textItem.size=%f;", lyr, s)
_, err := DoJS("compilejs.jsx", js)
if err != nil {