[HN Gopher] Show HN: OnlyJPG - Client-Side PNG/HEIC/AVIF/PDF/etc...
___________________________________________________________________
Show HN: OnlyJPG - Client-Side PNG/HEIC/AVIF/PDF/etc to JPG
TL;DR: private, in-browser converter that turns pretty much any
image file format into standard JPEGs. Everything runs locally. No
uploads. This started as a five-minute job and forty hours
later... I wanted to convert a HEIC without uploading it anywhere,
so I wrestled Emscripten/WebAssembly to run Google's Jpegli inside
a Web Worker. Now there's a small UI and it handles a bunch of
formats. Just about the only thing it can't decode is JXL - but
there's still some JPEG XL magic in there: XYB perceptual color
quantization is enabled by default via Jpegli. The upside of all
this over-engineering is privacy and compatibility: images are
processed entirely on your machine and never touch a server; the
output is a regular JPEG that works everywhere. I could have used
a CLI, sure -- but where's the fun in that? Would love feedback on
edge cases and defaults. Tested on Firefox, Chrome, and Safari.
Cheers!
Author : johnnyApplePRNG
Score : 52 points
Date : 2025-10-17 11:29 UTC (11 hours ago)
(HTM) web link (onlyjpg.com)
(TXT) w3m dump (onlyjpg.com)
| mondainx wrote:
| Very cool site, I especially loved the write-up, bravo!
| johnnyApplePRNG wrote:
| Cheers, mondainx!
|
| After toiling away on this by my lonesome for the past few
| weekends, that means the world to me :)
|
| Seriously, thank you!
| citbl wrote:
| Nice, bookmarked.
|
| But if you're serious about reducing carbon waste, don't make
| visitors download 7.5MB to load the webpage.
| johnnyApplePRNG wrote:
| You are so right.
|
| I am serious about reducing carbon waste. I was amazed at how
| quickly that CO2e estimate jumps just by savings a few
| megabytes here and there.
|
| At the very least, it's got me (and hopefully others!) thinking
| about the issue and I'll be doing everything I can to reduce
| the load (and the load time!) in the near future!
|
| Thanks for the kick in the butt!
| vinnymac wrote:
| Great work
|
| Have you seen vert.sh? It does on-device conversion of audio,
| images, and documents and is open source too.
| ranger_danger wrote:
| Does not appear to be open-source, but was built from at least
| 90% open-source software.
|
| And if you happen to have wasm or web workers disabled, you get
| an unhelpful "Processing 0/0 files..." message that just hangs
| forever.
| kreetx wrote:
| There is also https://squoosh.app/.
| simonmales wrote:
| And it's a brilliant example of a PWA.
| kreetx wrote:
| IIRC, you can also use it via npx, i.e, in the terminal!
| johnnyApplePRNG wrote:
| Absolutely, I'm a huge fan of Squoosh! It's a phenomenal tool
| and a big inspiration for this project.
|
| The main difference is that OnlyJPG is laser-focused on one
| thing: creating the best possible, universally compatible JPG
| using Google's Jpegli encoder.
|
| Surprisingly, Squoosh doesn't use Jpegli yet.
| catapart wrote:
| I was unsatisfied with the discussion of transparency. You
| mention to "jump to png", but I just scrolled to the heading and
| it tells me why jpg is better, in some cases, than png, not how
| to satisfy turning a png with transparency into a competent jpeg
| analog.
|
| Of course, if you meant "use the png format" instead of "look at
| the header", that's likewise unhelpful.
|
| Not sure if there's actually a suggestion in here. I entered the
| site thinking "if you want a jpg, this is the app". Any question
| I had about other formats was moot because this is the app for
| jpgs. But then you discussed the other formats so it seemed like
| you had some workarounds or ways to use jpgs in place of the
| other formats, and that left me unsatisfied whereas your saying
| nothing probably wouldn't have? Again, not sure if there's
| anything actionable in there, just letting you know my experience
| with the site.
| johnnyApplePRNG wrote:
| You're totally right.
|
| My weak attempt at being humorous fell completely flat.
|
| I should have taken a page from the HN ethos and left sarcasm
| and kidding out of the copy completely.
|
| Working on it now!
| BrannonKing wrote:
| Note: please don't turn your screenshots and digital art into
| JPG. JPG uses compression based on natural lighting. It works
| well for photos, but it's the wrong solution where run-length
| encoding will do much better (e.g. in screenshots). Black text
| (or cartoon art) on white backround always looks lousy when
| converted to JPG.
| tinyspacewizard wrote:
| What should we use instead?
| LeFantome wrote:
| PNG
| _bent wrote:
| For final export? AVIF, JpegXL, maybe even WebP (lossless
| mode).
|
| PNG kinda sucks for high resolution stuff because decoding is
| extremely slow. The way PNG does lossless compression also
| only really works with flat graphic design, anything with
| gradients or texture blows up the file size.
| Panzerschrek wrote:
| How a user of such a web-site may be sure that it really deosn't
| upload photos somewhere, even it claims not to do so?
| craftkiller wrote:
| Load the page, disconnect from the internet, convert your
| image(s).
|
| Or just use ImageMagick like a normal person.
| ctxc wrote:
| Did you say normal person? It's more like
|
| *or just Google "convert to jpg" like a normal person, scroll
| through fRee cOnVerTeR results from companies that have
| nothing to do with image conversion (for SEO of course),
| click whichever is the least clowny name (with free and fast
| in the description), upload image, hit the convert button
| OOPS THAT WAS AN AD, go back, upload again, hit the right
| convert button, watch image appear in an animation framed by
| ads, click the download button (the one below the HIGH
| QUALITY button that's disabled with a lock.png begging for
| upgrades)
| johnnyApplePRNG wrote:
| Pick your poison:
|
| A) $magick *.png -quality 85 out.jpg
|
| B) drag, drop, save
|
| I built B for the days I forget A :P
| adzm wrote:
| Be careful, you may run into surprises with the XYB stuff in
| jpegli. Most should support it, since it uses an ICC color
| profile, but if the decoder does not handle it I'm not entirely
| sure what happens. I ran into a handful of strange issues a few
| years ago when testing this out, though it was all relatively old
| software.
| johnnyApplePRNG wrote:
| I ran into this exact issue during testing! I noticed that XYB-
| encoded images sometimes had a green or desaturated cast,
| especially on color-managed systems like macOS.
|
| The way jpegli handles this is pretty clever and is designed
| for maximum compatibility. When you enable XYB mode, it doesn't
| create a non-standard file. Instead, it:
|
| 1) Performs its perceptual magic in the XYB color space
| internally.
|
| 2) Encodes the resulting image data into the standard Y'CbCr
| channels that every JPEG decoder understands.
|
| 3) Attaches a custom ICC color profile to the file.
|
| This gives you the best of both worlds.
|
| On modern, color-managed software (like current browsers, macOS
| Preview, etc.), the decoder reads the ICC profile and uses it
| to transform the colors back to perfect sRGB. This is how I
| fixed the green tint I was seeing--by ensuring the correct ICC
| profile was always embedded.
|
| On old or non-color-managed software, the decoder simply
| ignores the ICC profile. Since the image data is already in
| standard Y'CbCr channels, it just displays it as if it were a
| regular legacy JPEG. The colors might be slightly off, but the
| image will still render correctly without crashing or showing
| major artifacts.
|
| It's a great advancement in color spaces and it's the main
| reason for creating this pet project, really... Jpegli and XYB
| seem to be relatively unknown, despite gargantuan coding
| efforts by the Google Zurich team.
|
| I'm just trying to shed some light on it, mostly!
| onecandreamzz wrote:
| Can't wait for them to come out with composite file types.
|
| Where I could make one HTTP request and get a json blob and the
| associated image at the same time.
|
| Then separate them on the client side and add them to the Dom.
| ranger_danger wrote:
| You can already do this?
| leumon wrote:
| Maybe this is just some niche use-case, but I tested it with a
| 268x98 png screenshot, and it made the image bigger and worse:
| https://files.catbox.moe/7so3z6.png
| LeFantome wrote:
| JPEG is for photos.
|
| For a white screen with black text, PNG is also compressed and
| less lossy.
|
| People should not be using PNG for images. If they are using
| PNG properly, converting to JPEG is a mistake.
| johnnyApplePRNG wrote:
| Fair point.
|
| Tiny, high-contrast UI screenshots are a worst-case for JPG--
| size can grow and edges get mushy.
|
| PNG is the right choice here.
| mdasen wrote:
| This is really cool, but I found one thing in testing it out: it
| seems to do really poorly with WebP images.
|
| I've run some WebP images from reddit through your site and they
| all end up looking terrible. If I run them through Squoosh.app
| (MozJPEG, 75%), I get the expected minimal degradation in quality
| and a 30%ish reduction in size. If I run the same image through
| your site (which seems hard-coded to Q90 for quality), I get a
| minimal reduction in size (if any; to be expected given Q90) and
| it looks incredibly pixelated.
|
| If I give it a jpeg, it works great: a large reduction in size
| and I can't even notice a difference (which is kinda what I
| expect for Q90).
|
| EDIT: If I toggle on the "legacy mode" YCbCr (instead of XYB),
| the WebP files work great. If I get the jpeg from reddit instead
| of the webp, XYB is fine.
|
| Try an image like
| https://www.reddit.com/r/PeterExplainsTheJoke/comments/1o8wo...
| (you can right click and download the image to get the webp or
| "download linked file" to get the jpeg). If I put the jpeg into
| your site with XYB, there's very slight degradation and a 67%
| savings. If I put the webp in, it looks like it was resized to
| half or a quarter of the size and then enlarged back up (and it
| gained 57%). With webp and YCbCr, it gained 63% over the webp,
| but the image quality is good.
|
| So there's something with the WebP images and XYB that seems like
| it isn't working.
|
| EDIT 2: I just grabbed an AVIF I have around to test and the XYB
| seems to have the same problem there as well.
| johnnyApplePRNG wrote:
| Can I ask which browser you're using?
|
| I was unable to reproduce the exact same issue you described
| here on Firefox 128 on Linux... however, you're definitely onto
| something!
|
| It's a combination of two subtle issues:
|
| 1) A known bug in the jpegli library. As you suspected, XYB
| mode combined with chroma subsampling (like the old 4:2:0
| default) can cause the exact "downscaled" look you saw. [0]
|
| 2) A sizing bug in my decoder pipeline. I was mistakenly using
| an image's internal codedWidth instead of its final
| displayWidth. For some WebP/AVIF files, this created a smaller
| image on a larger canvas, which magnified the XYB bug.
|
| I've just pushed a fix that addresses both issues. I've also
| updated the defaults to what I believe is a much better
| starting point: Quality 80, XYB, and 4:4:4 subsampling. This
| combination avoids the bug while still leveraging the best
| perceptual model, so it should prevent those surprising quality
| drops.
|
| Thanks again for the incredibly detailed report-it was super
| helpful!
|
| There's an unbelievable amount of edge cases with all of these
| different image formats. It's been a great learning experience
| for sure!
|
| [0] https://github.com/google/jpegli/issues/122
| leptons wrote:
| ffmpeg runs in the browser now, and it converts images as well as
| video.
| johnnyApplePRNG wrote:
| Thank you all so much for the feedback, the bug reports, the
| critiques, and the encouragement.
|
| This is a personal project, and the engagement here is both
| exciting and incredibly valuable.
|
| I've already pushed a fix for the WebP/AVIF quality issue based
| on the excellent report from mdasen--thank you!
|
| I wanted to address a few other major themes you all brought up:
|
| 1) "JPG isn't for everything" (especially screenshots/art):
|
| You are 100% right.
|
| The goal of OnlyJPG isn't to argue that JPG is the best format
| for every use case (it definitely isn't!).
|
| The philosophy is: "When you are in a situation where you need a
| JPG for compatibility, you should be able to make the best
| possible one."
|
| I've seen firsthand how often people need to convert screenshots
| or diagrams to JPG for a CMS, an email client, or a social media
| site that mangles PNGs. The new default of 4:4:4 subsampling
| actually helps a lot with text and sharp lines, but I'll be
| looking into adding a dedicated "Graphics" mode that's even
| better tuned for this.
|
| 2) UX & Copy (especially the transparency section):
|
| The feedback that the copy was confusing is also spot on (thanks
| catapart!). It's hard to see those things when you're close to
| the project. My goal was to explain why you might choose JPG over
| other formats, but it came across as a confusing sales pitch. I'm
| going to rewrite those sections to be clearer and more direct
| about what the app actually does (e.g., "How OnlyJPG handles
| transparency from a PNG").
|
| 3) Performance, Trust, and Open Source:
|
| I have issues with the large initial page load, the question of
| trust, and the fact that the project isn't open-source. You're
| right on all counts.
|
| Performance: The ~7.5MB load is too high. Optimizing the WASM
| bundles and vendor libraries is now at the top of my to-do list.
|
| Trust: The best way to verify the "100% in-browser" claim is, as
| craftkiller noted, to load the page and then disconnect your
| internet. If it still works, you know nothing is being uploaded.
|
| Open Source: This is the big one. To be transparent, I'm a
| 40-year-old self-taught developer, and this is one of my first
| real apps. I was never introduced to GitHub and haven't gotten
| into the rhythm of open-sourcing my work. But the passionate
| feedback here has convinced me it's the right next step. I commit
| to open-sourcing OnlyJPG on GitHub. Your expertise and
| willingness to help have shown me the immense value of building
| in public.
|
| This has been an incredible (and slightly overwhelming!) learning
| experience. Thanks again for taking the time to test, critique,
| and advise.
___________________________________________________________________
(page generated 2025-10-17 23:02 UTC)