This commit is contained in:
Laurent Le Goff 2011-04-14 22:22:57 +02:00
parent a8724418ad
commit 3065973abc
4 changed files with 147 additions and 158 deletions

View File

@ -21,7 +21,7 @@ var (
type ImageGraphicContext struct { type ImageGraphicContext struct {
*StackGraphicContext *StackGraphicContext
img draw.Image img draw.Image
painter Painter painter Painter
fillRasterizer *raster.Rasterizer fillRasterizer *raster.Rasterizer
strokeRasterizer *raster.Rasterizer strokeRasterizer *raster.Rasterizer

View File

@ -1,154 +1,144 @@
// see http://pippin.gimp.org/image_processing/chap_resampling.html // see http://pippin.gimp.org/image_processing/chap_resampling.html
package draw2d package draw2d
import ( import (
"exp/draw" "exp/draw"
"image" "image"
"math" "math"
) )
type ImageFilter int type ImageFilter int
const ( const (
LinearFilter ImageFilter = iota LinearFilter ImageFilter = iota
BilinearFilter BilinearFilter
BicubicFilter BicubicFilter
) )
//see http://pippin.gimp.org/image_processing/chap_resampling.html //see http://pippin.gimp.org/image_processing/chap_resampling.html
func getColorLinear(img image.Image, x, y float64) image.Color { func getColorLinear(img image.Image, x, y float64) image.Color {
return img.At(int(x), int(y)) return img.At(int(x), int(y))
} }
func getColorBilinear(img image.Image, x, y float64) image.Color { func getColorBilinear(img image.Image, x, y float64) image.Color {
x0 := math.Floor(x) x0 := math.Floor(x)
y0 := math.Floor(y) y0 := math.Floor(y)
dx := x - x0 dx := x - x0
dy := y - y0 dy := y - y0
c0 := img.At(int(x0), int(y0)) rt, gt, bt, at := img.At(int(x0), int(y0)).RGBA()
c1 := img.At(int(x0+1), int(y0)) r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
c2 := img.At(int(x0+1), int(y0+1)) rt, gt, bt, at = img.At(int(x0+1), int(y0)).RGBA()
c3 := img.At(int(x0), int(y0+1)) r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
rt, gt, bt, at := c0.RGBA() rt, gt, bt, at = img.At(int(x0+1), int(y0+1)).RGBA()
r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at) r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
rt, gt, bt, at = c1.RGBA() rt, gt, bt, at = img.At(int(x0), int(y0+1)).RGBA()
r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at) r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
rt, gt, bt, at = c2.RGBA()
r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at) r := int(lerp(lerp(r0, r1, dx), lerp(r3, r2, dx), dy))
rt, gt, bt, at = c3.RGBA() g := int(lerp(lerp(g0, g1, dx), lerp(g3, g2, dx), dy))
r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at) b := int(lerp(lerp(b0, b1, dx), lerp(b3, b2, dx), dy))
r := int(lerp(lerp(r0, r1, dx), lerp(r3, r2, dx), dy)) a := int(lerp(lerp(a0, a1, dx), lerp(a3, a2, dx), dy))
g := int(lerp(lerp(g0, g1, dx), lerp(g3, g2, dx), dy)) return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
b := int(lerp(lerp(b0, b1, dx), lerp(b3, b2, dx), dy)) }
a := int(lerp(lerp(a0, a1, dx), lerp(a3, a2, dx), dy)) /**
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} -- LERP
} -- /lerp/, vi.,n.
/** --
-- LERP -- Quasi-acronym for Linear Interpolation, used as a verb or noun for
-- /lerp/, vi.,n. -- the operation. "Bresenham's algorithm lerps incrementally between the
-- -- two endpoints of the line." (From Jargon File (4.4.4, 14 Aug 2003)
-- Quasi-acronym for Linear Interpolation, used as a verb or noun for */
-- the operation. "Bresenham's algorithm lerps incrementally between the func lerp(v1, v2, ratio float64) float64 {
-- two endpoints of the line." (From Jargon File (4.4.4, 14 Aug 2003) return v1*(1-ratio) + v2*ratio
*/ }
func lerp(v1, v2, ratio float64) float64 {
return v1*(1-ratio) + v2*ratio
} func getColorCubicRow(img image.Image, x, y, offset float64) image.Color {
c0 := img.At(int(x), int(y))
c1 := img.At(int(x+1), int(y))
func getColorCubicRow(img image.Image, x, y, offset float64) image.Color { c2 := img.At(int(x+2), int(y))
c0 := img.At(int(x), int(y)) c3 := img.At(int(x+3), int(y))
c1 := img.At(int(x+1), int(y)) rt, gt, bt, at := c0.RGBA()
c2 := img.At(int(x+2), int(y)) r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
c3 := img.At(int(x+3), int(y)) rt, gt, bt, at = c1.RGBA()
rt, gt, bt, at := c0.RGBA() r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at) rt, gt, bt, at = c2.RGBA()
rt, gt, bt, at = c1.RGBA() r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at) rt, gt, bt, at = c3.RGBA()
rt, gt, bt, at = c2.RGBA() r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at) r, g, b, a := cubic(offset, r0, r1, r2, r3), cubic(offset, g0, g1, g2, g3), cubic(offset, b0, b1, b2, b3), cubic(offset, a0, a1, a2, a3)
rt, gt, bt, at = c3.RGBA() return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at) }
r, g, b, a := cubic(offset, r0, r1, r2, r3), cubic(offset, g0, g1, g2, g3), cubic(offset, b0, b1, b2, b3), cubic(offset, a0, a1, a2, a3)
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} func getColorBicubic(img image.Image, x, y float64) image.Color {
} x0 := math.Floor(x)
y0 := math.Floor(y)
func getColorBicubic(img image.Image, x, y float64) image.Color { dx := x - x0
x0 := math.Floor(x) dy := y - y0
y0 := math.Floor(y) c0 := getColorCubicRow(img, x0-1, y0-1, dx)
dx := x - x0 c1 := getColorCubicRow(img, x0-1, y0, dx)
dy := y - y0 c2 := getColorCubicRow(img, x0-1, y0+1, dx)
c0 := getColorCubicRow(img, x0-1, y0-1, dx) c3 := getColorCubicRow(img, x0-1, y0+2, dx)
c1 := getColorCubicRow(img, x0-1, y0, dx) rt, gt, bt, at := c0.RGBA()
c2 := getColorCubicRow(img, x0-1, y0+1, dx) r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
c3 := getColorCubicRow(img, x0-1, y0+2, dx) rt, gt, bt, at = c1.RGBA()
rt, gt, bt, at := c0.RGBA() r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at) rt, gt, bt, at = c2.RGBA()
rt, gt, bt, at = c1.RGBA() r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at) rt, gt, bt, at = c3.RGBA()
rt, gt, bt, at = c2.RGBA() r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at) r, g, b, a := cubic(dy, r0, r1, r2, r3), cubic(dy, g0, g1, g2, g3), cubic(dy, b0, b1, b2, b3), cubic(dy, a0, a1, a2, a3)
rt, gt, bt, at = c3.RGBA() return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at) }
r, g, b, a := cubic(dy, r0, r1, r2, r3), cubic(dy, g0, g1, g2, g3), cubic(dy, b0, b1, b2, b3), cubic(dy, a0, a1, a2, a3)
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} func cubic(offset, v0, v1, v2, v3 float64) uint32 {
} // offset is the offset of the sampled value between v1 and v2
return uint32(((((-7*v0+21*v1-21*v2+7*v3)*offset+
func cubic(offset, v0, v1, v2, v3 float64) uint32 { (15*v0-36*v1+27*v2-6*v3))*offset+
// offset is the offset of the sampled value between v1 and v2 (-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0)
return uint32(((((-7*v0+21*v1-21*v2+7*v3)*offset+ }
(15*v0-36*v1+27*v2-6*v3))*offset+
(-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0) func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) {
} bounds := src.Bounds()
x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y)
func compose(c1, c2 image.Color) image.Color { tr.TransformRectangle(&x0, &y0, &x1, &y1)
r1, g1, b1, a1 := c1.RGBA() var x, y, u, v float64
r2, g2, b2, a2 := c2.RGBA() var c1, c2, cr image.Color
ia := M - a2 var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32
r := ((r1 * ia) / M) + r2 var color image.RGBAColor
g := ((g1 * ia) / M) + g2 for x = x0; x < x1; x++ {
b := ((b1 * ia) / M) + b2 for y = y0; y < y1; y++ {
a := ((a1 * ia) / M) + a2 u = x
return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} v = y
} tr.InverseTransform(&u, &v)
c1 = dest.At(int(x), int(y))
switch filter {
func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) { case LinearFilter:
bounds := src.Bounds() c2 = src.At(int(u), int(v))
x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y) case BilinearFilter:
tr.TransformRectangle(&x0, &y0, &x1, &y1) c2 = getColorBilinear(src, u, v)
var x, y, u, v float64 case BicubicFilter:
var c1, c2, cr image.Color c2 = getColorBicubic(src, u, v)
var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32 }
for x = x0; x < x1; x++ { switch op {
for y = y0; y < y1; y++ { case draw.Over:
u = x r1, g1, b1, a1 = c1.RGBA()
v = y r2, g2, b2, a2 = c2.RGBA()
tr.InverseTransform(&u, &v) ia = M - a2
c1 = dest.At(int(x), int(y)) r = ((r1 * ia) / M) + r2
switch filter { g = ((g1 * ia) / M) + g2
case LinearFilter: b = ((b1 * ia) / M) + b2
c2 = src.At(int(u), int(v)) a = ((a1 * ia) / M) + a2
case BilinearFilter: color.R = uint8(r >> 8)
c2 = getColorBilinear(src, u, v) color.G = uint8(g >> 8)
case BicubicFilter: color.B = uint8(b >> 8)
c2 = getColorBicubic(src, u, v) color.A = uint8(a >> 8)
} cr = color
switch op { default:
case draw.Over: cr = c2
r1, g1, b1, a1 = c1.RGBA() }
r2, g2, b2, a2 = c2.RGBA() dest.Set(int(x), int(y), cr)
ia = M - a2 }
r = ((r1 * ia) / M) + r2 }
g = ((g1 * ia) / M) + g2 }
b = ((b1 * ia) / M) + b2
a = ((a1 * ia) / M) + a2
cr = image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
default:
cr = c2
}
dest.Set(int(x), int(y), cr)
}
}
}

View File

@ -7,7 +7,7 @@ import (
) )
type StackGraphicContext struct { type StackGraphicContext struct {
current *ContextStack current *ContextStack
} }
type ContextStack struct { type ContextStack struct {
@ -30,7 +30,7 @@ type ContextStack struct {
/** /**
* Create a new Graphic context from an image * Create a new Graphic context from an image
*/ */
func NewStackGraphicContext() (*StackGraphicContext){ func NewStackGraphicContext() *StackGraphicContext {
gc := &StackGraphicContext{} gc := &StackGraphicContext{}
gc.current = new(ContextStack) gc.current = new(ContextStack)
gc.current.Tr = NewIdentityMatrix() gc.current.Tr = NewIdentityMatrix()

View File

@ -1,2 +1 @@
package draw2dgl package draw2dgl