[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)