New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ImageData implement draw.Image interface. #50

Merged
merged 1 commit into from Jan 9, 2018

Conversation

Projects
None yet
2 participants
@dmitshur
Collaborator

dmitshur commented Jan 9, 2018

According to HTML standard, ImageData is defined to contain non-alpha-premultiplied pixels [1][2]:

Pixel values must not be premultiplied by alpha.

As a result, we change ImageData to use NRGBA rather than RGBA.

ImageData, in nature, is similar to image.NRGBA.

We change its API slightly to be more like image.NRGBA. This allows it to implement image.Image and draw.Image interfaces. That makes ImageData more useful, since it can be passed directly to drawing algorithms that work with image.Image or draw.Image. Skipping a temporary image.NRGBA can improve performance significantly.

Also implement bounds checking in At and Set methods to be consistent with image package.
(It's still possible to access the underlying data directly, if desired, via Data field.)

A downside of this change is the need to import image package, which can increase binary size. The increase is small enough, and the benefits of making ImageData more useful for idiomatic usage are deemed to justify the cost.


Output sizes of various programs that import dom package, in bytes. Minified. Uncompressed.

Before

$ curl -s localhost:8080/github.com/shurcooL/play/233/233.js | wc -c
  456030
$ curl -s localhost:8080/resume.js | wc -c
 5353378
$ curl -s localhost:8080/assets/blog/blog.js | wc -c
 5886257

After

$ curl -s localhost:8080/github.com/shurcooL/play/233/233.js | wc -c
  478307
$ curl -s localhost:8080/resume.js | wc -c
 5367217
$ curl -s localhost:8080/assets/blog/blog.js | wc -c
 5900096

Example

Before

// Create a temporary *image.NRGBA to use as buffer.
m := image.NewNRGBA(image.Rect(0, 0, width, height))

// Draw text on image.
fd := font.Drawer{
	Dst:  m,
	Src:  image.Black,
	Face: face,
	Dot:  fixed.P(100*scale, height-100*scale),
}
fd.DrawString("Hello.")

// Output image to a context.
id := ctx.CreateImageData(width, height)
for y := 0; y < height; y++ {
	for x := 0; x < width; x++ {
		id.SetNRGBA(x, y, m.NRGBAAt(x, y))
	}
}
ctx.PutImageData(id, 0, 0)

After

// Create and use ImageData as a draw.Image directly.
m := ctx.CreateImageData(width, height)

// Draw text on image.
fd := font.Drawer{
	Dst:  m,
	Src:  image.Black,
	Face: face,
	Dot:  fixed.P(100*scale, height-100*scale),
}
fd.DrawString("Hello.")

// Output image to a context.
ctx.PutImageData(m, 0, 0)

References

  1. https://html.spec.whatwg.org/multipage/canvas.html#pixel-manipulation
  2. https://stackoverflow.com/questions/23497925/how-can-i-stop-the-alpha-premultiplication-with-canvas-imagedata
Make ImageData implement draw.Image interface
According to HTML standard, ImageData is defined to contain
non-alpha-premultiplied pixels [1][2]:

>	Pixel values must not be premultiplied by alpha.

As a result, we change ImageData to use NRGBA rather than RGBA.

ImageData, in nature, is similar to image.NRGBA.

We change its API slightly to be more like image.NRGBA. This allows it
to implement image.Image and draw.Image interfaces. That makes ImageData
more useful, since it can be passed directly to drawing algorithms that
work with image.Image or draw.Image. Skipping a temporary image.NRGBA
can improve performance significantly.

Also implement bounds checking in At and Set methods to be consistent
with image package. (It's still possible to access the underlying data
directly, if desired, via Data field.)

A downside of this change is the need to import image package, which
can increase binary size. The increase is small enough, and the
benefits of making ImageData more useful for idiomatic usage are deemed
to justify the cost.

References:

1.	https://html.spec.whatwg.org/multipage/canvas.html#pixel-manipulation
2.	https://stackoverflow.com/questions/23497925/how-can-i-stop-the-alpha-premultiplication-with-canvas-imagedata
@dominikh

LGTM after previously discussed change to commit message.

@dmitshur dmitshur merged commit 6a8015d into master Jan 9, 2018

@dmitshur dmitshur deleted the ImageData-implement-draw.Image branch Jan 9, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment