Skip to content

Commit

Permalink
add gif encode options
Browse files Browse the repository at this point in the history
  • Loading branch information
disintegration committed Mar 8, 2018
1 parent ce99392 commit b039796
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 20 deletions.
41 changes: 38 additions & 3 deletions helpers.go
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"image"
"image/color"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
Expand Down Expand Up @@ -79,11 +80,17 @@ func Open(filename string) (image.Image, error) {
}

type encodeConfig struct {
jpegQuality int
jpegQuality int
gifNumColors int
gifQuantizer draw.Quantizer
gifDrawer draw.Drawer
}

var defaultEncodeConfig = encodeConfig{
jpegQuality: 95,
jpegQuality: 95,
gifNumColors: 256,
gifQuantizer: nil,
gifDrawer: nil,
}

// EncodeOption sets an optional parameter for the Encode and Save functions.
Expand All @@ -97,6 +104,30 @@ func JPEGQuality(quality int) EncodeOption {
}
}

// GIFNumColors returns an EncodeOption that sets the maximum number of colors
// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
func GIFNumColors(numColors int) EncodeOption {
return func(c *encodeConfig) {
c.gifNumColors = numColors
}
}

// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
// a palette of the GIF-encoded image.
func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
return func(c *encodeConfig) {
c.gifQuantizer = quantizer
}
}

// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
// the source image to the desired palette of the GIF-encoded image.
func GIFDrawer(drawer draw.Drawer) EncodeOption {
return func(c *encodeConfig) {
c.gifDrawer = drawer
}
}

// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
cfg := defaultEncodeConfig
Expand Down Expand Up @@ -126,7 +157,11 @@ func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) e
case PNG:
err = png.Encode(w, img)
case GIF:
err = gif.Encode(w, img, &gif.Options{NumColors: 256})
err = gif.Encode(w, img, &gif.Options{
NumColors: cfg.gifNumColors,
Quantizer: cfg.gifQuantizer,
Drawer: cfg.gifDrawer,
})
case TIFF:
err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
case BMP:
Expand Down
63 changes: 46 additions & 17 deletions helpers_test.go
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"image"
"image/color"
"image/color/palette"
"image/draw"
"io"
"io/ioutil"
"os"
Expand Down Expand Up @@ -39,6 +41,23 @@ func (badFile) Close() error {
return errClose
}

type quantizer struct {
palette []color.Color
}

func (q quantizer) Quantize(p color.Palette, m image.Image) color.Palette {
pal := make([]color.Color, len(p), cap(p))
copy(pal, p)
n := cap(p) - len(p)
if n > len(q.palette) {
n = len(q.palette)
}
for i := 0; i < n; i++ {
pal = append(pal, q.palette[i])
}
return pal
}

func TestOpenSave(t *testing.T) {
imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 4, 6))
imgWithoutAlpha.Pix = []uint8{
Expand All @@ -59,8 +78,16 @@ func TestOpenSave(t *testing.T) {
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, 0x00,
}

options := []EncodeOption{
JPEGQuality(100),
options := [][]EncodeOption{
{
JPEGQuality(100),
},
{
JPEGQuality(99),
GIFDrawer(draw.FloydSteinberg),
GIFNumColors(256),
GIFQuantizer(quantizer{palette.Plan9}),
},
}

dir, err := ioutil.TempDir("", "imaging")
Expand All @@ -77,24 +104,26 @@ func TestOpenSave(t *testing.T) {
img = imgWithAlpha
}

err := Save(img, filename, options...)
if err != nil {
t.Fatalf("failed to save image (%q): %v", filename, err)
}
for _, opts := range options {
err := Save(img, filename, opts...)
if err != nil {
t.Fatalf("failed to save image (%q): %v", filename, err)
}

img2, err := Open(filename)
if err != nil {
t.Fatalf("failed to open image (%q): %v", filename, err)
}
got := Clone(img2)
img2, err := Open(filename)
if err != nil {
t.Fatalf("failed to open image (%q): %v", filename, err)
}
got := Clone(img2)

delta := 0
if ext == "jpg" || ext == "jpeg" || ext == "gif" {
delta = 3
}
delta := 0
if ext == "jpg" || ext == "jpeg" || ext == "gif" {
delta = 3
}

if !compareNRGBA(got, img, delta) {
t.Fatalf("bad encode-decode result (ext=%q): got %#v want %#v", ext, got, img)
if !compareNRGBA(got, img, delta) {
t.Fatalf("bad encode-decode result (ext=%q): got %#v want %#v", ext, got, img)
}
}
}

Expand Down

0 comments on commit b039796

Please sign in to comment.