From d83be6df2d8b0e2fef4cb6866cfdb6434bbef5c4 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 17 Sep 2015 11:08:47 -0400 Subject: PLT-173 Added graphics-go and goexif libraries for image manipulation --- .../p/graphics-go/graphics/interp/Makefile | 13 ++ .../p/graphics-go/graphics/interp/bilinear.go | 206 +++++++++++++++++++++ .../p/graphics-go/graphics/interp/bilinear_test.go | 143 ++++++++++++++ .../p/graphics-go/graphics/interp/doc.go | 25 +++ .../p/graphics-go/graphics/interp/interp.go | 29 +++ 5 files changed, 416 insertions(+) create mode 100644 Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/Makefile create mode 100644 Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear.go create mode 100644 Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear_test.go create mode 100644 Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/doc.go create mode 100644 Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/interp.go (limited to 'Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp') diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/Makefile b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/Makefile new file mode 100644 index 000000000..4d8f524fb --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/Makefile @@ -0,0 +1,13 @@ +# Copyright 2012 The Graphics-Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include $(GOROOT)/src/Make.inc + +TARG=code.google.com/p/graphics-go/graphics/interp +GOFILES=\ + bilinear.go\ + doc.go\ + interp.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear.go b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear.go new file mode 100644 index 000000000..e18321a15 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear.go @@ -0,0 +1,206 @@ +// Copyright 2012 The Graphics-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package interp + +import ( + "image" + "image/color" + "math" +) + +// Bilinear implements bilinear interpolation. +var Bilinear Interp = bilinear{} + +type bilinear struct{} + +func (i bilinear) Interp(src image.Image, x, y float64) color.Color { + if src, ok := src.(*image.RGBA); ok { + return i.RGBA(src, x, y) + } + return bilinearGeneral(src, x, y) +} + +func bilinearGeneral(src image.Image, x, y float64) color.Color { + p := findLinearSrc(src.Bounds(), x, y) + var fr, fg, fb, fa float64 + var r, g, b, a uint32 + + r, g, b, a = src.At(p.low.X, p.low.Y).RGBA() + fr += float64(r) * p.frac00 + fg += float64(g) * p.frac00 + fb += float64(b) * p.frac00 + fa += float64(a) * p.frac00 + + r, g, b, a = src.At(p.high.X, p.low.Y).RGBA() + fr += float64(r) * p.frac01 + fg += float64(g) * p.frac01 + fb += float64(b) * p.frac01 + fa += float64(a) * p.frac01 + + r, g, b, a = src.At(p.low.X, p.high.Y).RGBA() + fr += float64(r) * p.frac10 + fg += float64(g) * p.frac10 + fb += float64(b) * p.frac10 + fa += float64(a) * p.frac10 + + r, g, b, a = src.At(p.high.X, p.high.Y).RGBA() + fr += float64(r) * p.frac11 + fg += float64(g) * p.frac11 + fb += float64(b) * p.frac11 + fa += float64(a) * p.frac11 + + var c color.RGBA64 + c.R = uint16(fr + 0.5) + c.G = uint16(fg + 0.5) + c.B = uint16(fb + 0.5) + c.A = uint16(fa + 0.5) + return c +} + +func (bilinear) RGBA(src *image.RGBA, x, y float64) color.RGBA { + p := findLinearSrc(src.Bounds(), x, y) + + // Array offsets for the surrounding pixels. + off00 := offRGBA(src, p.low.X, p.low.Y) + off01 := offRGBA(src, p.high.X, p.low.Y) + off10 := offRGBA(src, p.low.X, p.high.Y) + off11 := offRGBA(src, p.high.X, p.high.Y) + + var fr, fg, fb, fa float64 + + fr += float64(src.Pix[off00+0]) * p.frac00 + fg += float64(src.Pix[off00+1]) * p.frac00 + fb += float64(src.Pix[off00+2]) * p.frac00 + fa += float64(src.Pix[off00+3]) * p.frac00 + + fr += float64(src.Pix[off01+0]) * p.frac01 + fg += float64(src.Pix[off01+1]) * p.frac01 + fb += float64(src.Pix[off01+2]) * p.frac01 + fa += float64(src.Pix[off01+3]) * p.frac01 + + fr += float64(src.Pix[off10+0]) * p.frac10 + fg += float64(src.Pix[off10+1]) * p.frac10 + fb += float64(src.Pix[off10+2]) * p.frac10 + fa += float64(src.Pix[off10+3]) * p.frac10 + + fr += float64(src.Pix[off11+0]) * p.frac11 + fg += float64(src.Pix[off11+1]) * p.frac11 + fb += float64(src.Pix[off11+2]) * p.frac11 + fa += float64(src.Pix[off11+3]) * p.frac11 + + var c color.RGBA + c.R = uint8(fr + 0.5) + c.G = uint8(fg + 0.5) + c.B = uint8(fb + 0.5) + c.A = uint8(fa + 0.5) + return c +} + +func (bilinear) Gray(src *image.Gray, x, y float64) color.Gray { + p := findLinearSrc(src.Bounds(), x, y) + + // Array offsets for the surrounding pixels. + off00 := offGray(src, p.low.X, p.low.Y) + off01 := offGray(src, p.high.X, p.low.Y) + off10 := offGray(src, p.low.X, p.high.Y) + off11 := offGray(src, p.high.X, p.high.Y) + + var fc float64 + fc += float64(src.Pix[off00]) * p.frac00 + fc += float64(src.Pix[off01]) * p.frac01 + fc += float64(src.Pix[off10]) * p.frac10 + fc += float64(src.Pix[off11]) * p.frac11 + + var c color.Gray + c.Y = uint8(fc + 0.5) + return c +} + +type bilinearSrc struct { + // Top-left and bottom-right interpolation sources + low, high image.Point + // Fraction of each pixel to take. The 0 suffix indicates + // top/left, and the 1 suffix indicates bottom/right. + frac00, frac01, frac10, frac11 float64 +} + +func findLinearSrc(b image.Rectangle, sx, sy float64) bilinearSrc { + maxX := float64(b.Max.X) + maxY := float64(b.Max.Y) + minX := float64(b.Min.X) + minY := float64(b.Min.Y) + lowX := math.Floor(sx - 0.5) + lowY := math.Floor(sy - 0.5) + if lowX < minX { + lowX = minX + } + if lowY < minY { + lowY = minY + } + + highX := math.Ceil(sx - 0.5) + highY := math.Ceil(sy - 0.5) + if highX >= maxX { + highX = maxX - 1 + } + if highY >= maxY { + highY = maxY - 1 + } + + // In the variables below, the 0 suffix indicates top/left, and the + // 1 suffix indicates bottom/right. + + // Center of each surrounding pixel. + x00 := lowX + 0.5 + y00 := lowY + 0.5 + x01 := highX + 0.5 + y01 := lowY + 0.5 + x10 := lowX + 0.5 + y10 := highY + 0.5 + x11 := highX + 0.5 + y11 := highY + 0.5 + + p := bilinearSrc{ + low: image.Pt(int(lowX), int(lowY)), + high: image.Pt(int(highX), int(highY)), + } + + // Literally, edge cases. If we are close enough to the edge of + // the image, curtail the interpolation sources. + if lowX == highX && lowY == highY { + p.frac00 = 1.0 + } else if sy-minY <= 0.5 && sx-minX <= 0.5 { + p.frac00 = 1.0 + } else if maxY-sy <= 0.5 && maxX-sx <= 0.5 { + p.frac11 = 1.0 + } else if sy-minY <= 0.5 || lowY == highY { + p.frac00 = x01 - sx + p.frac01 = sx - x00 + } else if sx-minX <= 0.5 || lowX == highX { + p.frac00 = y10 - sy + p.frac10 = sy - y00 + } else if maxY-sy <= 0.5 { + p.frac10 = x11 - sx + p.frac11 = sx - x10 + } else if maxX-sx <= 0.5 { + p.frac01 = y11 - sy + p.frac11 = sy - y01 + } else { + p.frac00 = (x01 - sx) * (y10 - sy) + p.frac01 = (sx - x00) * (y11 - sy) + p.frac10 = (x11 - sx) * (sy - y00) + p.frac11 = (sx - x10) * (sy - y01) + } + + return p +} + +// TODO(crawshaw): When we have inlining, consider func (p *RGBA) Off(x, y) int +func offRGBA(src *image.RGBA, x, y int) int { + return (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4 +} +func offGray(src *image.Gray, x, y int) int { + return (y-src.Rect.Min.Y)*src.Stride + (x - src.Rect.Min.X) +} diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear_test.go b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear_test.go new file mode 100644 index 000000000..242d70546 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear_test.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Graphics-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package interp + +import ( + "image" + "image/color" + "testing" +) + +type interpTest struct { + desc string + src []uint8 + srcWidth int + x, y float64 + expect uint8 +} + +func (p *interpTest) newSrc() *image.RGBA { + b := image.Rect(0, 0, p.srcWidth, len(p.src)/p.srcWidth) + src := image.NewRGBA(b) + i := 0 + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + src.SetRGBA(x, y, color.RGBA{ + R: p.src[i], + G: p.src[i], + B: p.src[i], + A: 0xff, + }) + i++ + } + } + return src +} + +var interpTests = []interpTest{ + { + desc: "center of a single white pixel should match that pixel", + src: []uint8{0x00}, + srcWidth: 1, + x: 0.5, + y: 0.5, + expect: 0x00, + }, + { + desc: "middle of a square is equally weighted", + src: []uint8{ + 0x00, 0xff, + 0xff, 0x00, + }, + srcWidth: 2, + x: 1.0, + y: 1.0, + expect: 0x80, + }, + { + desc: "center of a pixel is just that pixel", + src: []uint8{ + 0x00, 0xff, + 0xff, 0x00, + }, + srcWidth: 2, + x: 1.5, + y: 0.5, + expect: 0xff, + }, + { + desc: "asymmetry abounds", + src: []uint8{ + 0xaa, 0x11, 0x55, + 0xff, 0x95, 0xdd, + }, + srcWidth: 3, + x: 2.0, + y: 1.0, + expect: 0x76, // (0x11 + 0x55 + 0x95 + 0xdd) / 4 + }, +} + +func TestBilinearRGBA(t *testing.T) { + for _, p := range interpTests { + src := p.newSrc() + + // Fast path. + c := Bilinear.(RGBA).RGBA(src, p.x, p.y) + if c.R != c.G || c.R != c.B || c.A != 0xff { + t.Errorf("expect channels to match, got %v", c) + continue + } + if c.R != p.expect { + t.Errorf("%s: got 0x%02x want 0x%02x", p.desc, c.R, p.expect) + continue + } + + // Standard Interp should use the fast path. + cStd := Bilinear.Interp(src, p.x, p.y) + if cStd != c { + t.Errorf("%s: standard mismatch got %v want %v", p.desc, cStd, c) + continue + } + + // General case should match the fast path. + cGen := color.RGBAModel.Convert(bilinearGeneral(src, p.x, p.y)) + r0, g0, b0, a0 := c.RGBA() + r1, g1, b1, a1 := cGen.RGBA() + if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { + t.Errorf("%s: general case mismatch got %v want %v", p.desc, c, cGen) + continue + } + } +} + +func TestBilinearSubImage(t *testing.T) { + b0 := image.Rect(0, 0, 4, 4) + src0 := image.NewRGBA(b0) + b1 := image.Rect(1, 1, 3, 3) + src1 := src0.SubImage(b1).(*image.RGBA) + src1.Set(1, 1, color.RGBA{0x11, 0, 0, 0xff}) + src1.Set(2, 1, color.RGBA{0x22, 0, 0, 0xff}) + src1.Set(1, 2, color.RGBA{0x33, 0, 0, 0xff}) + src1.Set(2, 2, color.RGBA{0x44, 0, 0, 0xff}) + + tests := []struct { + x, y float64 + want uint8 + }{ + {1, 1, 0x11}, + {3, 1, 0x22}, + {1, 3, 0x33}, + {3, 3, 0x44}, + {2, 2, 0x2b}, + } + + for _, p := range tests { + c := Bilinear.(RGBA).RGBA(src1, p.x, p.y) + if c.R != p.want { + t.Errorf("(%.0f, %.0f): got 0x%02x want 0x%02x", p.x, p.y, c.R, p.want) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/doc.go b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/doc.go new file mode 100644 index 000000000..b115534cc --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/doc.go @@ -0,0 +1,25 @@ +// Copyright 2012 The Graphics-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package interp implements image interpolation. + +An interpolator provides the Interp interface, which can be used +to interpolate a pixel: + + c := interp.Bilinear.Interp(src, 1.2, 1.8) + +To interpolate a large number of RGBA or Gray pixels, an implementation +may provide a fast-path by implementing the RGBA or Gray interfaces. + + i1, ok := i.(interp.RGBA) + if ok { + c := i1.RGBA(src, 1.2, 1.8) + // use c.R, c.G, etc + return + } + c := i.Interp(src, 1.2, 1.8) + // use generic color.Color +*/ +package interp diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/interp.go b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/interp.go new file mode 100644 index 000000000..560637d4a --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/interp.go @@ -0,0 +1,29 @@ +// Copyright 2012 The Graphics-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package interp + +import ( + "image" + "image/color" +) + +// Interp interpolates an image's color at fractional co-ordinates. +type Interp interface { + // Interp interpolates (x, y). + Interp(src image.Image, x, y float64) color.Color +} + +// RGBA is a fast-path interpolation implementation for image.RGBA. +// It is common for an Interp to also implement RGBA. +type RGBA interface { + // RGBA interpolates (x, y). + RGBA(src *image.RGBA, x, y float64) color.RGBA +} + +// Gray is a fast-path interpolation implementation for image.Gray. +type Gray interface { + // Gray interpolates (x, y). + Gray(src *image.Gray, x, y float64) color.Gray +} -- cgit v1.2.3-1-g7c22