-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
1,781 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
data/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package ps | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
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. | ||
type ModeEnum int | ||
|
||
// Holds the current mode. | ||
var Mode ModeEnum | ||
|
||
// Fast mode never checks layers before returning. | ||
const Fast ModeEnum = 2 | ||
|
||
// Normal Mode Always checks to see if layers are up to date | ||
// before returning them. | ||
const Normal ModeEnum = 0 | ||
|
||
// Safe Mode Always loads the document from scratch. (Very Slow) | ||
const Safe ModeEnum = 1 | ||
|
||
// PSSaveOptions is an enum for options when closing a document. | ||
type PSSaveOptions int | ||
|
||
func (p *PSSaveOptions) String() string { | ||
return fmt.Sprint("", *p) | ||
} | ||
|
||
// PSSaveChanges saves changes before closing documents. | ||
const PSSaveChanges PSSaveOptions = 1 | ||
|
||
// PSDoNotSaveChanges closes documents without saving. | ||
const PSDoNotSaveChanges PSSaveOptions = 2 | ||
|
||
// PSPromptToSaveChanges prompts the user whether to save each | ||
// document before closing it. | ||
const PSPromptToSaveChanges PSSaveOptions = 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package ps | ||
|
||
import ( | ||
"encoding/hex" | ||
// "fmt" | ||
) | ||
|
||
// Color is an interface for color objects, allowing colors to be | ||
// used in various formats. | ||
// | ||
// RGB is the default format for everything. | ||
type Color interface { | ||
RGB() [3]int // The color in RGB format. | ||
Hex() []uint8 // The color in hexadecimal format. | ||
} | ||
|
||
// Compare determines which of two colors is "brighter". | ||
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 { | ||
return a | ||
} | ||
return b | ||
} | ||
|
||
// RGB is a color in RGB format. It fulfills the Color interface. | ||
type RGB struct { | ||
Red int | ||
Green int | ||
Blue int | ||
} | ||
|
||
// RGB returns the color in RGB format. | ||
func (r RGB) RGB() [3]int { | ||
return [3]int{r.Red, r.Green, r.Blue} | ||
} | ||
|
||
// TODO: Implement RGB.Hex() | ||
func (r RGB) Hex() []uint8 { | ||
return make([]uint8, 6) | ||
} | ||
|
||
// Hex is a color in hexadecimal format. It fulfills the Color interface. | ||
type Hex []uint8 | ||
|
||
func (h Hex) RGB() [3]int { | ||
src := []byte(h) | ||
dst := make([]byte, hex.DecodedLen(len(src))) | ||
_, err := hex.Decode(dst, src) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return [3]int{int(dst[0]), int(dst[1]), int(dst[2])} | ||
} | ||
|
||
func (h Hex) Hex() []uint8 { | ||
return h | ||
} | ||
|
||
// Stroke represents a layer stroke effect. | ||
type Stroke struct { | ||
Size float32 | ||
Color | ||
} | ||
|
||
// func (s *Stroke) String() string { | ||
// return fmt.Sprintf("%vpt %v", s.Size, s.Color.RGB()) | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,181 @@ | ||
// Package ps is a rudimentary API between Adobe Photoshop CS5 and Golang. | ||
// | ||
// Most of the interaction between the two is implemented via | ||
// Javascript and/or VBS/Applescript. | ||
// | ||
// Currently only works with CS5 on Windows. | ||
package ps | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
// "log" | ||
"os" | ||
"os/exec" | ||
"path" | ||
"path/filepath" | ||
"runtime" | ||
"strings" | ||
) | ||
|
||
const ( | ||
Cmd = "cscript.exe" | ||
Opts = "/nologo" | ||
) | ||
var Cmd string | ||
var Opts string | ||
var pkgpath string | ||
|
||
var PKGPATH = path.Join(os.Getenv("GOPATH"), "src", "github.com", "sbrow", "ps") | ||
func init() { | ||
_, file, _, _ := runtime.Caller(0) | ||
pkgpath = filepath.Dir(file) | ||
switch runtime.GOOS { | ||
case "windows": | ||
Cmd = "cscript.exe" | ||
Opts = "/nologo" | ||
case "darwin": | ||
Cmd = "osacript" | ||
} | ||
} | ||
|
||
// Start opens Photoshop. | ||
func Start() error { | ||
_, err := run("start") | ||
return err | ||
} | ||
|
||
func Open(path string) ([]byte, error) { | ||
return run("open", path) | ||
// Close closes the active document in Photoshop. | ||
func Close(save PSSaveOptions) error { | ||
_, err := run("close", save.String()) | ||
return err | ||
} | ||
|
||
func Close() error { | ||
_, err := run("close") | ||
// 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 | ||
} | ||
|
||
func Quit() ([]byte, error) { | ||
return run("quit") | ||
// Quit exits Photoshop with the given saving option. | ||
func Quit(save PSSaveOptions) error { | ||
_, err := run("quit", save.String()) | ||
return err | ||
} | ||
|
||
func Js(args ...string) ([]byte, error) { | ||
return run("dojs", args...) | ||
// SaveAs saves the Photoshop document to the given location. | ||
func SaveAs(path string) error { | ||
_, err := run("save", path) | ||
return err | ||
} | ||
|
||
// DoJs runs a Photoshop Javascript script file (.jsx) from the specified location. | ||
// It can't directly return output, so instead the scripts write their output to | ||
// a temporary file, whose contents is then read and returned. | ||
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) | ||
if !strings.HasSuffix(path, ".jsx") { | ||
path += ".jsx" | ||
} | ||
|
||
args = append([]string{outpath}, args...) | ||
|
||
// If passed a script by name, assume it's in the default folder. | ||
if filepath.Dir(path) == "." { | ||
path = filepath.Join(pkgpath, "scripts", path) | ||
} | ||
|
||
args = append([]string{path}, args...) | ||
cmd, err := run("dojs", args...) | ||
if err == nil { | ||
file, err := ioutil.ReadFile(outpath) | ||
if err == nil { | ||
cmd = append(cmd, file...) | ||
} | ||
} | ||
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. | ||
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 dir string | ||
var out bytes.Buffer | ||
var stderr bytes.Buffer | ||
var errs bytes.Buffer | ||
|
||
switch runtime.GOOS { | ||
case "windows": | ||
ext = ".vbs" | ||
dir = "win" | ||
case "darwin": | ||
ext = ".applescript" | ||
dir = "mac" | ||
} | ||
if !strings.HasSuffix(name, ext) { | ||
name += ext | ||
} | ||
args = append([]string{Opts, path.Join(PKGPATH, dir, name)}, args...) | ||
|
||
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(Cmd, args...) | ||
cmd.Stdout = &out | ||
cmd.Stderr = &stderr | ||
cmd.Stderr = &errs | ||
err := cmd.Run() | ||
return out.Bytes(), err | ||
if err != nil || len(errs.Bytes()) != 0 { | ||
return out.Bytes(), errors.New(string(errs.Bytes())) | ||
} | ||
return out.Bytes(), nil | ||
} | ||
|
||
// DoAction runs the Photoshop action with name from 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 (if any); you will have to implement syncing | ||
// them yourself. | ||
func ApplyDataset(name string) ([]byte, error) { | ||
return DoJs("applyDataset.jsx", name) | ||
} | ||
|
||
// 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, 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]) | ||
} | ||
} | ||
if pth[last] != "" { | ||
js += fmt.Sprintf(".artLayers.getByName('%s')", pth[last]) | ||
} | ||
return js + ";" | ||
} |
Oops, something went wrong.