Go语言中对图像进行缩放

由Google开发,简洁、高效、开源的Go语言日渐成为语言新宠。它专门针对多处理器系统应用程序的编程进行优化,使得Go编译的程序与C或C++代码的速度相媲美,且更安全、支持并行进程。Go语言在Go1版本上支持Windows, 苹果Mac OS X, Linux和FreeBSD操作系统。Go支持面向对象,而且具有真正的封装(closures)和反射 (reflection)等功能。

在学习曲线方面,派克认为Go与Java类似,对于Java开发者来说,应该能够轻松学会 Go。同样,对于C#开发者来说,也很轻松学会GO语言。

笔者对图形图像研究很感兴趣,让我们来看看Go语言中对图像进行缩放的解决方案:

package resize

import (

"image"

"image/color"

)

// average convert the sums to averages and returns the result.

func average(sum []uint64, w, h int, n uint64) *image.RGBA {

ret := image.NewRGBA(image.Rect(0, 0, w, h))

for y := 0; y < h; y++ {

for x := 0; x < w; x++ {

index := 4 * (y*w + x)

pix := ret.Pix[y*ret.Stride+x*4:]

pix[0] = uint8(sum[index+0] / n)

pix[1] = uint8(sum[index+1] / n)

pix[2] = uint8(sum[index+2] / n)

pix[3] = uint8(sum[index+3] / n)

}

}

return ret

}

// ResizeRGBA returns a scaled copy of the RGBA image slice r of m.

// The returned image has width w and height h.

func ResizeRGBA(m *image.RGBA, r image.Rectangle, w, h int) *image.RGBA {

ww, hh := uint64(w), uint64(h)

dx, dy := uint64(r.Dx()), uint64(r.Dy())

// See comment in Resize.

n, sum := dx*dy, make([]uint64, 4*w*h)

for y := r.Min.Y; y < r.Max.Y; y++ {

pix := m.Pix[(y-r.Min.Y)*m.Stride:]

for x := r.Min.X; x < r.Max.X; x++ {

// Get the source pixel.

p := pix[(x-r.Min.X)*4:]

r64 := uint64(p[0])

g64 := uint64(p[1])

b64 := uint64(p[2])

a64 := uint64(p[3])

// Spread the source pixel over 1 or more destination rows.

py := uint64(y) * hh

for remy := hh; remy > 0; {

qy := dy - (py % dy)

if qy > remy {

qy = remy

}

// Spread the source pixel over 1 or more destination columns.

px := uint64(x) * ww

index := 4 * ((py/dy)*ww + (px / dx))

for remx := ww; remx > 0; {

qx := dx - (px % dx)

if qx > remx {

qx = remx

}

qxy := qx * qy

sum[index+0] += r64 * qxy

sum[index+1] += g64 * qxy

sum[index+2] += b64 * qxy

sum[index+3] += a64 * qxy

index += 4

px += qx

remx -= qx

}

py += qy

remy -= qy

}

}

}

return average(sum, w, h, n)

}

// ResizeNRGBA returns a scaled copy of the RGBA image slice r of m.

// The returned image has width w and height h.

func ResizeNRGBA(m *image.NRGBA, r image.Rectangle, w, h int) *image.RGBA {

ww, hh := uint64(w), uint64(h)

dx, dy := uint64(r.Dx()), uint64(r.Dy())

// See comment in Resize.

n, sum := dx*dy, make([]uint64, 4*w*h)

for y := r.Min.Y; y < r.Max.Y; y++ {

pix := m.Pix[(y-r.Min.Y)*m.Stride:]

for x := r.Min.X; x < r.Max.X; x++ {

// Get the source pixel.

p := pix[(x-r.Min.X)*4:]

r64 := uint64(p[0])

g64 := uint64(p[1])

b64 := uint64(p[2])

a64 := uint64(p[3])

r64 = (r64 * a64) / 255

g64 = (g64 * a64) / 255

b64 = (b64 * a64) / 255

// Spread the source pixel over 1 or more destination rows.

py := uint64(y) * hh

for remy := hh; remy > 0; {

qy := dy - (py % dy)

if qy > remy {

qy = remy

}

// Spread the source pixel over 1 or more destination columns.

px := uint64(x) * ww

index := 4 * ((py/dy)*ww + (px / dx))

for remx := ww; remx > 0; {

qx := dx - (px % dx)

if qx > remx {

qx = remx

}

qxy := qx * qy

sum[index+0] += r64 * qxy

sum[index+1] += g64 * qxy

sum[index+2] += b64 * qxy

sum[index+3] += a64 * qxy

index += 4

px += qx

remx -= qx

}

py += qy

remy -= qy

}

}

}

return average(sum, w, h, n)

}

// Resample returns a resampled copy of the image slice r of m.

// The returned image has width w and height h.

func Resample(m image.Image, r image.Rectangle, w, h int) *image.RGBA {

if w < 0 || h < 0 {

return nil

}

if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {

return image.NewRGBA(image.Rect(0, 0, w, h))

}

curw, curh := r.Dx(), r.Dy()

img := image.NewRGBA(image.Rect(0, 0, w, h))

for y := 0; y < h; y++ {

for x := 0; x < w; x++ {

// Get a source pixel.

subx := x * curw / w

suby := y * curh / h

r32, g32, b32, a32 := m.At(subx, suby).RGBA()

r := uint8(r32 >> 8)

g := uint8(g32 >> 8)

b := uint8(b32 >> 8)

a := uint8(a32 >> 8)

img.SetRGBA(x, y, color.RGBA{r, g, b, a})

}

}

return img

}

有了上面的基础,下文讲解 利用Go语言上传图像并生成缩略图