ソースを参照

add gif encode options

Grigory Dryapak 7 年 前
コミット
b039796423
2 ファイル変更84 行追加20 行削除
  1. 38 3
      helpers.go
  2. 46 17
      helpers_test.go

+ 38 - 3
helpers.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"image"
 	"image/color"
+	"image/draw"
 	"image/gif"
 	"image/jpeg"
 	"image/png"
@@ -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.
@@ -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
@@ -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:

+ 46 - 17
helpers_test.go

@@ -5,6 +5,8 @@ import (
 	"errors"
 	"image"
 	"image/color"
+	"image/color/palette"
+	"image/draw"
 	"io"
 	"io/ioutil"
 	"os"
@@ -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{
@@ -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")
@@ -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)
+			}
 		}
 	}