diff --git a/cmd/jfifcom/asdf.jpg b/cmd/jfifcom/asdf.jpg new file mode 100644 index 0000000..2b90651 Binary files /dev/null and b/cmd/jfifcom/asdf.jpg differ diff --git a/cmd/jfifcom/jfifcom b/cmd/jfifcom/jfifcom new file mode 100755 index 0000000..8a4eab8 Binary files /dev/null and b/cmd/jfifcom/jfifcom differ diff --git a/cmd/jfifcom/main.go b/cmd/jfifcom/main.go new file mode 100644 index 0000000..8948ccf --- /dev/null +++ b/cmd/jfifcom/main.go @@ -0,0 +1,63 @@ +// jfifcom embeds a new comment segment with the data from stdin +// before the start of stream (SOS) segment. +package main + +import ( + "flag" + "fmt" + "io" + "io/ioutil" + "os" + + "neilpa.me/go-jfif" +) + +func main() { + os.Exit(realMain(os.Args[1:], os.Stdin)) +} + +func realMain(args []string, stdin io.Reader) int { + flag.Usage = printUsage + flag.CommandLine.Parse(args) + + if flag.NArg() == 0 { + return usageError("no files specified") + } + + buf, err := ioutil.ReadAll(stdin) + if err != nil { + return fatal(err.Error()) + } + + for _, arg := range flag.Args() { + //fmt.Println("embeddding", arg, "buf", buf) + + err = jfif.Append(arg, jfif.Patch{jfif.COM, buf}) + if err != nil { + return fatal(err.Error()) // todo: continue writing the other files? + } + } + return 0 +} + +func fatal(format string, args ...interface{}) int { + format = os.Args[0] + ": " + format + "\n" + fmt.Fprintf(os.Stderr, format, args...) + return 1 +} + +func usageError(msg string) int { + fmt.Fprintln(os.Stderr, msg) + printUsage() + return 2 +} + +func printUsage() { + fmt.Fprintf(os.Stderr, `Usage: %s jpeg [jpeg...] < ... + + jfifcomment embeds a new comment segment with the data from stdin + before the start of stream (SOS) segment. +`, os.Args[0]) + flag.PrintDefaults() + fmt.Fprintln(os.Stderr) +} diff --git a/cmd/jfifcom/main_test.go b/cmd/jfifcom/main_test.go new file mode 100644 index 0000000..c3a1129 --- /dev/null +++ b/cmd/jfifcom/main_test.go @@ -0,0 +1,71 @@ +package main + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestMain(t *testing.T) { + root := filepath.Join("..", "..", "testdata") + + tests := []struct { + in string + golden string + }{ + { + "min.jpg", + "min.jfifcom.jpg", + }, + } + + for _, tt := range tests { + t.Run(tt.golden, func(t *testing.T) { + temp, err := ioutil.TempFile(os.TempDir(), "jfifcom-test-main-"+tt.in) + if err != nil { + t.Fatal(err) + } + path := temp.Name() + defer os.Remove(path) + defer temp.Close() + + src, err := os.Open(filepath.Join(root, tt.in)) + if err != nil { + t.Fatal(err) + } + defer src.Close() + + _, err = io.Copy(temp, src) + if err != nil { + t.Fatal(err) + } + temp.Close() + src.Close() + + exit := realMain([]string{path}, strings.NewReader("hello")) + if exit != 0 { + t.Fatalf("invalid exit %d", exit) + } + + compareFiles(t, path, filepath.Join(root, tt.golden)) + }) + } +} + +func compareFiles(t *testing.T, path, golden string) { + want, err := ioutil.ReadFile(golden) + if err != nil { + t.Fatal(err) + } + got, err := ioutil.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Errorf("bytes don't match\ngot: % x\nwant: % x", got, want) // TODO Better diff + } +} diff --git a/cmd/jfifcom/min.jpg b/cmd/jfifcom/min.jpg new file mode 100644 index 0000000..71911bf Binary files /dev/null and b/cmd/jfifcom/min.jpg differ diff --git a/testdata/min.jfifcom.jpg b/testdata/min.jfifcom.jpg new file mode 100644 index 0000000..04612f0 Binary files /dev/null and b/testdata/min.jfifcom.jpg differ