The world’s smallest PNG
,
up to date
(initially posted
)
The smallest PNG file is 67 bytes. It’s a single black pixel. Right here’s what it appears to be like like, zoomed in 200×:
Wow, what a magnificence.
This file has 4 sections:
- The PNG signature, the identical for each PNG: 8 bytes
- The picture’s metadata, which incorporates its dimensions: 25 bytes
- The picture’s pixel knowledge: 22 bytes
- An “finish of picture” marker: 12 bytes
The remainder of this submit describes this file in additional element and tries to elucidate how PNGs work alongside the best way.
There’s a giant twist on the finish, if that excites you. However I hope you’re simply excited to study PNGs.
Half 1: the PNG signature
Each single PNG, together with this one, begins with the identical 8 bytes. Encoded in hex, these bytes are:
89 50 4E 47 0D 0A 1A 0A
That is known as the PNG signature. Attempt doing a hex dump on any PNG and also you’ll see that it begins with these bytes.
PNG decoders use the signature to make sure that they’re studying a PNG picture. Usually, they reject the file if it doesn’t begin with the signature. Information can get corrupted in varied methods (ever had a file with the mistaken extension?) and this helps deal with that.
Enjoyable truth: for those who decode these bytes as ASCII, you’ll see the letters “PNG” in there:
.PNG....
In order that’s the primary 8 bytes. One half carried out! Right here’s our “guidelines”:
PNG signature- Picture metadata chunk
- Pixel knowledge chunk
- “Finish of picture” chunk
What about the remainder?
The following a part of the PNG is the picture metadata, which is one among a number of chunks. What’s a piece?
Fast intro to chunks
Aside from the PNG signature firstly, PNGs are made up of chunks.
Chunks have two logical items: a sort and a few knowledge bytes. Sorts are issues like “picture header” or “textual content metadata”. The information will depend on the sort—the textual content metadata chunk is encoded in a different way from the picture header chunk.
These logical items are encoded with four fields. These fields are all the time in the identical order for each chunk. They’re:
- Size: the variety of bytes within the chunk’s knowledge area (area #3 under). Encoded as a 4-byte integer.
- Chunk sort: the kind of chunk that is. There are many totally different chunk sorts. Encoded as a 4-byte ASCII string, resembling “IHDR” for “picture header” or “tEXt” for “textual content metadata”.
- Information: the information for the chunk. See the “size” area for what number of bytes there will probably be. Varies primarily based on the chunk sort. For instance, the IHDR chunk encodes the picture’s dimensions. Could also be empty, however normally isn’t.
- Checksum: a checksum for the remainder of the chunk, to verify no knowledge was corrupted. 4 bytes.
As you possibly can see, every chunk is a minimal of 12 bytes lengthy (4 for the size, 4 for the sort, and 4 for the checksum).
Be aware that the “size” area is the dimensions of the “knowledge” area, not all the chunk. If you wish to know the entire dimension of the chunk, simply add 12—4 bytes for the size, 4 bytes for the sort, and 4 bytes for the checksum.
You could have some wiggle room however chunks have a particular order. For instance, the picture metadata chunk has to seem earlier than the pixel knowledge chunk. When you attain the “picture is finished” chunk, the PNG is finished.
Our tiny PNG may have simply three of those chunks.
The primary chunk of each PNG, together with ours, is of sort IHDR, quick for “image header”.
Every chunk begins with the size of the information in that chunk.
The IHDR chunk all the time has 13 bytes of related knowledge, as we’ll see in a second. 13 is 0D
in hex, which will get encoded like this:
00 00 00 0D
The chunk sort is subsequent. That is one other 4 bytes. “IHDR” is encoded as:
49 48 44 52
That is simply ASCII encoding. Chunk sorts are made up of ASCII letters. The capitalization of each letter is significant. For instance, the primary letter is capitalized which implies it’s a required chunk.
Subsequent, the chunk’s knowledge. IHDR’s knowledge occurs to be 13 whole bytes, organized as follows:
-
The primary eight bytes encode the picture’s width and peak. As a result of it is a 1×1 picture, that’s encoded as
00 00 00 01 00 00 00 01
. -
The following two bytes are the bit depth and color type.
These values are in all probability essentially the most complicated a part of this PNG.
There are 5 attainable coloration sorts. Our picture is black-and-white so we use the “greyscale” coloration sort (encoded as
00
). If our picture had coloration, we’d use the “truecolor” sort (encoded with02
). There are three different coloration sorts which we don’t want in the present day, however you possibly can read more about them in the PNG specification.When you’ve picked a coloration sort, that you must choose a bit depth. The bit depth will depend on the colour sort, however normally means the variety of bits per coloration channel in a picture. For instance, hex colours like
#FE9802
have a bit depth of eight—eight bits for purple, eight bits for inexperienced, and eight bits for blue. Our all-black picture doesn’t want all that…we solely want one bit! The pixel is both utterly black (0
) or utterly white (1
)—in our case, it’s utterly black.If we picked a extra “expressive” coloration sort and bit depth, we might make the identical 1×1 picture visually, however the file may very well be larger as a result of there may very well be extra bits per pixel that we don’t really need. For instance, if we used the “truecolor” sort and 16 bits per channel, every pixel would require 48 bits as a substitute of only one—not essential to encode “utterly black”.
With bit depth of 1 and a coloration sort of 0, we encode these two values with
00 01
. -
The following byte is the compression method. All PNGs set this to
00
for now. That is right here simply in case they need to add one other compression technique later. So far as I do know, no person has. -
Identical story for the filter method. It’s all the time
00
. -
The final a part of the chunk’s knowledge is the interlace method. PNGs help progressive decoding which permits pictures to be partly rendered as they obtain. We aren’t going to make use of that function so we set this to
00
.
Lastly, each chunk ends with a four-byte checksum. It makes use of a common checksum function known as CRC32, and makes use of the remainder of the chunk as an enter. Computing that checksum offers us the next bytes:
37 6E F9 24
All collectively, right here’s the entire IHDR chunk:
Bytes | What? |
---|---|
00 00 00 0D |
knowledge size of 13 bytes |
49 48 44 52 |
“IHDR” as ASCII |
00 00 00 01 |
width |
00 00 00 01 |
peak |
01 |
bit depth |
00 |
coloration sort |
00 |
compression technique |
00 |
filter technique |
00 |
interlace technique |
37 6E F9 24 |
checksum |
In order that’s our first chunk! Let’s take one other take a look at our guidelines:
PNG signaturePicture metadata chunk- Pixel knowledge chunk
- “Finish of picture” chunk
Two extra chunks to go—pixel knowledge is subsequent.
Half 3: pixel knowledge chunk
Our subsequent chunk is IDAT, quick for “image data”. That is the place the precise pixels are encoded…or only one pixel, in our case.
Do not forget that every chunk has 4 elements: the information’s size, the chunk sort, the knowledge, and a checksum.
This chunk may have 10 bytes of knowledge. We’ll discuss what that knowledge is shortly, however I promise it’s 10 bytes. Let’s encode that size:
00 00 00 0A
Subsequent, let’s encode “IDAT” for the chunk sort:
49 44 41 54
Once more, that is simply ASCII, and I’m displaying the hex-encoded values.
Now for the attention-grabbing half: the picture knowledge.
First step: uncompressed pixels
Picture knowledge is encoded in a sequence of “scanlines”, after which compressed.
A scanline represents a horizontal line of pixels. For instance, a 123×456 picture has 456 scanlines. In our case, we now have only one scanline, as a result of our picture is only one pixel tall.
Scanlines begin with one thing known as a filter type which may enhance compression, relying in your picture. Our picture is so small that that is irrelevant, so we use filter sort 0, or “None”.
After the filter sort, every pixel is encoded with a number of bits, relying on the bit depth. In our case, we simply want one bit per pixel—recall that we now have a bit depth of 1; all black or all white.
In case your pixel knowledge doesn’t line up with a byte boundary—in different phrases, if it’s not a a number of of 8 bits—you pad the top of your scanline with zeroes. That’s true in our case, so we add seven padding bits to fill out a byte.
Placing that collectively (a zero byte to begin the scanline, the one zero bit, and 7 zero padding bits), our single scanline is:
00 00
Now it’s time to “compress” the information.
Second step: “compression”
Subsequent, we compress the scanline knowledge…nicely, not fairly.
Extra precisely, we run it by a compression algorithm. More often than not, compression algorithms produce smaller outputs—that’s the entire level! However typically, “compressing” tiny inputs really produces larger outputs due to some small overhead. Sadly for us, that’s what occurs right here. However the PNG file format makes us do it.
PNG picture knowledge is encoded in the zlib format utilizing the DEFLATE compression algorithm. DEFLATE can also be used with gzip and ZIP, two highly regarded compression codecs.
I gained’t go in depth on DEFLATE right here (partly as a result of I’m not an knowledgeable), however right here’s what our chunk’s knowledge comprises:
- The zlib header: 2 bytes
- One compressed DEFLATE block that encodes two literal zeroes: 4 bytes
- The zlib checksum (that is separate from the PNG chunk checksum!): 4 bytes
For extra on how DEFLATE works, take a look at “An Explanation of the DEFLATE Algorithm”. I additionally advocate infgen, a great tool for inspecting DEFLATE streams.
All collectively, listed here are the ten knowledge bytes:
78 01 63 60 00 00 00 02 00 01
Once more, unlucky that we needed to run our two-byte scanline by an algorithm that made it 5 occasions larger, however PNG makes us do it!
With that, we will compute the PNG’s checksum area and end off the chunk.
Bytes | What? |
---|---|
00 00 00 0A |
knowledge size of 10 bytes |
49 44 41 54 |
“IDAT” as ASCII |
78 01 |
zlib header |
63 60 00 00 |
“compressed” DEFLATE block |
00 02 00 01 |
zlib checksum |
73 75 01 18 |
chunk checksum |
Only one extra chunk to go! Taking a last take a look at our guidelines at first is crossed off:
PNG signaturePicture metadata chunkPixel knowledge chunk- “Finish of picture” chunk
Let’s end this up.
Half 4: the top
Poetically, PNGs finish like they start: with a small variety of fixed bytes.
IEND is the ultimate chunk, quick for “image trailer”.
The zero size is encoded with 4 zeroes:
00 00 00 00
“IEND” is then encoded:
49 45 4E 44
There’s no knowledge in IEND chunks, so we simply transfer onto the checksum. As a result of every part else within the chunk is fixed, this checksum is all the time the identical:
AE 42 60 82
Right here’s the entire trailer chunk:
Bytes | What? |
---|---|
00 00 00 00 |
knowledge size of 0 |
49 45 4E 44 |
“IEND” as ASCII |
AE 42 60 82 |
checksum |
And our PNG is finished!
Admiring our work
Right here it’s yet one more time, scaled up 200×:
Lovely. It begins with the traditional PNG signature, follows up with a little bit of metadata, “compresses” the pixel knowledge, and indicators off with an empty chunk.
And that’s the world’s smallest PNG!
…or is it?
The twist: there are many champions
All through this submit, I’ve stated that that is the world’s smallest PNG. However that’s not fairly true: it’s tied for first. There are a number of “world’s smallest PNGs”!
So long as we encode all pixel knowledge in a single byte, we will tie for the world’s smallest PNG.
For instance, you may encode this 8×1 black picture, which can also be 67 bytes:
This works as a result of we use all eight bits are used to encode pixel knowledge.
With our 1×1 picture, recall that seven bits had been successfully “wasted” on padding. Right here’s mainly what occurred:
Bits | What? |
---|---|
0 |
a black pixel |
0000000 |
padding |
An 8×1 picture can encode eight black pixels like so:
Bits | What? |
---|---|
00000000 |
eight black pixels |
As a substitute of including extra pixels, you may additionally add extra coloration decision. Many gray colours could be encoded in a single byte, letting us tie for first. For instance, this 1×1 gray pixel can also be 67 bytes:
Once more, this “makes use of up” the entire byte we now have out there, in contrast to our 1×1 picture.
For extra on this, my former coworker Jordan Rose printed “The Biggest Smallest PNG” in response to this submit. It reveals the most important 67-byte PNG: a 1×2064 black line.
Abstract
PNGs begin with a “signature”. The remainder of the file is made up of chunks. Every chunk has a size, sort, knowledge, and checksum. Some chunks are all the time required, just like the picture header (IHDR) chunk.
The smallest PNGs use the minimal variety of chunks and the smallest attainable knowledge.
Our PNGs are made up of 4 elements:
- The fixed PNG signature (8 bytes)
- The IHDR chunk, containing metadata (25 bytes)
- The IDAT chunk, picture pixel knowledge (22 bytes)
- The IEND chunk, a picture trailer (12 bytes)
When you’re serious about studying extra about PNGs interactively, I constructed PNG Chunk Explorer, which helps you to analyze PNGs. Attempt importing your individual pictures to see what they’re made from! (It doesn’t work nicely on cellular, apologies.)
I additionally constructed Single Color Image, which generates monochromatic PNGs of arbitrary sizes. For instance, you may generate a 12×34 purple rectangle. The pictures needs to be small however I haven’t but carried out essentially the most refined compression, so that you would possibly must run its outcomes by a PNG compressor to realize the smallest sizes.
Lastly, I additionally wrote in regards to the largest possible PNG. There’s no theoretical file dimension restrict, however there’s a most variety of pixels, and plenty of decoders impose varied limits.
I hope this lengthy submit has given you a superb understanding of the PNG file format. When you learn this far and have something to say, let me know!