Hacker News new | ask | show | jobs
by Retr0id 1525 days ago
With some dirty hacks, I got it down to 83 bytes:

https://cdn.discordapp.com/attachments/286612533757083648/96...

  00  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
  10  00 00 01 00 00 00 01 00  01 03 00 00 00 66 bc 3a  |.............f�:|
  20  25 00 00 00 03 50 4c 54  45 b5 d0 d0 63 04 16 ea  |%....PLTE���c..�|
  30  00 00 00 1b 49 44 41 54  68 81 ec c1 01 0d 00 00  |....IDATh.��....|
  40  00 c2 a0 f7 4f 6d 0f 07  14 00 00 00 00 00 00 00  |. �Om..........|
  50  c0 b9 01                                          |��.|
Although technically invalid, it still renders fine in Firefox, Chrome, and Safari.

Edit: 87 -> 83 bytes

Edit2: Maybe in a couple of years time, we can use JPEG-XL instead (only 22 bytes, without any hacks!):

  data:image/jxl;base64,/wp/QCQIBgEALABLOEmIDIPCakgSBg==
5 comments

Hadn't heard of JPEG XL until you mentioned it. The format looks really cool! Support for lossless and lossy compression, animation, and tons of other new features

https://en.wikipedia.org/wiki/JPEG_XL

Preliminary support in Firefox and Chromium nightly/testing builds already. I share your hope that we can start to use it in the next couple years. Looking at you, Safari ;)

Still sad about the demise of JNG all these years later. There was even a "light" version of the spec to address the complexity issues, and someone in bug #18574 had even made a reference library which took up less space than the default Mozilla libpng, and maintained their own browser branch. It was maintained for a few years but abandoned when it was clear Mozilla was all in on APNG.

But, yeah, we had all those things in something that was actually in major browsers, 22 years ago.

https://bugzilla.mozilla.org/show_bug.cgi?id=18574

http://mngzilla.sourceforge.net/

There is this JPEG XL art gallery with very nice images 20-100 bytes e.g.: https://jpegxl.info/art/2021-04_jon.html

To see them, enable flag in chrome: chrome://flags/#enable-jxl

I thought that it had existed for decades, but I had confused it for jp2. https://en.wikipedia.org/wiki/JPEG_2000
JXL without container has a very short header, which is nice.

WebP is 38 bytes, and is already supported by browsers.

  00000000  52 49 46 46 24 00 00 00  57 45 42 50 56 50 38 4c  |RIFF$...WEBPVP8L|
  00000010  18 00 00 00 2f ff c0 3f  00 07 50 e8 d6 16 ba ff  |..../???..P??.??|
  00000020  01 00 45 fa ff 9f 22 fa  9f fa df 7f              |..E??."?.??.|


  data:image/webp;base64,UklGRiQAAABXRUJQVlA4TBgAAAAv/8A/AAdQ6NYWuv8BAEX6/58i+p/6338=

Maybe can be made smaller, I just used cwebp -z 9.
> Although technically invalid, it still renders fine in Firefox, Chrome, and Safari.

When I learned HTML the syntax was sooo particular.

Now (our pretty much since then) anything goes and I love it

Natural evolution of protocols

No. It goes only because there are very few browser engines, who mostly can align their behaviour with each other.

Protocols with miltiple implementations are way more strict, because you can't feasibly test your quirky approach on every implementation, and the chance they will all be as forgiving is slim.

HTML parsing is well-specced these days.
The parsing is easy. And done in many, many libraries outside of the browsers. (And no, parsing with regex is still not possible, zalgo)

The problem is not parsing of HTML, its the DOM events, CSS application, javascript apis and above all the combination thereof which must be rendered all exactly the same, what makes it hard.

parsing was never so much the problem as what was rendered afterwards being different.
Still super bloated compared to the tiniest GIF:

47 49 46 38 39 61 01 00 01 00

00 ff 00 2c 00 00 00 00 01 00

01 00 00 02 00 3b

http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ev...

That’s bloated ;-)

   P1
   1 1
   1
is a 9 byte 1 × 1 pixel black image in portable bitmap format (https://en.wikipedia.org/wiki/Netpbm#File_formats). Consumers of such files likely will know how to scale them to 256 × 256 pixels. The trailing newline may not even be necessary. If so, it would become 8 bytes.

Gray 1 X 1 pixel images in binary portable graymap format have the same size. To get a non-gray RGB color, you’ll need two more bytes in binary portable pixmap format.

If we permit the fairly recent QOI format[0] we can produce a 1x1 transparent pixel in just 23 bytes (14 byte header, 1 byte for QOI_OP_INDEX, 8 byte end marker):

  71 6f 69 66 00 00 00 01 00 00 00 01 04 00 | 14 byte header
  00                                        | QOI_OP_INDEX 
  00 00 00 00 00 00 00 01                   | end marker
Similarly the 103 byte png in the article would be [EDIT] This is incorrect, see below

  71 6f 69 66 00 00 01 00 00 00 01 00 04 00 | 14 byte header
  fe b7 d0 d0                               | QOI_OP_RGB, RGB color, 
  fd fd fd fd c6                            | QOI_OP_RUN for 62+62+62+62+7
  00 00 00 00 00 00 00 01                   | end marker
[0]: https://qoiformat.org/qoi-specification.pdf

[EDIT] I realized that we actually run into one of QOI's drawbacks if we were to encode the 103 byte png in the article, as we actually need to repeat the pixel 65535 times, so we'd have floor(65535/62)=1057 QOI_OP_RUN bytes followed by another QOI_OP_RUN to repeat the last pixel. Here it's pretty clear that the QOI spec missed out on special handling of repeated QOI_OP_RUN operators, as long repetitions could have been handled in far fewer bytes.

So what are the tricks
The first trick is simply "cut the end of the file off". This saves the adler32 checksum on the end of the zlib stream, the crc32 on the end of the IDAT chunk, and the entire IEND chunk.

This works because modern browsers have support for progressively rendering images that are still being downloaded - as a result, truncation is also handled gracefully.

However, this alone results in rendering errors - the last few rows of pixels end up missing, like this:

https://cdn.discordapp.com/attachments/286612533757083648/96...

I don't know the precise reason for this, but I believe the parsing state machine ends up stalling too soon, so I threw some extra zeroes into the IDAT data to "flush" the state machine - but not enough to increase the file size.