add encodeImage and encodeImageMagick

This commit is contained in:
Milan Nikolic
2015-11-05 04:53:35 +01:00
parent d70de9f4db
commit bbcaf0f9dd

View File

@@ -23,7 +23,7 @@ import (
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
_ "image/gif" "image/gif"
"image/jpeg" "image/jpeg"
"image/png" "image/png"
"io" "io"
@@ -46,7 +46,7 @@ import (
"github.com/gographics/imagick/imagick" "github.com/gographics/imagick/imagick"
_ "github.com/hotei/bmp" _ "github.com/hotei/bmp"
"github.com/skarademir/naturalsort" "github.com/skarademir/naturalsort"
_ "golang.org/x/image/tiff" "golang.org/x/image/tiff"
_ "golang.org/x/image/webp" _ "golang.org/x/image/webp"
"gopkg.in/alecthomas/kingpin.v2" "gopkg.in/alecthomas/kingpin.v2"
) )
@@ -130,116 +130,60 @@ func convertImage(img image.Image, index int, pathName string) {
filename = filepath.Join(workdir, fmt.Sprintf("%03d.%s", index, ext)) filename = filepath.Join(workdir, fmt.Sprintf("%03d.%s", index, ext))
} }
var i image.Image if opts.ToPNG {
// convert image to PNG
if opts.Width > 0 || opts.Height > 0 { if opts.Grayscale {
i = imaging.Resize(img, opts.Width, opts.Height, filters[opts.Filter]) encodeImageMagick(img, filename)
} else {
encodeImage(img, filename)
}
} else if opts.ToBMP {
// convert image to 4-Bit BMP (16 colors)
encodeImageMagick(img, filename)
} else if opts.ToGIF {
// convert image to GIF
encodeImageMagick(img, filename)
} else { } else {
i = img // convert image to JPEG (default)
if opts.Grayscale {
encodeImageMagick(img, filename)
} else {
encodeImage(img, filename)
}
} }
if opts.Grayscale { <-throttle
i = imaging.Grayscale(img) }
// Transforms image (resize|rotate|flip)
func transformImage(img image.Image) image.Image {
var i image.Image = img
if opts.Width > 0 || opts.Height > 0 {
i = imaging.Resize(i, opts.Width, opts.Height, filters[opts.Filter])
} }
if opts.Rotate > 0 { if opts.Rotate > 0 {
switch opts.Rotate { switch opts.Rotate {
case 90: case 90:
i = imaging.Rotate90(img) i = imaging.Rotate90(i)
case 180: case 180:
i = imaging.Rotate180(img) i = imaging.Rotate180(i)
case 270: case 270:
i = imaging.Rotate270(img) i = imaging.Rotate270(i)
} }
} }
if opts.Flip != "none" { if opts.Flip != "none" {
switch opts.Flip { switch opts.Flip {
case "horizontal": case "horizontal":
i = imaging.FlipH(img) i = imaging.FlipH(i)
case "vertical": case "vertical":
i = imaging.FlipV(img) i = imaging.FlipV(i)
} }
} }
if opts.ToPNG { return i
// convert image to PNG
f, err := os.Create(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error())
}
defer f.Close()
png.Encode(f, i)
} else if opts.ToBMP {
// convert image to 4-Bit BMP (16 colors)
imagick.Initialize()
mw := imagick.NewMagickWand()
defer mw.Destroy()
b := new(bytes.Buffer)
jpeg.Encode(b, i, &jpeg.Options{jpeg.DefaultQuality})
err := mw.ReadImageBlob(b.Bytes())
if err != nil {
fmt.Fprintf(os.Stderr, "Error ReadImageBlob: %v\n", err.Error())
}
w := imagick.NewPixelWand()
w.SetColor("black")
defer w.Destroy()
var cs imagick.ColorspaceType = imagick.COLORSPACE_SRGB
if opts.Grayscale {
cs = imagick.COLORSPACE_GRAY
}
mw.SetImageFormat("BMP3")
mw.SetImageBackgroundColor(w)
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_REMOVE)
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE)
mw.SetImageMatte(false)
mw.SetImageCompression(imagick.COMPRESSION_NO)
mw.QuantizeImage(16, cs, 8, true, true)
mw.WriteImage(filename)
} else if opts.ToGIF {
// convert image to GIF
imagick.Initialize()
mw := imagick.NewMagickWand()
defer mw.Destroy()
b := new(bytes.Buffer)
jpeg.Encode(b, i, &jpeg.Options{jpeg.DefaultQuality})
err := mw.ReadImageBlob(b.Bytes())
if err != nil {
fmt.Fprintf(os.Stderr, "Error ReadImageBlob: %v\n", err.Error())
}
var cs imagick.ColorspaceType = imagick.COLORSPACE_SRGB
if opts.Grayscale {
cs = imagick.COLORSPACE_GRAY
}
mw.SetImageFormat("GIF")
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_REMOVE)
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE)
mw.SetImageMatte(false)
mw.SetImageCompression(imagick.COMPRESSION_LZW)
mw.QuantizeImage(256, cs, 8, true, true)
mw.WriteImage(filename)
} else {
// convert image to JPEG (default)
f, err := os.Create(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error())
}
defer f.Close()
jpeg.Encode(f, i, &jpeg.Options{opts.Quality})
}
<-throttle
} }
// Converts PDF/EPUB/XPS document to CBZ // Converts PDF/EPUB/XPS document to CBZ
@@ -269,7 +213,11 @@ func convertDocument(file string) {
img, err := doc.Image(n) img, err := doc.Image(n)
if err == nil && img != nil { if err == nil {
img = transformImage(img)
}
if img != nil {
throttle <- 1 throttle <- 1
wg.Add(1) wg.Add(1)
@@ -338,15 +286,17 @@ func convertArchive(file string) {
continue continue
} }
if !opts.RGB && !isGrayScale(img) { i := transformImage(img)
copyFile(bytes.NewReader(buf), filepath.Join(workdir, filepath.Base(pathname)))
if !opts.RGB && !isGrayScale(i) {
encodeImage(i, filepath.Join(workdir, filepath.Base(pathname)))
continue continue
} }
if img != nil { if i != nil {
throttle <- 1 throttle <- 1
wg.Add(1) wg.Add(1)
go convertImage(img, 0, pathname) go convertImage(i, 0, pathname)
} }
} else { } else {
if opts.NonImage { if opts.NonImage {
@@ -388,8 +338,10 @@ func convertDirectory(path string) {
continue continue
} }
i = transformImage(i)
if !opts.RGB && !isGrayScale(i) { if !opts.RGB && !isGrayScale(i) {
copyFile(f, filepath.Join(workdir, filepath.Base(img))) encodeImage(i, filepath.Join(workdir, filepath.Base(img)))
continue continue
} }
@@ -448,6 +400,95 @@ func saveArchive(file string) {
z.Close() z.Close()
} }
// Decodes image from reader
func decodeImage(reader io.Reader, filename string) (i image.Image, err error) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "Recovered in decodeImage %s: %v\n", filename, r)
}
}()
i, _, err = image.Decode(reader)
return i, err
}
// Encode image to file
func encodeImage(i image.Image, filename string) (err error) {
f, err := os.Create(filename)
if err != nil {
return
}
switch filepath.Ext(filename) {
case ".png":
err = png.Encode(f, i)
case ".tif":
case ".tiff":
err = tiff.Encode(f, i, nil)
case ".gif":
err = gif.Encode(f, i, nil)
default:
err = jpeg.Encode(f, i, &jpeg.Options{opts.Quality})
}
f.Close()
return
}
// Encode image to file (ImageMagick)
func encodeImageMagick(i image.Image, filename string) (err error) {
imagick.Initialize()
mw := imagick.NewMagickWand()
defer mw.Destroy()
b := new(bytes.Buffer)
jpeg.Encode(b, i, &jpeg.Options{opts.Quality})
err = mw.ReadImageBlob(b.Bytes())
if err != nil {
fmt.Fprintf(os.Stderr, "Error ReadImageBlob: %v\n", err.Error())
return
}
if opts.Grayscale {
c := mw.GetImageColors()
mw.QuantizeImage(c, imagick.COLORSPACE_GRAY, 8, true, true)
}
switch filepath.Ext(filename) {
case ".png":
mw.SetImageFormat("PNG")
mw.WriteImage(filename)
case ".gif":
mw.SetImageFormat("GIF")
mw.WriteImage(filename)
case ".bmp":
w := imagick.NewPixelWand()
w.SetColor("black")
defer w.Destroy()
cs := mw.GetImageColorspace()
if opts.Grayscale {
cs = imagick.COLORSPACE_GRAY
}
mw.SetImageFormat("BMP3")
mw.SetImageBackgroundColor(w)
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_REMOVE)
mw.SetImageAlphaChannel(imagick.ALPHA_CHANNEL_DEACTIVATE)
mw.SetImageMatte(false)
mw.SetImageCompression(imagick.COMPRESSION_NO)
mw.QuantizeImage(16, cs, 8, true, true)
mw.WriteImage(filename)
default:
mw.SetImageFormat("JPEG")
mw.WriteImage(filename)
}
return
}
// Lists contents of archive // Lists contents of archive
func listArchive(file string) []string { func listArchive(file string) []string {
var contents []string var contents []string
@@ -718,18 +759,6 @@ func isGrayScale(img image.Image) bool {
return false return false
} }
// Decodes image from reader
func decodeImage(reader io.Reader, filename string) (i image.Image, err error) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "Recovered in decodeImage %s: %v\n", filename, r)
}
}()
i, _, err = image.Decode(reader)
return i, err
}
// Copies reader to file // Copies reader to file
func copyFile(reader io.Reader, filename string) error { func copyFile(reader io.Reader, filename string) error {
os.MkdirAll(filepath.Dir(filename), 0755) os.MkdirAll(filepath.Dir(filename), 0755)
@@ -872,7 +901,7 @@ func parseFlags() {
convert.Flag("png", "Encode images to PNG instead of JPEG").BoolVar(&opts.ToPNG) convert.Flag("png", "Encode images to PNG instead of JPEG").BoolVar(&opts.ToPNG)
convert.Flag("bmp", "Encode images to 4-Bit BMP (16 colors) instead of JPEG").BoolVar(&opts.ToBMP) convert.Flag("bmp", "Encode images to 4-Bit BMP (16 colors) instead of JPEG").BoolVar(&opts.ToBMP)
convert.Flag("gif", "Encode images to GIF instead of JPEG").BoolVar(&opts.ToGIF) convert.Flag("gif", "Encode images to GIF instead of JPEG").BoolVar(&opts.ToGIF)
convert.Flag("rgb", "Convert images that have RGB colorspace (use --no-rgb if you only want to process grayscale images)").Default("true").BoolVar(&opts.RGB) convert.Flag("rgb", "Convert images that have RGB colorspace (use --no-rgb if you only want to convert grayscale images)").Default("true").BoolVar(&opts.RGB)
convert.Flag("nonimage", "Leave non image files in archive (use --no-nonimage to remove non image files from archive)").Default("true").BoolVar(&opts.NonImage) convert.Flag("nonimage", "Leave non image files in archive (use --no-nonimage to remove non image files from archive)").Default("true").BoolVar(&opts.NonImage)
convert.Flag("grayscale", "Convert images to grayscale (monochromatic)").BoolVar(&opts.Grayscale) convert.Flag("grayscale", "Convert images to grayscale (monochromatic)").BoolVar(&opts.Grayscale)
convert.Flag("rotate", "Rotate images, valid values are 0, 90, 180, 270").Default(strconv.Itoa(0)).IntVar(&opts.Rotate) convert.Flag("rotate", "Rotate images, valid values are 0, 90, 180, 270").Default(strconv.Itoa(0)).IntVar(&opts.Rotate)