internal/restorable/image.go
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
	w, h := i.image.Size()
	if width <= 0 || height <= 0 {
		panic("restorable: width/height must be positive")
	}
	if x < 0 || y < 0 || w <= x || h <= y || x+width <= 0 || y+height <= 0 || w < x+width || h < y+height {
		panic(fmt.Sprintf("restorable: out of range x: %d, y: %d, width: %d, height: %d", x, y, width, height))
	}

	// TODO: Avoid making other images stale if possible. (#514)
	// For this purpuse, images should remember which part of that is used for DrawTriangles.
	theImages.makeStaleIfDependingOn(i)

	if pixels == nil {
		pixels = make([]byte, 4*width*height)
	}
	i.image.ReplacePixels(pixels, x, y, width, height)

	if !IsRestoringEnabled() {
		i.makeStale()
		return
	}

	if x == 0 && y == 0 && width == w && height == h {
		if pixels != nil {
			if i.basePixels == nil {
				i.basePixels = &Pixels{
					length: 4 * w * h,
				}
			}
			i.basePixels.CopyFrom(pixels, 0)
		} else {
			// If basePixels is nil, the restored pixels are cleared.
			// See restore() implementation.
			i.basePixels = nil
		}
		i.drawTrianglesHistory = nil
		i.stale = false
		return
	}

	if len(i.drawTrianglesHistory) > 0 {
		panic("restorable: ReplacePixels for a part after DrawTriangles is forbidden")
	}

	if i.stale {
		return
	}

	idx := 4 * (y*w + x)
	if pixels != nil {
		if i.basePixels == nil {
			i.basePixels = &Pixels{
				length: 4 * w * h,
			}
		}
		for j := 0; j < height; j++ {
			i.basePixels.CopyFrom(pixels[4*j*width:4*(j+1)*width], idx)
			idx += 4 * w
		}
	} else if i.basePixels != nil {
		zeros := make([]byte, 4*width)
		for j := 0; j < height; j++ {
			i.basePixels.CopyFrom(zeros, idx)
			idx += 4 * w
		}
	}
}
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
	w, h := i.image.Size()
	if width <= 0 || height <= 0 {
		panic("restorable: width/height must be positive")
	}
	if x < 0 || y < 0 || w <= x || h <= y || x+width <= 0 || y+height <= 0 || w < x+width || h < y+height {
		panic(fmt.Sprintf("restorable: out of range x: %d, y: %d, width: %d, height: %d", x, y, width, height))
	}

	// TODO: Avoid making other images stale if possible. (#514)
	// For this purpuse, images should remember which part of that is used for DrawTriangles.
	theImages.makeStaleIfDependingOn(i)

	if pixels == nil {
		pixels = make([]byte, 4*width*height)
	}
	i.image.ReplacePixels(pixels, x, y, width, height)

	if !IsRestoringEnabled() {
		i.makeStale()
		return
	}

	if x == 0 && y == 0 && width == w && height == h {
		if pixels != nil {
			if i.basePixels == nil {
				i.basePixels = &Pixels{
					length: 4 * w * h,
				}
			}
			i.basePixels.CopyFrom(pixels, 0)
		} else {
			// If basePixels is nil, the restored pixels are cleared.
			// See restore() implementation.
			i.basePixels = nil
		}
		i.drawTrianglesHistory = nil
		i.stale = false
		return
	}

	if len(i.drawTrianglesHistory) > 0 {
		panic("restorable: ReplacePixels for a part after DrawTriangles is forbidden")
	}

	if i.stale {
		return
	}

	idx := 4 * (y*w + x)
	if pixels != nil {
		if i.basePixels == nil {
			i.basePixels = &Pixels{
				length: 4 * w * h,
			}
		}
		for j := 0; j < height; j++ {
			i.basePixels.CopyFrom(pixels[4*j*width:4*(j+1)*width], idx)
			idx += 4 * w
		}
	} else if i.basePixels != nil {
		zeros := make([]byte, 4*width)
		for j := 0; j < height; j++ {
			i.basePixels.CopyFrom(zeros, idx)
			idx += 4 * w
		}
	}
}
// ReplacePixels replaces the image pixels with the given pixels slice.
//
// If pixels is nil, ReplacePixels clears the specified reagion.