From 4ba34829e7bbf19fe396abcb392df5bbbe81cb46 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Thu, 12 May 2016 10:52:30 +0900 Subject: [PATCH 1/4] Add RGB encoder --- webp/encode.go | 2 ++ webp/rgb_image.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++ webp/webp_test.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 webp/rgb_image.go diff --git a/webp/encode.go b/webp/encode.go index 210398f..561b56f 100644 --- a/webp/encode.go +++ b/webp/encode.go @@ -118,6 +118,8 @@ func EncodeRGBA(w io.Writer, img image.Image, c Config) (err error) { pic.writer = C.WebPWriterFunction(C.writeWebP) switch p := img.(type) { + case *RGBImage: + C.WebPPictureImportRGB(pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) case *image.RGBA: C.WebPPictureImportRGBA(pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) case *image.NRGBA: diff --git a/webp/rgb_image.go b/webp/rgb_image.go new file mode 100644 index 0000000..5632f70 --- /dev/null +++ b/webp/rgb_image.go @@ -0,0 +1,80 @@ +// Package rgb provides RGB image which implements image.Image interface. +package webp + +import ( + "image" + "image/color" +) + +// Image represent image data which has RGB colors. +// Image is compatible with image.RGBA, but does not have alpha channel to reduce using memory. +type RGBImage struct { + // Pix holds the image's stream, in R, G, B order. + Pix []uint8 + // Stride is the Pix stride (in bytes) between vertically adjacent pixels. + Stride int + // Rect is the image's bounds. + Rect image.Rectangle +} + +// NewRGBImage allocates and returns RGB image +func NewRGBImage(r image.Rectangle) *RGBImage { + w, h := r.Dx(), r.Dy() + return &RGBImage{Pix: make([]uint8, 3*w*h), Stride: 3 * w, Rect: r} +} + +// ColorModel returns RGB color model. +func (p *RGBImage) ColorModel() color.Model { + return ColorModel +} + +// Bounds implements image.Image.At +func (p *RGBImage) Bounds() image.Rectangle { + return p.Rect +} + +// At implements image.Image.At +func (p *RGBImage) At(x, y int) color.Color { + return p.RGBAAt(x, y) +} + +// RGBAAt returns the color of the pixel at (x, y) as RGBA. +func (p *RGBImage) RGBAAt(x, y int) color.RGBA { + if !(image.Point{x, y}.In(p.Rect)) { + return color.RGBA{} + } + i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*3 + return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], 0xFF} +} + +// ColorModel is RGB color model instance +var ColorModel = color.ModelFunc(rgbModel) + +func rgbModel(c color.Color) color.Color { + if _, ok := c.(RGB); ok { + return c + } + r, g, b, _ := c.RGBA() + return RGB{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)} +} + +// RGB color +type RGB struct { + R, G, B uint8 +} + +// RGBA implements Color.RGBA +func (c RGB) RGBA() (r, g, b, a uint32) { + r = uint32(c.R) + r |= r << 8 + g = uint32(c.G) + g |= g << 8 + b = uint32(c.B) + b |= b << 8 + a = uint32(0xFFFF) + return +} + +// Make sure Image implements image.Image. +// See https://golang.org/doc/effective_go.html#blank_implements. +var _ image.Image = new(RGBImage) diff --git a/webp/webp_test.go b/webp/webp_test.go index 60370ae..679e825 100644 --- a/webp/webp_test.go +++ b/webp/webp_test.go @@ -9,6 +9,7 @@ import ( "github.com/harukasan/go-libwebp/test/util" "github.com/harukasan/go-libwebp/webp" + "image/color" ) func TestMain(m *testing.M) { @@ -170,6 +171,28 @@ func TestEncodeRGBA(t *testing.T) { } } +func TestEncodeRGB(t *testing.T) { + img := util.ReadPNG("yellow-rose-3.png") + + config := webp.Config{ + Preset: webp.PresetDefault, + Quality: 100, + Method: 6, + } + + f := util.CreateFile("TestEncodeRGB.webp") + w := bufio.NewWriter(f) + defer func() { + w.Flush() + f.Close() + }() + + if err := webp.EncodeRGBA(w, img, config); err != nil { + t.Errorf("Got Error: %v", err) + return + } +} + func TestEncodeYUVA(t *testing.T) { data := util.ReadFile("cosmos.webp") options := &webp.DecoderOptions{} @@ -198,3 +221,60 @@ func TestEncodeYUVA(t *testing.T) { return } } + +func TestImageInterface(t *testing.T) { + rect := image.Rect(0, 0, 100, 100) + img := webp.NewRGBImage(rect) + + if got := img.ColorModel(); got != webp.ColorModel { + t.Errorf("ColorModel() should return rgb.ColorModel, got: %v", got) + } + + if got := img.Bounds(); got != rect { + t.Errorf("Bounds() should return %v, got: %v", rect, got) + } + + black := color.RGBA{0x00, 0x00, 0x00, 0xFF} + if got := img.At(0, 0); got != black { + t.Errorf("At(0, 0) should return %v, got: %v", black, got) + } + + blank := color.RGBA{} + if got := img.At(-1, -1); got != blank { + t.Errorf("At(0, 0) should return %v, got: %v", blank, got) + } +} + +func TestConvertFromRGBA(t *testing.T) { + rgba := color.RGBA{0x11, 0x22, 0x33, 0xFF} + expect := webp.RGB{0x11, 0x22, 0x33} + if got := webp.ColorModel.Convert(rgba); got != expect { + t.Errorf("got: %v, expect: %v", got, expect) + } +} + +func TestConvertFromRGB(t *testing.T) { + c := webp.RGB{0x11, 0x22, 0x33} + if got := webp.ColorModel.Convert(c); got != c { + t.Errorf("got: %v, expect: %v", got, c) + } +} + +func TestColorRGBA(t *testing.T) { + c := webp.RGB{0x11, 0x22, 0x33} + r, g, b, a := uint32(0x1111), uint32(0x2222), uint32(0x3333), uint32(0xFFFF) + + gotR, gotG, gotB, gotA := c.RGBA() + if gotR != r { + t.Errorf("got R: %v, expect R: %v", gotR, r) + } + if gotG != g { + t.Errorf("got G: %v, expect G: %v", gotG, g) + } + if gotB != b { + t.Errorf("got B: %v, expect B: %v", gotB, b) + } + if gotA != a { + t.Errorf("got A: %v, expect A: %v", gotA, a) + } +} From 462078c647f86dc3a1bf5f440edd796beb4fb5d5 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Thu, 16 Jun 2016 16:13:50 +0900 Subject: [PATCH 2/4] Rename ambiguous ColorModel to RGBModel --- webp/rgb_image.go | 4 ++-- webp/webp_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webp/rgb_image.go b/webp/rgb_image.go index 5632f70..430ad72 100644 --- a/webp/rgb_image.go +++ b/webp/rgb_image.go @@ -25,7 +25,7 @@ func NewRGBImage(r image.Rectangle) *RGBImage { // ColorModel returns RGB color model. func (p *RGBImage) ColorModel() color.Model { - return ColorModel + return RGBModel } // Bounds implements image.Image.At @@ -48,7 +48,7 @@ func (p *RGBImage) RGBAAt(x, y int) color.RGBA { } // ColorModel is RGB color model instance -var ColorModel = color.ModelFunc(rgbModel) +var RGBModel = color.ModelFunc(rgbModel) func rgbModel(c color.Color) color.Color { if _, ok := c.(RGB); ok { diff --git a/webp/webp_test.go b/webp/webp_test.go index 679e825..103c0ce 100644 --- a/webp/webp_test.go +++ b/webp/webp_test.go @@ -226,7 +226,7 @@ func TestImageInterface(t *testing.T) { rect := image.Rect(0, 0, 100, 100) img := webp.NewRGBImage(rect) - if got := img.ColorModel(); got != webp.ColorModel { + if got := img.ColorModel(); got != webp.RGBModel { t.Errorf("ColorModel() should return rgb.ColorModel, got: %v", got) } @@ -248,14 +248,14 @@ func TestImageInterface(t *testing.T) { func TestConvertFromRGBA(t *testing.T) { rgba := color.RGBA{0x11, 0x22, 0x33, 0xFF} expect := webp.RGB{0x11, 0x22, 0x33} - if got := webp.ColorModel.Convert(rgba); got != expect { + if got := webp.RGBModel.Convert(rgba); got != expect { t.Errorf("got: %v, expect: %v", got, expect) } } func TestConvertFromRGB(t *testing.T) { c := webp.RGB{0x11, 0x22, 0x33} - if got := webp.ColorModel.Convert(c); got != c { + if got := webp.RGBModel.Convert(c); got != c { t.Errorf("got: %v, expect: %v", got, c) } } From 7c460481c0db584403ce3c310760e13019507ff8 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Fri, 17 Jun 2016 02:29:22 +0900 Subject: [PATCH 3/4] Fix comments --- webp/rgb_image.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webp/rgb_image.go b/webp/rgb_image.go index 430ad72..837144c 100644 --- a/webp/rgb_image.go +++ b/webp/rgb_image.go @@ -6,8 +6,8 @@ import ( "image/color" ) -// Image represent image data which has RGB colors. -// Image is compatible with image.RGBA, but does not have alpha channel to reduce using memory. +// RGBImage represent image data which has RGB colors. +// RGBImage is compatible with image.RGBA, but does not have alpha channel to reduce using memory. type RGBImage struct { // Pix holds the image's stream, in R, G, B order. Pix []uint8 @@ -47,7 +47,7 @@ func (p *RGBImage) RGBAAt(x, y int) color.RGBA { return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], 0xFF} } -// ColorModel is RGB color model instance +// RGBModel is RGB color model instance var RGBModel = color.ModelFunc(rgbModel) func rgbModel(c color.Color) color.Color { @@ -75,6 +75,6 @@ func (c RGB) RGBA() (r, g, b, a uint32) { return } -// Make sure Image implements image.Image. +// Make sure RGBImage implements image.Image. // See https://golang.org/doc/effective_go.html#blank_implements. var _ image.Image = new(RGBImage) From 5feb01ea46f22b59bf396c2448d44bdf4f54cb86 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Tue, 21 Jun 2016 11:46:19 +0900 Subject: [PATCH 4/4] Remove inappropriate comment --- webp/rgb_image.go | 1 - 1 file changed, 1 deletion(-) diff --git a/webp/rgb_image.go b/webp/rgb_image.go index 837144c..e9e7a03 100644 --- a/webp/rgb_image.go +++ b/webp/rgb_image.go @@ -1,4 +1,3 @@ -// Package rgb provides RGB image which implements image.Image interface. package webp import (