mirror of
				https://github.com/axllent/goptimize.git
				synced 2025-11-04 03:48:28 -05:00 
			
		
		
		
	Compare commits
	
		
			12 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ee6aa69087 | ||
| 
						 | 
					8362617920 | ||
| 
						 | 
					b157fcd72b | ||
| 
						 | 
					0c000fe262 | ||
| 
						 | 
					97fa6c94c5 | ||
| 
						 | 
					36e9b4c8fa | ||
| 
						 | 
					5df486c53e | ||
| 
						 | 
					120e5fefde | ||
| 
						 | 
					d2a591a6d9 | ||
| 
						 | 
					8e5e7b6098 | ||
| 
						 | 
					47024e030b | ||
| 
						 | 
					45915d4b42 | 
@@ -1,5 +1,10 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [dev]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Switch to [pflag](https://github.com/spf13/pflag) for better flag management
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [0.0.1]
 | 
					## [0.0.1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Initial release
 | 
					- Initial release
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							@@ -6,7 +6,7 @@ build = echo "\n\nBuilding $(1)-$(2)" && GOOS=$(1) GOARCH=$(2) go build ${LDFLAG
 | 
				
			|||||||
	&& bzip2 dist/goptimize_${VERSION}_$(1)_$(2)
 | 
						&& bzip2 dist/goptimize_${VERSION}_$(1)_$(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
goptimize: *.go
 | 
					goptimize: *.go
 | 
				
			||||||
	go get github.com/disintegration/imaging
 | 
						go get github.com/disintegration/imaging golang.org/x/image/bmp golang.org/x/image/tiff github.com/axllent/gitrel github.com/spf13/pflag
 | 
				
			||||||
	go build ${LDFLAGS} -o goptimize
 | 
						go build ${LDFLAGS} -o goptimize
 | 
				
			||||||
	rm -rf /tmp/go-*
 | 
						rm -rf /tmp/go-*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,6 +16,7 @@ clean:
 | 
				
			|||||||
release:
 | 
					release:
 | 
				
			||||||
	mkdir -p dist
 | 
						mkdir -p dist
 | 
				
			||||||
	rm -f dist/goptimize_${VERSION}_*
 | 
						rm -f dist/goptimize_${VERSION}_*
 | 
				
			||||||
 | 
						go get github.com/disintegration/imaging golang.org/x/image/bmp golang.org/x/image/tiff github.com/axllent/gitrel github.com/spf13/pflag
 | 
				
			||||||
	$(call build,linux,amd64)
 | 
						$(call build,linux,amd64)
 | 
				
			||||||
	$(call build,linux,386)
 | 
						$(call build,linux,386)
 | 
				
			||||||
	$(call build,linux,arm)
 | 
						$(call build,linux,arm)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								README.md
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
				
			|||||||
# Goptimizer - downscales and optimizes images
 | 
					# Goptimizer - downscales and optimizes images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Goptimizer is a commandline utility written in Golang. It downscales and optimize existing images JPEG, PNG and Gif files.
 | 
					Goptimizer is a commandline utility written in Golang. It downscales and optimizes JPEG, PNG and Gif files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image downscaling is done within Goptimize (`-m <width>x<height>`, see [Usage](#usage-options)), however optimization is done using the following additional tools (if they are installed):
 | 
					Image downscaling/rotation is done within goptimize (`-m <width>x<height>`, see [Usage](#usage-options)), however optimization is done using the following additional tools (if they are installed):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- jpegoptim
 | 
					- jpegoptim
 | 
				
			||||||
- jpegtran (`libjpeg-turbo-progs`)
 | 
					- jpegtran (`libjpeg-turbo-progs`)
 | 
				
			||||||
@@ -28,23 +28,18 @@ It will also preserve (by default) the file's original modification times (`-p=f
 | 
				
			|||||||
Usage: ./goptimize [options] <images>
 | 
					Usage: ./goptimize [options] <images>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Options:
 | 
					Options:
 | 
				
			||||||
  -gifsicle string
 | 
					  -q, --quality int        quality, JPEG only (default 75)
 | 
				
			||||||
        gifsicle binary (default "gifsicle")
 | 
					  -m, --max string         downscale to a maximum width & height in pixels (<width>x<height>)
 | 
				
			||||||
  -jpegoptim string
 | 
					  -o, --out string         output directory (default overwrites original)
 | 
				
			||||||
        jpegoptim binary (default "jpegoptim")
 | 
					  -p, --preserve           preserve file modification times (default true)
 | 
				
			||||||
  -jpegtran string
 | 
					  -u, --update             update to latest release
 | 
				
			||||||
        jpegtran binary (default "jpegtran")
 | 
					  -v, --version            show version number
 | 
				
			||||||
  -m string
 | 
					  -h, --help               show help
 | 
				
			||||||
        downscale to a maximum width & height in pixels (<width>x<height>)
 | 
					      --jpegtran string    jpegtran binary (default "jpegtran")
 | 
				
			||||||
  -o string
 | 
					      --jpegoptim string   jpegoptim binary (default "jpegoptim")
 | 
				
			||||||
        output directory (default overwrites original)
 | 
					      --gifsicle string    gifsicle binary (default "gifsicle")
 | 
				
			||||||
  -optipng string
 | 
					      --pngquant string    pngquant binary (default "pngquant")
 | 
				
			||||||
        optipng binary (default "optipng")
 | 
					      --optipng string     optipng binary (default "optipng")
 | 
				
			||||||
  -p    preserve file modification times (default true)
 | 
					 | 
				
			||||||
  -pngquant string
 | 
					 | 
				
			||||||
        pngquant binary (default "pngquant")
 | 
					 | 
				
			||||||
  -q int
 | 
					 | 
				
			||||||
        quality - JPEG only (default 75)
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,3 +49,19 @@ Options:
 | 
				
			|||||||
- `./goptimize -m 800x800 *` - optimize and downscale all image files to a maximum size of 800x800px
 | 
					- `./goptimize -m 800x800 *` - optimize and downscale all image files to a maximum size of 800x800px
 | 
				
			||||||
- `./goptimize -m 1200x0 image.jpg` - optimize and downscale a JPG file to a maximum size of width of 1200px
 | 
					- `./goptimize -m 1200x0 image.jpg` - optimize and downscale a JPG file to a maximum size of width of 1200px
 | 
				
			||||||
- `./goptimize -o out/ image.jpg` - optimize a JPG file and save it to `out/`
 | 
					- `./goptimize -o out/ image.jpg` - optimize a JPG file and save it to `out/`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Download the appropriate binary from the [releases](https://github.com/axllent/goptimize/releases/latest), or if you have golang installed 
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					go get github.com/axllent/goptimize
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some ideas for the future:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Dry run
 | 
				
			||||||
 | 
					- Option to copy exif data (how?)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								goptimize.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								goptimize.go
									
									
									
									
									
								
							@@ -32,7 +32,7 @@ func Goptimize(file string) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// open original, rotate if neccesary
 | 
						// open original, rotate if necessary
 | 
				
			||||||
	src, err := imaging.Open(file, imaging.AutoOrientation(true))
 | 
						src, err := imaging.Open(file, imaging.AutoOrientation(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -116,19 +116,19 @@ func Goptimize(file string) {
 | 
				
			|||||||
	if format.String() == "JPEG" {
 | 
						if format.String() == "JPEG" {
 | 
				
			||||||
		// run one or the other, running both has no advantage
 | 
							// run one or the other, running both has no advantage
 | 
				
			||||||
		if jpegtran != "" {
 | 
							if jpegtran != "" {
 | 
				
			||||||
			RunOptimiser(tmpFilename, true, jpegtran, "-optimize", "-outfile")
 | 
								RunOptimizer(tmpFilename, true, jpegtran, "-optimize", "-outfile")
 | 
				
			||||||
		} else if jpegoptim != "" {
 | 
							} else if jpegoptim != "" {
 | 
				
			||||||
			RunOptimiser(tmpFilename, false, jpegoptim, "-f", "-s", "-o")
 | 
								RunOptimizer(tmpFilename, false, jpegoptim, "-f", "-s", "-o")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if format.String() == "PNG" {
 | 
						} else if format.String() == "PNG" {
 | 
				
			||||||
		if pngquant != "" {
 | 
							if pngquant != "" {
 | 
				
			||||||
			RunOptimiser(tmpFilename, true, pngquant, "-f", "--output")
 | 
								RunOptimizer(tmpFilename, true, pngquant, "-f", "--output")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if optipng != "" {
 | 
							if optipng != "" {
 | 
				
			||||||
			RunOptimiser(tmpFilename, true, optipng, "-out")
 | 
								RunOptimizer(tmpFilename, true, optipng, "-out")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if format.String() == "GIF" && gifsicle != "" {
 | 
						} else if format.String() == "GIF" && gifsicle != "" {
 | 
				
			||||||
		RunOptimiser(tmpFilename, true, gifsicle, "-o")
 | 
							RunOptimizer(tmpFilename, true, gifsicle, "-o")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// re-open modified temporary file
 | 
						// re-open modified temporary file
 | 
				
			||||||
@@ -166,7 +166,7 @@ func Goptimize(file string) {
 | 
				
			|||||||
		defer out.Close()
 | 
							defer out.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if _, err := io.Copy(out, tmpFile); err != nil {
 | 
							if _, err := io.Copy(out, tmpFile); err != nil {
 | 
				
			||||||
			fmt.Printf("Error ovewriting original file: %v\n", err)
 | 
								fmt.Printf("Error overwriting original file: %v\n", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -215,9 +215,9 @@ func Goptimize(file string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunOptimiser will run the specified command on a copy of the temporary file,
 | 
					// RunOptimizer will run the specified command on a copy of the temporary file,
 | 
				
			||||||
// and overwrite it if the output is smaller than the original
 | 
					// and overwrite it if the output is smaller than the original
 | 
				
			||||||
func RunOptimiser(src string, outFileArg bool, args ...string) {
 | 
					func RunOptimizer(src string, outFileArg bool, args ...string) {
 | 
				
			||||||
	// create a new temp file
 | 
						// create a new temp file
 | 
				
			||||||
	tmpFile, err := ioutil.TempFile(os.TempDir(), "Goptimized-")
 | 
						tmpFile, err := ioutil.TempFile(os.TempDir(), "Goptimized-")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										40
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								main.go
									
									
									
									
									
								
							@@ -1,7 +1,6 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"flag"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
@@ -9,6 +8,7 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/axllent/gitrel"
 | 
						"github.com/axllent/gitrel"
 | 
				
			||||||
 | 
						"github.com/spf13/pflag"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -26,11 +26,15 @@ var (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
						// set up new flag instance
 | 
				
			||||||
 | 
						flag := pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// set the default help
 | 
						// set the default help
 | 
				
			||||||
	flag.Usage = func() {
 | 
						flag.Usage = func() {
 | 
				
			||||||
		fmt.Println("Goptimize - downscales and optimizes images")
 | 
							fmt.Println("Goptimize - downscales and optimizes images")
 | 
				
			||||||
		fmt.Printf("\nUsage: %s [options] <images>\n", os.Args[0])
 | 
							fmt.Printf("\nUsage: %s [options] <images>\n", os.Args[0])
 | 
				
			||||||
		fmt.Println("\nOptions:")
 | 
							fmt.Println("\nOptions:")
 | 
				
			||||||
 | 
							flag.SortFlags = false
 | 
				
			||||||
		flag.PrintDefaults()
 | 
							flag.PrintDefaults()
 | 
				
			||||||
		fmt.Println("\nExamples:")
 | 
							fmt.Println("\nExamples:")
 | 
				
			||||||
		fmt.Printf("  %s image.png\n", os.Args[0])
 | 
							fmt.Printf("  %s image.png\n", os.Args[0])
 | 
				
			||||||
@@ -47,24 +51,27 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var maxSizes string
 | 
						var maxSizes string
 | 
				
			||||||
	var update, showversion bool
 | 
						var update, showversion, showhelp bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flag.IntVar(&quality, "q", 75, "quality - JPEG only")
 | 
						flag.IntVarP(&quality, "quality", "q", 75, "quality, JPEG only")
 | 
				
			||||||
	flag.StringVar(&outputDir, "o", "", "output directory (default overwrites original)")
 | 
						flag.StringVarP(&maxSizes, "max", "m", "", "downscale to a maximum width & height in pixels (<width>x<height>)")
 | 
				
			||||||
	flag.BoolVar(&preserveModTimes, "p", true, "preserve file modification times")
 | 
						flag.StringVarP(&outputDir, "out", "o", "", "output directory (default overwrites original)")
 | 
				
			||||||
	flag.StringVar(&maxSizes, "m", "", "downscale to a maximum width & height in pixels (<width>x<height>)")
 | 
						flag.BoolVarP(&preserveModTimes, "preserve", "p", true, "preserve file modification times")
 | 
				
			||||||
	flag.BoolVar(&update, "u", false, "update to latest release")
 | 
						flag.BoolVarP(&update, "update", "u", false, "update to latest release")
 | 
				
			||||||
	flag.BoolVar(&showversion, "v", false, "show version number")
 | 
						flag.BoolVarP(&showversion, "version", "v", false, "show version number")
 | 
				
			||||||
 | 
						flag.BoolVarP(&showhelp, "help", "h", false, "show help")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// third-party optimizers
 | 
						// third-party optimizers
 | 
				
			||||||
	flag.StringVar(&gifsicle, "gifsicle", "gifsicle", "gifsicle binary")
 | 
					 | 
				
			||||||
	flag.StringVar(&jpegoptim, "jpegoptim", "jpegoptim", "jpegoptim binary")
 | 
					 | 
				
			||||||
	flag.StringVar(&jpegtran, "jpegtran", "jpegtran", "jpegtran binary")
 | 
						flag.StringVar(&jpegtran, "jpegtran", "jpegtran", "jpegtran binary")
 | 
				
			||||||
	flag.StringVar(&optipng, "optipng", "optipng", "optipng binary")
 | 
						flag.StringVar(&jpegoptim, "jpegoptim", "jpegoptim", "jpegoptim binary")
 | 
				
			||||||
 | 
						flag.StringVar(&gifsicle, "gifsicle", "gifsicle", "gifsicle binary")
 | 
				
			||||||
	flag.StringVar(&pngquant, "pngquant", "pngquant", "pngquant binary")
 | 
						flag.StringVar(&pngquant, "pngquant", "pngquant", "pngquant binary")
 | 
				
			||||||
 | 
						flag.StringVar(&optipng, "optipng", "optipng", "optipng binary")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// parse flags
 | 
						flag.SortFlags = false
 | 
				
			||||||
	flag.Parse()
 | 
					
 | 
				
			||||||
 | 
						// parse args excluding os.Args[0]
 | 
				
			||||||
 | 
						flag.Parse(os.Args[1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// detect optimizer paths
 | 
						// detect optimizer paths
 | 
				
			||||||
	gifsicle, _ = exec.LookPath(gifsicle)
 | 
						gifsicle, _ = exec.LookPath(gifsicle)
 | 
				
			||||||
@@ -73,6 +80,11 @@ func main() {
 | 
				
			|||||||
	optipng, _ = exec.LookPath(optipng)
 | 
						optipng, _ = exec.LookPath(optipng)
 | 
				
			||||||
	pngquant, _ = exec.LookPath(pngquant)
 | 
						pngquant, _ = exec.LookPath(pngquant)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if showhelp {
 | 
				
			||||||
 | 
							flag.Usage()
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if showversion {
 | 
						if showversion {
 | 
				
			||||||
		fmt.Println(fmt.Sprintf("Version: %s", version))
 | 
							fmt.Println(fmt.Sprintf("Version: %s", version))
 | 
				
			||||||
		latest, _, _, err := gitrel.Latest("axllent/goptimize", "goptimize")
 | 
							latest, _, _, err := gitrel.Latest("axllent/goptimize", "goptimize")
 | 
				
			||||||
@@ -88,7 +100,7 @@ func main() {
 | 
				
			|||||||
			fmt.Println(err)
 | 
								fmt.Println(err)
 | 
				
			||||||
			os.Exit(1)
 | 
								os.Exit(1)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fmt.Printf("Updated %s to version %s", os.Args[0], rel)
 | 
							fmt.Printf("Updated %s to version %s\n", os.Args[0], rel)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user