# Supplementary Material (ESI) for Nanoscale # This journal is (c) The Royal Society of Chemistry 2011 // written by Benny Siegert , NS3E, UMR 3208 ISL/CNRS // Copyright (C) 2010-2011 CNRS / ISL. All rights reserved. // package main import ( "bytes" "flag" "fmt" "image" "image/jpeg" "image/png" "io/ioutil" "os" "path/filepath" "runtime" "strings" ) var line = flag.Int("l", 104, "line number of each input file") var outputfile = flag.String("o", "out.png", "name of the output file") func openImage(filename string) *bytes.Buffer { b, err := ioutil.ReadFile(filename) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } return bytes.NewBuffer(b) } // glob expands shell patterns (like *.jpg) in its arguments if // running on Windows. func glob(patterns []string) []string { if runtime.GOOS != "windows" { return patterns } filenames := make([]string, 0, len(patterns)) for _, p := range patterns { matches := filepath.Glob(strings.Replace(p, "\\", "/", -1)) filenames = append(filenames, matches...) } return filenames } // createOutputLine decodes the jpeg image in buf and writes the pixels // in line i into out. It runs as a goroutine and sends a value on done // when it finishes. func createOutputLine(minX, maxX, i int, buf *bytes.Buffer, out *image.NRGBA, done chan bool) { img, err := jpeg.Decode(buf) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } for j := minX; j < maxX; j++ { out.Set(j, i, img.At(j, *line)) } done <- true } // The principal function of this program. For each of the files, // copy exactly one horizontal line into the output. func createOutput(minX, maxX int, files []string) image.Image { var ( num int // number of images i int file string ) out := image.NewNRGBA(maxX-minX, len(files)) done := make(chan bool, len(files)) for i, file = range files { num++ go createOutputLine(minX, maxX, i, openImage(file), out, done) } for i = 0; i < num; i++ { <-done } return out } func main() { var minX, maxX int runtime.GOMAXPROCS(2) flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [flags] imagefile ...\n\nFlags:\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() if flag.NArg() == 0 { flag.Usage() os.Exit(2) } // expand wildcards in the file name arguments (for Windows) filenames := glob(flag.Args()) // open the first input file to determine the width and to check if the // line number is valid config, err := jpeg.DecodeConfig(openImage(filenames[0])) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } minX = 0 maxX = config.Width if *line < 0 || *line >= config.Height { fmt.Fprintf(os.Stderr, "%s: value for line is out of range, must be between 0 and %d\n", os.Args[0], config.Height) os.Exit(2) } // now build and write the output f, err := os.Open(*outputfile, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0644) if err != nil { fmt.Fprintln(os.Stderr, "while opening output file:", err) os.Exit(3) } defer f.Close() err = png.Encode(f, createOutput(minX, maxX, filenames)) if err != nil { fmt.Fprintln(os.Stderr, "while writing output file:", err) os.Exit(3) } }