perf(photos): ускорить рендер правок в 9 раз
Расчёт правок считал math.Pow для каждого канала каждого пикселя, из-за чего большое фото обрабатывалось больше секунды. Факторы правок теперь считаются один раз на рендер, квадраты считаются умножением, а строки обрабатываются параллельно. Обработка кадра 4000×3000 сократилась с 1.23 с до 0.14 с. Задержка от сохранения правок до появления отредактированной версии в сетке и просмотре: около 0.15 с для небольшого фото и 0.6 с для большого (полноразмерная версия догружается следом, через 1.4 с).
This commit is contained in:
@@ -3,6 +3,8 @@ package photos
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/gen2brain/webp"
|
||||
@@ -27,20 +29,49 @@ func applyLight(src image.Image, p LightParams) *image.NRGBA {
|
||||
red := curveLUT(p.Curve.Red)
|
||||
green := curveLUT(p.Curve.Green)
|
||||
blue := curveLUT(p.Curve.Blue)
|
||||
adj := newLightAdjuster(p)
|
||||
|
||||
rows := dst.Rect.Dy()
|
||||
workers := runtime.GOMAXPROCS(0)
|
||||
if workers > rows {
|
||||
workers = rows
|
||||
}
|
||||
if workers <= 1 {
|
||||
applyLightRows(dst, 0, rows, adj, &master, &red, &green, &blue)
|
||||
return dst
|
||||
}
|
||||
// Рендер больших фото идёт по строкам параллельно.
|
||||
chunk := (rows + workers - 1) / workers
|
||||
var wg sync.WaitGroup
|
||||
for from := 0; from < rows; from += chunk {
|
||||
to := from + chunk
|
||||
if to > rows {
|
||||
to = rows
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(from, to int) {
|
||||
defer wg.Done()
|
||||
applyLightRows(dst, from, to, adj, &master, &red, &green, &blue)
|
||||
}(from, to)
|
||||
}
|
||||
wg.Wait()
|
||||
return dst
|
||||
}
|
||||
|
||||
// applyLightRows applies the adjustments to the given range of rows.
|
||||
func applyLightRows(dst *image.NRGBA, from, to int, adj lightAdjuster, master, red, green, blue *[256]uint8) {
|
||||
width := dst.Rect.Dx()
|
||||
for y := 0; y < dst.Rect.Dy(); y++ {
|
||||
for y := from; y < to; y++ {
|
||||
row := dst.Pix[y*dst.Stride : y*dst.Stride+width*4]
|
||||
for i := 0; i+3 < len(row); i += 4 {
|
||||
if row[i+3] == 0 {
|
||||
continue
|
||||
}
|
||||
row[i] = uint8(adjustChannel(float64(row[i]), p, &master, &red))
|
||||
row[i+1] = uint8(adjustChannel(float64(row[i+1]), p, &master, &green))
|
||||
row[i+2] = uint8(adjustChannel(float64(row[i+2]), p, &master, &blue))
|
||||
row[i] = uint8(adj.apply(float64(row[i]), master, red))
|
||||
row[i+1] = uint8(adj.apply(float64(row[i+1]), master, green))
|
||||
row[i+2] = uint8(adj.apply(float64(row[i+2]), master, blue))
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// decodeAndAdjust decodes the original and applies the light adjustments to
|
||||
|
||||
Reference in New Issue
Block a user