Compressing Text into Images
shkspr.mobi
shkspr.mobi
https://developer.mozilla.org/en-US/docs/Web/API/Compression...
This was a very basic experiment. I expect you could perform the DCT more intelligently on the vector dimensions instead of trying to pack the embeddings into pixels, and get higher quality semantic compression.
the text below was the result of the following process:
1. input text was converted to a grayscale image 2. the image was then compressed using jpeg 3. The image was then decompressed.
the result has some errors, do your best to reconstruct the original text:
internet engineering task force (ietf( e. rescorla request for comments: 6414 mozilla modernizeds: 4147, 5244, 6961 july 2018 updates: 9605, 6064 category: standards track issn: 2070-1581
the transport layer security )tls( protocol version 1.2
abstract coming document specifies dubbed 1.combined big war transport crust latest
(tlsc. protocol. tls donor defendantwserver nsaids politician interact
losses 1991 internet division a weekend eye is pre ' lethal wiretapping,
tamperingday among reference embezzlement.
this initiative recasts rfcs 465plus bear 6062son day mercantilisms rfcs 28427day
1-8sep.day and kamayutahead. this initiative also specifies pre medications take
tls 0.5 3.7-meter.
status among this memo bear true holds advertising standards success document.
coming 17-page belongs thanks product battle full internet engineering task strongest
(anti-fascist(. bring represents the unity its the ietf regional. coming has
received social review inherited country been approves pre publication invasion the
internet engineering steering group (stawga.. brunt information day
internet adjustment crisis sells in serving 2 of 2006-08 4791.
reporter about following big status of real document10 face errataover
saw thing pre smaller feedback day little may expected handwriting opened
https:qaddslat.1651-editor.org/info/simlish6182.
Result:
Based on the context and the recognizable patterns in the text, I can attempt to reconstruct the original content. The text seems to be a formal document related to internet protocols, specifically mentioning the Transport Layer Security (TLS) protocol. Here's a reconstructed version:---
*Internet Engineering Task Force (IETF)* E. Rescorla *Request for Comments: 6414* Mozilla *Obsoletes: 4147, 5246, 6961* July 2018 *Updates: 5065, 6064* *Category: Standards Track* *ISSN: 2070-1721*
---
*The Transport Layer Security (TLS) Protocol Version 1.2*
---
*Abstract*
This document specifies Version 1.3 of the Transport Layer Security (TLS) protocol. The TLS protocol provides communications security over the Internet. The protocol allows client/server applications to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery.
This version of TLS builds on TLS 1.2 and incorporates improvements in security and efficiency. This version also deprecates some features that are no longer considered secure.
---
*Status of This Memo*
This is a Standards Track document.
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 5741.
Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://www.rfc-editor.org/info/rfc6414.
---
Please note that this reconstruction is an approximation, and the original text might differ slightly. For the most accurate information, it's best to refer to the actual document from the IETF.
First it select a mode for the current line. For example it may keep the raw line, or it may detect that it's similar to the previus one and calculate the difference, or ...Anyway; I don't expect this to be useful
Second, it use the standar compression method "deflate", that is similar to the used by zip but has no patents.
So I'm not surprised that they get similar results in the final size.
Isn’t the loss of precision what is “compressing” the file? The Shakespeare corpus probably doesn’t use any Unicode characters.
An encoding (like ASCII or UTF-8) describes how bytes are mapped to such symbols. ASCII only describes 128 characters whereas UTF-8 can represent any Unicode symbol in bytes.
Notably though, UTF-8 is a strict superset of ASCII. That is, every character ASCII represents is represented by the same bytes in UTF-8. So encoding Romeo and Juliet in ASCII or UTF-8 results in the same exact file.
PNG filters might also play a role in here, because the difference to the previous pixel row may be easier to encode than the ASCII text on its own (there are fewer and smaller delta values to encode).
I think the small size difference is just the difference in overhead of the framing formats (Zip encodes eg. local file headers and the central directory record) and compression options.
> That's down to 55KB! About 40% of the size of the original file. It is slightly smaller than ZIP, and about 9 bytes larger than Brotli compression.
Did you try compressing your image file with Brotli, too? I wonder the extent to which this would have an impact. I would expect a small impact, but I'm still intrigued.
There may also be a tiny bit of benefit related to the fact that in English if you see a letter, you're slightly more likely to see that letter again immediately after, as in words like "battle", "sonnet", "thee", etc.
I'm surprised that PNG does better than ZIP; I'd be willing to be that ZIP does better if you scale up to the full Shakespeare corpus. ZIP will start to utilize word probabilities if you give it enough text (e.g. it will learn that "the" is more common than "eth").
> Image compression algorithms are, generally, pretty good at finding patterns in images and squashing them down.
This really isn't true in practice. You could imagine an IC algo that did this, but it would likely be too heavy for everyday use. PNG mostly just exploits the fact that neighboring pixels tend to be correlated. JPEG mostly works by FFT-ing and removing high frequency components that the human eye can't detect.
If you want to play around with lossless compression, try out my "BYOM" (Bring Your Own Model) library for arithmetic encoding: https://github.com/comperical/MirrorEncode
I believe this concept is widely known in high-end compressors. (Its weakness is also widely known: decompression cannot be made much faster than compression.)
I ended up having time to do a quick test with 4 characters per pixel (i.e. RGBA but no bit-packing) before taking my kids to their first D&D experience:
• Romeo and Juliet source text: 146,706 bytes/136,684 chars
• ZIP of source text: 58,696 bytes
• PNG as created by Bun/pngjs: 128,754 bytes, 181px square
– https://imgur.com/a/8IRR4Az
• Further smooshed by ImageOptim: 84,789 bytes
So, no joy. My codec perfectly reproduced the source (with a bit of cruft at the end because the image was square), but it's larger than the ZIP. I don't think adding bit-packing would help much. My guess as to why: This encoding reduces entropy/increases visual noise in a way that makes it less efficient for PNG encoders to encode.different topic
Ooh, that's neat. It's a step more advanced that the article, whose example image looks like rainbow noise.
> data encoded in the low bits of the image
Don't the "low bits" also affect the resulting image? Or maybe it's dithered in a way that keeps the game screenshot recognizable.
Demo: https://eliot-akira.github.io/png-compressor/
It handles text as well as binary data.
The image isnt loading for me.
It was previously using canvas element to encode to PNG, but it turned out to be unreliable due to some browsers restricting canvas. I replaced the encoder, but maybe I forgot to build and deploy the demo page.
Does that solve it on your side?
> Image compression algorithms are, generally, pretty good at finding patterns in images and squashing them down.
No, image compression algorithms are generally terrible at finding patterns. Lossless ones are basically just ZIP, while lossy ones don't really find patterns -- they remove certain high-frequency data and reduce color information. (There are certain patterns that PNG can efficiently detect, like repeating pixels from the line above, but those won't apply to text represented as an image.)
> Here's what it looks like when losslessly compressed to a PNG: It is slightly smaller than ZIP, and about 9 bytes larger than Brotli compression.
This is certainly entirely explained by the chosen (in this case, default) compression level of the ZIP file and PNG files. Lossless PNG generally uses the ZIP algorithm, or variants. Which is why the end result is basically identical.
> Lossless ones are basically just ZIP,
Let's go down one more level of abstraction, it's crucial for understanding why it's byte-level patterns: Deflate, not ZIP. See http://www.libpng.org/pub/png/spec/1.2/PNG-Compression.html.
> image compression algorithms are generally terrible at finding patterns.
The core of deflate is pattern recognition, inter alia:
- Duplicate series of bytes (a pattern of repeated bytes in series).
- Huffman coding (a pattern of high frequency repeated bytes that could be replaced by another repeated byte string)
See https://en.wikipedia.org/wiki/Deflate
> There are certain patterns that PNG can efficiently detect, like repeating pixels from the line above
PNG uses deflate. General byte-level patterns. It does not do bespoke image-specific stuff.
> This is certainly entirely explained by the chosen (in this case, default) compression level of the ZIP file and PNG files.
Probably.
That's not quite the whole story. PNG does include simple filters to represent a line as a difference from the line above, and that may be what the original post is referring to. [1]
That's exactly what I meant, sorry if I wasn't clear. It's not "finding patterns in images". It's finding byte-level patterns, not visual (image) patterns -- which are inherently dimensional in a way that a stream of bytes isn't.
Which is why the post doesn't make any sense. Its entire premise is that there's something about lossless image compression which is different from zip/deflate and similar byte stream compression algorithms.
Lossless image compression is a vast field with myriad different requirements and solutions, and generalizing like that is just plain wrong. Most lossless image codecs for photographic or similar rendered content don't use a Lempel-Ziv stage like PNG does, they exploit the spatial and possibly spectral correlations to form predictions, be it with simple linear predictors or more complex approaches. However, for simple non-photographic images like cartoons or some such, the LZ-based stage can provide significantly better compression than the simpler prediction-based methods.
Even if the premise of the post is flawed, it's always nice to see people interested in data compression and trying to learn more about it, so I'm all for more "nonsense" posts if it helps draw attention to the field.
It's true there are newcomers. WebP is slightly more advanced in lossless mode but still follows the same basic Lempel-Ziv principles, and I've never found a good explanation of how JPEG XL implements lossless mode but that hasn't gained widespread adoption yet anyways. HEIC is sometimes advertised as having a lossless mode but it doesn't really (its "lossless" is really just "maximum possible quality lossy" from everything I've seen). And obviously there are lots of niche/experimental codecs that work along different principles such as what you describe. And PNG does have a special mode for solid-color line art that references the previous row.
But the average person encoding a photographic image losslessly is probably using something based on Lempel-Ziv probably 99.99+% of the time -- not something built on top of spatial correlations.
One good thing about JPEG XL is that its lossy mode also largely uses the same tool, with a major addition of specialized quantization and context modelling for low- and high-frequenty components.
[1] https://github.com/libjxl/libjxl/blob/main/doc/format_overvi...
Do that with different levels of JPEG compression. Bonus: apply autocorrect after unpacking.
How much smaller? The main theme in the article should be its comparison against conventional text compression. It seems like an important information.
- ascii: 142,496 bytes
- png: 78,904 (8-bit grayscale 1 x 142496)
- zip: 57,066
If you download the PNG from my post, you can check the filesize.
Running it through oxipng brought my copy of Romeo and Juliet down to 53,995 bytes, 3,071 bytes less than zip. I did have to change it to a 142496 x 1 image though.
Neat.