internal/restorable: remove clearIfOverlapped

We found clearIfOverlapped could be a heavy task in some actual applications.
Instead of clearing existing data in the pixels records, add a new record
with a nil slice which indicates a cleared region.
This commit is contained in:
Hajime Hoshi 2023-05-25 21:03:40 +09:00
parent 47f19da710
commit 0f4066e7ac
2 changed files with 31 additions and 28 deletions

View File

@ -244,9 +244,6 @@ func (i *Image) makeStale(rect image.Rectangle) {
// Clear pixels to save memory. // Clear pixels to save memory.
for _, r := range addedRegions { for _, r := range addedRegions {
if r.Empty() {
continue
}
i.basePixels.Clear(r) i.basePixels.Clear(r)
} }

View File

@ -26,25 +26,6 @@ type pixelsRecord struct {
pix []byte pix []byte
} }
func (p *pixelsRecord) clearIfOverlapped(rect image.Rectangle) {
r := p.rect.Intersect(rect)
if r.Empty() {
return
}
ox := r.Min.X - p.rect.Min.X
oy := r.Min.Y - p.rect.Min.Y
w := p.rect.Dx()
for j := 0; j < r.Dy(); j++ {
for i := 0; i < r.Dx(); i++ {
idx := 4 * ((oy+j)*w + ox + i)
p.pix[idx] = 0
p.pix[idx+1] = 0
p.pix[idx+2] = 0
p.pix[idx+3] = 0
}
}
}
func (p *pixelsRecord) readPixels(pixels []byte, region image.Rectangle, imageWidth, imageHeight int) { func (p *pixelsRecord) readPixels(pixels []byte, region image.Rectangle, imageWidth, imageHeight int) {
r := p.rect.Intersect(region.Intersect(image.Rect(0, 0, imageWidth, imageHeight))) r := p.rect.Intersect(region.Intersect(image.Rect(0, 0, imageWidth, imageHeight)))
if r.Empty() { if r.Empty() {
@ -56,11 +37,20 @@ func (p *pixelsRecord) readPixels(pixels []byte, region image.Rectangle, imageWi
srcBaseX := r.Min.X - p.rect.Min.X srcBaseX := r.Min.X - p.rect.Min.X
srcBaseY := r.Min.Y - p.rect.Min.Y srcBaseY := r.Min.Y - p.rect.Min.Y
lineWidth := 4 * r.Dx() lineWidth := 4 * r.Dx()
if p.pix != nil {
for j := 0; j < r.Dy(); j++ { for j := 0; j < r.Dy(); j++ {
dstX := 4 * ((dstBaseY+j)*region.Dx() + dstBaseX) dstX := 4 * ((dstBaseY+j)*region.Dx() + dstBaseX)
srcX := 4 * ((srcBaseY+j)*p.rect.Dx() + srcBaseX) srcX := 4 * ((srcBaseY+j)*p.rect.Dx() + srcBaseX)
copy(pixels[dstX:dstX+lineWidth], p.pix[srcX:srcX+lineWidth]) copy(pixels[dstX:dstX+lineWidth], p.pix[srcX:srcX+lineWidth])
} }
} else {
for j := 0; j < r.Dy(); j++ {
dstX := 4 * ((dstBaseY+j)*region.Dx() + dstBaseX)
for i := 0; i < lineWidth; i++ {
pixels[i+dstX] = 0
}
}
}
} }
type pixelsRecords struct { type pixelsRecords struct {
@ -98,12 +88,19 @@ func (pr *pixelsRecords) addOrReplace(pixels []byte, region image.Rectangle) {
} }
func (pr *pixelsRecords) clear(region image.Rectangle) { func (pr *pixelsRecords) clear(region image.Rectangle) {
if region.Empty() {
return
}
var n int var n int
var needsClear bool
for _, r := range pr.records { for _, r := range pr.records {
if r.rect.In(region) { if r.rect.In(region) {
continue continue
} }
r.clearIfOverlapped(region) if r.rect.Overlaps(region) {
needsClear = true
}
pr.records[n] = r pr.records[n] = r
n++ n++
} }
@ -111,6 +108,11 @@ func (pr *pixelsRecords) clear(region image.Rectangle) {
pr.records[i] = nil pr.records[i] = nil
} }
pr.records = pr.records[:n] pr.records = pr.records[:n]
if needsClear {
pr.records = append(pr.records, &pixelsRecord{
rect: region,
})
}
} }
func (pr *pixelsRecords) readPixels(pixels []byte, region image.Rectangle, imageWidth, imageHeight int) { func (pr *pixelsRecords) readPixels(pixels []byte, region image.Rectangle, imageWidth, imageHeight int) {
@ -125,7 +127,11 @@ func (pr *pixelsRecords) readPixels(pixels []byte, region image.Rectangle, image
func (pr *pixelsRecords) apply(img *graphicscommand.Image) { func (pr *pixelsRecords) apply(img *graphicscommand.Image) {
// TODO: Isn't this too heavy? Can we merge the operations? // TODO: Isn't this too heavy? Can we merge the operations?
for _, r := range pr.records { for _, r := range pr.records {
if r.pix != nil {
img.WritePixels(r.pix, r.rect) img.WritePixels(r.pix, r.rect)
} else {
img.WritePixels(make([]byte, 4*r.rect.Dx()*r.rect.Dy()), r.rect)
}
} }
} }