Optimize binary size and thumbnail performance
This commit is contained in:
+43
-16
@@ -57,6 +57,14 @@ func resizeBox(src image.Image, width int) image.Image {
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
// JPEGs decode to *image.YCbCr. Reading its planes directly avoids an
|
||||
// interface call and a colour conversion per source pixel, which makes the
|
||||
// resize ~4x faster; everything else takes the generic At() path.
|
||||
avg := boxAvg
|
||||
if ycc, ok := src.(*image.YCbCr); ok {
|
||||
avg = func(_ image.Image, r image.Rectangle) color.RGBA { return boxAvgYCbCr(ycc, r) }
|
||||
}
|
||||
|
||||
for y := 0; y < dstH; y++ {
|
||||
sy0 := y * srcH / dstH
|
||||
sy1 := (y + 1) * srcH / dstH
|
||||
@@ -69,23 +77,42 @@ func resizeBox(src image.Image, width int) image.Image {
|
||||
if sx1 == sx0 {
|
||||
sx1 = sx0 + 1
|
||||
}
|
||||
var r, g, bl, n uint64
|
||||
for sy := sy0; sy < sy1; sy++ {
|
||||
for sx := sx0; sx < sx1; sx++ {
|
||||
sr, sg, sb, _ := src.At(b.Min.X+sx, b.Min.Y+sy).RGBA()
|
||||
r += uint64(sr >> 8)
|
||||
g += uint64(sg >> 8)
|
||||
bl += uint64(sb >> 8)
|
||||
n++
|
||||
}
|
||||
}
|
||||
dst.SetRGBA(x, y, color.RGBA{
|
||||
R: uint8(r / n),
|
||||
G: uint8(g / n),
|
||||
B: uint8(bl / n),
|
||||
A: 255,
|
||||
})
|
||||
box := image.Rect(sx0, sy0, sx1, sy1).Add(b.Min)
|
||||
dst.SetRGBA(x, y, avg(src, box))
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// boxAvg returns the mean colour of the pixels of src inside r.
|
||||
func boxAvg(src image.Image, r image.Rectangle) color.RGBA {
|
||||
var red, g, bl, n uint64
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
sr, sg, sb, _ := src.At(x, y).RGBA()
|
||||
red += uint64(sr >> 8)
|
||||
g += uint64(sg >> 8)
|
||||
bl += uint64(sb >> 8)
|
||||
n++
|
||||
}
|
||||
}
|
||||
return color.RGBA{R: uint8(red / n), G: uint8(g / n), B: uint8(bl / n), A: 255}
|
||||
}
|
||||
|
||||
// boxAvgYCbCr is boxAvg for *image.YCbCr, reading the sample planes directly.
|
||||
// Each pixel is still converted to RGB before averaging so out-of-gamut
|
||||
// samples clamp exactly as they do through At().
|
||||
func boxAvgYCbCr(src *image.YCbCr, r image.Rectangle) color.RGBA {
|
||||
var red, g, bl, n uint64
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
ci := src.COffset(x, y)
|
||||
sr, sg, sb := color.YCbCrToRGB(src.Y[src.YOffset(x, y)], src.Cb[ci], src.Cr[ci])
|
||||
red += uint64(sr)
|
||||
g += uint64(sg)
|
||||
bl += uint64(sb)
|
||||
n++
|
||||
}
|
||||
}
|
||||
return color.RGBA{R: uint8(red / n), G: uint8(g / n), B: uint8(bl / n), A: 255}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user