/* * Add this to the top of your post. This will get interpreted in and applies to your page * e.g. * * (this code) * * # My Summer Vacation * * ## Grandma's House * * We left for Grandma's house at 2pm on Friday. I was so excited to see her pet Bear and Fox! */
var fixGistRules = [ ".gist .gist-highlight { border-left: 3ex solid #eee; position: relative;}", ".gist .gist-highlight pre { counter-reset: linenumbers;}", ".gist .gist-highlight pre div:before { color: #aaa; content: counter(linenumbers); counter-increment: linenumbers; left: -3ex; position: absolute; text-align: right; width: 2.5ex;}" ];
var head = document.getElementsByTagName('head')[0], style = document.createElement('style');
rules = new Array(); var i=0; for ( i=0; i< fixGistRules.length; i++ ){ var fullrule = document.createTextNode(fixGistRules[i]); rules.push(fullrule); } style.type = 'text/css'; for ( var i=0; i< rules.length; i++ ){ if(style.styleSheet){ style.styleSheet.cssText = rules[i].nodeValue; }else { style.appendChild(rules[i]); head.appendChild(style); } }
The good folks at Instagram posted a fun challenge on their engineering blog recently:
"Your challenge, if you choose to accept it, is to write a simple script that takes a shredded image in as input and outputs an unshredded and reconstituted image. That is, imagine if you took an image, divided it into an even number of columns and shuffled those columns randomly to produce a shredded image. Then, take that image into the script and output the original image."
(The original post is here: Instagram Engineering Challenge: The Unshredder).
This struck me as a great opportunity to hack out some code in Go (rev 60.1) as part of my continuing exploration of the language and its packages.
Here are the input and target output images:
They offer the following tips:
Great. The simplest approach that occurred to me was this:
As it turns out, this works. My solution is on Github here: https://github.com/joncooper/instashred. They've run out of t-shirts, though :P, so no soup for me.
Here's a quick tour of the standard library's packages that I used:
The image.Image
interface from the image package provides what the docs describe in their typically awesome and laconic manner as "a finite rectangular grid of Colors drawn from a ColorModel."
Basically, the image.Image
interface defines a read-only grid of pixels expressed as image.Color
, upon which you can call RGBA()
to get out a tuple containing alpha-premultiplied channel intensities.
At first the read-only nature of image.Image
made me scratch my head a bit. But it ends up being pretty neat. You can do things like create a procedural image which can then be sampled, like this:
The standard library also implements image.Tiled, which acts like an infinitely (okay, just extremely large) large tiling of a source image. See the source here--it's just pretty.
Image file support is minimal but useful at the moment. There are image
subpackages that implement decoding/encoding for JPEG and PNG, and decode only for BMP, GIF and TIFF.
Here's an example for how you write an image.Image to a PNG file:
This package implements image compositing functions and little else. In particular, it doesn't implement vector art staples like line, circle, rectangle, etc.
It's deals solely with compositing images by copying image.Color
pixels from one image.Image
and pasting them into a draw.Image
, optionally using a mask and a Porter-Duff compositing operator.
See the golang blog's post on this package here: The Go image/draw package.
The primary operation I used is image.Draw
, which has the following function signature:
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
This copies a region the size of r
from src
into dst
with the top left corner at sp
.
Here's an example combining tying the last three together:
The relationship between image.Image and draw.Image is extremely representative of idiomatic Go. In Go, a type doesn't declare that it implements an interface, it just does so, and it gets checked statically at compile time.
A draw.Image
is just like an image.Image
, but you can draw into it. The interface requirements are a superset of those defined in image.Image
. Taking a look at the source to draw.Image
reveals the neat way that interface inheritance happens in Go:
This implementation was enjoyable; I am really warming up to Go.
So far, the standard libraries are uniformly sensible and in many cases beautiful. It's clearly an opinionated language and set of packages, but so far, I seem to agree with those opinions. :)
Cheers,
Jon