Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Squoosh: Make images smaller using best-in-class codecs, right in the browser (squoosh.app)
241 points by Tomte on April 30, 2021 | hide | past | favorite | 68 comments


Squoosh is the thing that really made me "get" WASM - it helped me understand that WASM suddenly makes the best-in-breed libraries for pretty much everything available to me in the browser, provided they can be compiled to it.

And the WASM sandbox should be airtight, which means it's much safer to run C code in WASM than directly!

I'm mainly a Python developer, so an accompanying revelation was that projects like wasmer-python then give me the same opportunity in my default environment - call out to best-in-breed C/Rust/etc libraries without the risk and misery of needing to compile and package them as Python extensions. Instead, wait for the JavaScript WASM community to figure out how to use them and take advantage of their work from my Python projects as well.


What is the difference between WASM (new/good) and Java applets (old/bad)?


They try to do completely different things, it would be more meaningful to compare wasm with asm.js (let's try to improve a dynamic JITted language as a compilation target with simple semantics) and Java with Rust (let's try to make a language you could write anything in).

Java/JVM is a strong compilation target but it is mainly a language and an ecosystem, wasm is building an impressive ecosystem but it is mainly a compilation target designed to be easily embeddable anywhere.

Essentially the only things they have in common is the "run everywhere" slogan.

To actually answer your question with my opinions:

- wasm has a stronger sandbox and will (likely) never have any runtime reflection capability

- wasm is primarily meant to be easily embedded/interpreted

- wasm is extremely small

- it offers no new functionality that isn't already present in javascript (this will eventually become false)

- wasm lives within the sandbox of the browser

- it is standardized together with javascript inside the web platform, not as a separate entity


I'm not asking to compare Java with WASM. I'm asking to compare Java applets with WASM. They try to do one and the same thing. And the response I usually get, that the difference is that the applet sandbox leaked but the WASM sandbox is strong, makes absolutely no sense. Why would solving that problem involve tossing out applets only to replace them with a clone of the idea? How does that improve the sandbox? If the sandbox is the problem, why not work on that? How do you know how strong the WASM sandbox is, really?


The applet sandbox didn't merely leak; it was non-existent.

Java applets had built-in access to the complete filesystem, network, shared memory etc. A java applet could read cookies, credentials etc stored on disk and transmit them elsewhere - this was not "hacking", it was merely "write the code to do it".

By contrast, the WASM standard offers no access to anything - no IO of any kind. The only documented way to do IO is to have the hosting code (eg javascript) pass in a function pointer to perform IO on behalf of the WASM.

You could definitely go looking for a vulnerability in a particular WASM engine which let you escape the sandbox on that engine - and I have real concerns about JIT type-confusion vulnerabilities, and the GPU as an attack vector. However, "find a vulnerability to exploit" and "call an officially-documented method" are very different approaches to performing IO.


> Java applets had built-in access to the complete filesystem, network, shared memory etc.

This is definitely not true:

https://docs.oracle.com/javase/tutorial/deployment/applet/se...

It says you can only access the local filesystem from "privileged applets" that are explicitly allowed to run outside the sandbox.


> Why would solving that problem involve tossing out applets only to replace them with a clone of the idea?

Because neither Sun nor browser vendors had interest in doing the work needed to improve sandboxing in Java; browser vendors had no say on Java development and Sun care more about non-applet Java

> How does that improve the sandbox?

The same way rewriting a C program in a memory safe language will decrease null pointer exceptions. wasm is closer to brainfuck in terms of functionality than Java applet.

> If the sandbox is the problem, why not work on that?

historically because nobody wanted of could, technologically it is what happened

> How do you know how strong the WASM sandbox is, really?

This only time will tell, but there are many reasons to be optimistic: wasm offers no high level functionality for rich interaction with the host environtment, all comunications are via function calls with only statically sized numbers and a linear memory, features in wasm were filtered to allow static strict typecheching and performance penalities where accepted where necessary (all memory accesses are bound checked)

My point is that Java applet and wasm are very different. Java applet are like Flash, it is a whole SDK, a programming model, and a separate process that live in a browser plugin.

The main use case of a Java applet is to run a java/JVM application inside an iframe with the motst of the JVM functionality at its disposal (one such feature is runtime reflection so that JVM bytecode is almost impossible to sandbox).

Sandboxing the JVM is close in complexity as sandboxing C: it is going to be hard and ultimately the larger ecosystem will not care about the compromises needed for it to work.

On the other hand wasm mostly tries to just be faster to run. In 2013 Mozilla released asm.js as a subset of javascript that was easier to optimize (it is how it became possible to run demo of unreal engine in javascript). The novelty of this approach was that asm.js was just javascript.

wasm is a continuation of this approach, its sandbox is stronger than Java applet sandbox because wasm is incredibly smaller and it lives inside the same engine as javascript.

Google tried to other way, developing separate plugin languages reserved for browser extensions like NPAPI or PNaCl, I do not know a lot about them, but as far as I understand they mostly worked fine and did not have security issues.


My remembered experience of Java applets was that they loaded slowly, they required Java to be installed on the client computer (so they didn’t work out of the box for most people) and obviously they only run JVM code. Java applets also lived in an element on the webpage - which isn’t true of wasm. (But maybe there was also a way to run Java applets “headless”). I used to close websites if the Java applet loader appeared because otherwise I would be waiting for ages, and most of the time it wouldn’t work anyway because Java would be out of date or broken, or at best just slow and ugly.

In comparison, wasm apps have their own VM that is embedded into the browser. So there’s nothing extra for users to install (like the jvm). It’s small and lightweight, has (almost) no runtime SDK and it works on phones. I suppose you could write a compiler from C & Rust to Java byte code, ignoring most of the JVM’s features. But that big landscape of exposed features through the JVM still needs to be shipped somehow, and it’s a sandboxing nightmare that wasm just doesn’t have to contend with. Also let’s not forget that Google got sued over their use of Java by Oracle. I don’t want the web of the future to depend on any IP owned by oracle - that sounds like a disaster waiting to happen.


Java Applets were running 2 separate sandboxes (the browser and the JVM) while hoping neither had security problems natively or with the interconnect. WASM is just a new way to nail code to the existing browser engine and sandbox.


Part of it is that the design of WASM is informed by twenty years of additional experience as an industry.

It turns out we want something that is much smaller and much lighter than applets, and is developed as an open collaborative standard from the start.

We also want it built into browsers (so users don't have to install anything else).

Finally, it turns out we don't need it to be able to render directly its own area of the screen - a very non-obvious improvement over applets.


> which means it's much safer to run C code in WASM than directly

Anything is safer than to run C code directly ;)


I've been listening to the HTTP 203 podcast, which is presented by two people who worked on this project. The most recent episode has some great discussions about some of the newer image formats. Well worth a listen! https://http203.libsyn.com/


They also host HTTP 203 videos on specific topics on Youtube, which are also excellent. For example here is a video about the different Javascript APIs you could use to keep an app in sync across multiple tabs or devices:

https://www.youtube.com/watch?v=9UNwHmagedE


fwiw, we did a video on image compression a while back, but it wasn't part of the 203 series https://www.youtube.com/watch?v=F1kYBnY6mwg


Another talk that goes into the design of squoosh: https://www.youtube.com/watch?v=ipNW6lJHVEs


I want it to be smarter and choose quasi-optimal settings for me automatically. Dropping an almost entirely solid white PNG on it, the initial suggestion is to convert to JPEG which _increases_ the size rather than decreasing it!


The goal of Squoosh is more to teach out about all the options and levers codecs have. JPEG is not “suggested”, it’s just literally the first codec we ported to Wasm so that’s the auto-selected one :D

The Squoosh CLI has an auto-optimizer that will make an image as small as possible while staying under a given Butteraugli threshold, but you still have to decide on the format yourself.

https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli


If anything, it's getting harder to choose the 'right' format https://jakearchibald.com/2020/avif-has-landed/#why-not-loss...


That page is rather deceptive because the images it uses are 1920x1080, but they are displayed after downsampling them to be much smaller. This masks the substantial blurriness introduced by lower quality levels of AVIF. If you zoom into the full resolution versions you can see that the road surface actually has a lot of roughness, but the compressed version makes the road look smooth.


Those images are displayed at the correct size for high density devices. Real users don't zoom in and compare to the original.


The file sizes quoted should be for the resolution of image actually displayed. It would be fine to say a 960x540 image is X bytes with AVIF and Y bytes with JPEG and let viewers judge for themselves whether the two look equivalent. What that page actually does is quote the file sizes for 1920x1080 images, but shrink them to 960x540 before letting viewers compare the compression quality.


That's how you cater for high density devices.

If you take a 320x image and display it at 320x CSS pixels, it'll look blurry on the vast majority of mobile devices, and a lot of laptops, because 1 CSS pixel is larger than 1 device pixel.

https://developer.mozilla.org/en-US/docs/Web/API/Window/devi...

Fwiw this is covered in the article https://jakearchibald.com/2020/avif-has-landed/#what-is-acce...


Are you saying that people don't ever zoom in on images on the web? Because my wife does this regularly to look at details in photos.


I'm saying it's an edge case you shouldn't optimise for. Otherwise, if you're displaying an image at 640x480 CSS pixels, how wide should the image be in pixels? 2,000? 3,000? 10,000? Maybe each image should be 10MB just in case the user zooms in that far?

I think you should optimise for regular display size and density.



This is the best app for WASM. Integration of so many complex codecs and CPU-heavy optimizations used to be possible only in native apps.


It’s possible in javascript, but the best thing about wasm is that we don’t have to rewrite all this code in javascript, or suffer the performance penalties of doing so. If it already works in C, we can compile and ship that straight to the browser.


This is really cool and I appreciate the JpegXL support as well, even if it's not super well supported right now. I recently moved all of my photos from Dropbox to a local Nextcloud and I have a bunch of old photos that I don't want to delete, but don't need to be taking up gigabytes either. I can definitely get some good use out of this.


Apparently JXL will support lossless conversion from JPEG to JXL (it won't be as compressed as full JXL, but it will be better than standard JPEG).


I use this site as my go-to example whenever I talk about webassembly. Absolutely fantastic demonstration of new possibilities!


I am used to compression percentages being the percentage of the original file size, not some sort of inverse.


One of the Squoosh developers here: I agree, but it's an argument I lost. This sort of thing really divides people it seems.


You used the percentage of the original file in the CLI tool!

(jake, is that you?)


Yes, that is Jake. This is Surma.

You seem to be right. Gonna fix the CLI (the CLI is my doing)


Ohh does that mean we can have the argument again?


Yeah. You need to fix the CLI and add an emdedable API


An Emmerdale API?


Wahh wahhh waaah wawawawahhh.


I guess people don't recognise the Emmerdale theme tune..


It makes sense to say it's x% smaller. It's clear what the UI means anyway.


The difficulty is:

Do you express the resulting file size or the amount saved? “30%” could mean you “30% of the original file size” or “you shaved off 30% of the original file size”. You could denote the difference with a sign, like “-30%” but that still confuses people. We ran both options by a lot of our colleagues.

“x% of the original file size” is the least ambiguous, but who has the space to put that entire phrase in their app :-/


> You could denote the difference with a sign, like “-30%” but that still confuses people

How? This doesn't seem to be a problem whenever a shop runs a sale.

You could write "shrunk by/to x%". Or, to stay with the app's theme, "Squooshed by 30%!"


> This doesn't seem to be a problem whenever a shop runs a sale.

Maybe because they don't mind people misinterpreting the sale as larger? I've never seen 30% off mean "30% of the original price", so if people misinterpret it will always be too small.


my unhelpful take is that I like both


In general, percentages are confusing: depending on the context, "30%" can mean a ratio of 0.3, a ratio of 0.7, or a ratio of 1.3. Of course a large part of the general public doesn't understand that if you make something 10% bigger and then make it 10% smaller you don't get back to where you started, nor that travelling 10% faster won't cut your journey time by 10%, but I've also seen people with PhDs get confused by percentages when discussing compiler benchmark results.

If your main goal is to avoid misunderstanding (which it isn't always) then in my opinion it's best not to have anything to do with percentages. Instead, just give the ratio. It might not be elegant, and perhaps some people won't understand it at all, but "0.7x compression" cannot, I think, be misunderstood. (Or can it? I wait to be corrected!)


> "0.7x compression" cannot, I think, be misunderstood

FWIW I'm not sure what your intended meaning is here. I interpret it to mean that the file got bigger.


30% smaller than what?


The Squoosh folks are in here so I just want to say thank you it is a fantastic piece of software


<3


One of my browser tabs is always open to Squoosh, it's an awesome tool. If only I could hook Squoosh in during Hugo site builds...(looks like that might be possible with their CLI, hopefully some whip-smart kid with lots of free-time figures it out for me).


Seems like it would be fairly trivial to write a bash script that ran the hugo build, then optimized the images with the squoosh cli.

Squoosh is available in npm, which should make this pretty easy: https://www.npmjs.com/package/@squoosh/cli


happy squoosh user here. It's my go to image compressor for png/jpeg. I've tried many compressors but it performs well overall.

I hope google team also add support for GIF compression, currently I'm using https://gifcompressor.com

Also, it would be convenient if there's a native Windows client which gives the option to select and compress images using context menu itself.


The thing with GIF is that it’s rarely better than a paletted PNG.

As for animations, video formats with a very low fps are usually way better suited and smaller than GIFs.


Why isn't Google's involvement in this more clearly explained?


Hi! Squoosh team lead here :)

What kind of explanation would you like to see? We link to the repo and the Privacy explainer at the bottom of the page. Why is it important to you to know that it’s made by Googlers?


because rightly or wrongly, people are starting to distrust big tech companies.


It's open source. Please take a look for anything you might distrust.


What are they going to do, watermark all of your images with subliminal messages about never using Bing?


Working for a big tech company doesn't mean you represent them in everything you do in your off-hours.


That name is perfection. Kudos to whoever came up with it!


I wish there was something like this for video codecs!


I also love Squoosh. A fantastic peace of software


Is there a good way to run this on a S3 bucket?


Do you mean serve the app from an S3 bucket? It’s a fully static site without any server-side components, so go nuts.

If you mean compress all images in an S3 bucket? Not directly. But we do have a Squoosh CLI!

https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli


Thanks, I meant the second option: run on every image on a specific bucket.


Mount the bucket with something like rclone, then write a small script to optimize the images with the cli tool.


Great tip, thanks for sharing!


Check out https://optidash.ai if you need an API for this.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: