<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ubed Sheikh</title>
    <description>The latest articles on DEV Community by Ubed Sheikh (@ubed_sheikh_21).</description>
    <link>https://dev.to/ubed_sheikh_21</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3936210%2F1b606365-9358-42e2-a909-1ce46f1b1d53.png</url>
      <title>DEV Community: Ubed Sheikh</title>
      <link>https://dev.to/ubed_sheikh_21</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ubed_sheikh_21"/>
    <language>en</language>
    <item>
      <title>Why WebP to JPG Conversion Breaks on Most Tools — And How the HTML5 Canvas API Fixes It</title>
      <dc:creator>Ubed Sheikh</dc:creator>
      <pubDate>Thu, 04 Jun 2026 17:31:20 +0000</pubDate>
      <link>https://dev.to/ubed_sheikh_21/why-webp-to-jpg-conversion-breaks-on-most-tools-and-how-the-html5-canvas-api-fixes-it-i9h</link>
      <guid>https://dev.to/ubed_sheikh_21/why-webp-to-jpg-conversion-breaks-on-most-tools-and-how-the-html5-canvas-api-fixes-it-i9h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkid4s66ov93hc4oaebp.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkid4s66ov93hc4oaebp.webp" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've ever downloaded an image from WhatsApp, a website, or an Android screenshot and tried to upload it to a government portal or older app — only to get a "format not supported" error — you've hit the WebP problem.&lt;/p&gt;

&lt;p&gt;This post explains why it happens, what most tools get wrong, and how browser-based conversion using the HTML5 Canvas API actually solves it cleanly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why WebP Breaks on So Many Platforms
&lt;/h2&gt;

&lt;p&gt;WebP was developed by Google in 2010 and is now the default format for images on Chrome, Android, and most modern websites. It produces files 25–35% smaller than JPG at the same visual quality.&lt;/p&gt;

&lt;p&gt;The problem: a huge number of platforms still don't support it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indian government portals (Aadhaar, SSC, UPSC, 
Railway) — require JPG only&lt;/li&gt;
&lt;li&gt;WhatsApp Web downloads — saves as .webp by default&lt;/li&gt;
&lt;li&gt;Older Windows apps — don't open WebP natively&lt;/li&gt;
&lt;li&gt;Email attachments — many clients can't render WebP&lt;/li&gt;
&lt;li&gt;Job portals like Naukri — require JPG profile photo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you have a perfectly good image, in a modern format, that half the world can't use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Most Online Converters Get Wrong
&lt;/h2&gt;

&lt;p&gt;Most online image converters are server-side. You upload your file → it goes to their server → gets converted → you download the result.&lt;/p&gt;

&lt;p&gt;Three problems with this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Privacy risk.&lt;/strong&gt; Your Aadhaar photo, passport scan, or ID document just got uploaded to a random server you know nothing about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Quality loss from double compression.&lt;/strong&gt; &lt;br&gt;
Server-side tools often re-compress the image twice — once on upload, once on conversion. You lose quality you didn't need to lose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. They break on edge cases.&lt;/strong&gt; Animated WebP, &lt;br&gt;
WebP with transparency, or WebP files above a certain size often fail silently on server-side tools.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Browser-Based Approach: HTML5 Canvas API
&lt;/h2&gt;

&lt;p&gt;Modern browsers can handle image conversion entirely client-side using the Canvas API. No server needed.&lt;/p&gt;

&lt;p&gt;Here's the core of how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;convertImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetFormat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;naturalWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;naturalHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// For JPG output: fill transparent areas with white&lt;/span&gt;
      &lt;span class="c1"&gt;// (JPG doesn't support transparency)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetFormat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FFFFFF&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;targetFormat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key method is &lt;code&gt;canvas.toBlob()&lt;/code&gt;. It accepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; — the target MIME type (&lt;code&gt;image/jpeg&lt;/code&gt;, 
&lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;image/webp&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;quality&lt;/code&gt; — a value between 0 and 1 for lossy 
formats like JPG and WebP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser handles all the encoding natively. &lt;br&gt;
Your file never leaves the device.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Gotcha: Transparency in JPG Output
&lt;/h2&gt;

&lt;p&gt;One thing that catches a lot of developers: JPG doesn't support transparency.&lt;/p&gt;

&lt;p&gt;If you're converting a PNG or WebP with a transparent background to JPG, you need to explicitly fill the canvas with white (or whatever background colour you want) before drawing the image — otherwise you get black &lt;br&gt;
or corrupted areas.&lt;/p&gt;

&lt;p&gt;That's what this line does in the snippet above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetFormat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FFFFFF&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most broken converters skip this step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Use Case: India's Government Portals
&lt;/h2&gt;

&lt;p&gt;This is the gap I ran into personally. In India, almost every government portal — Aadhaar, SSC CGL, UPSC, Railway RRB, passport applications — &lt;br&gt;
requires photos in JPG format, typically under 50KB.&lt;/p&gt;

&lt;p&gt;But WhatsApp (used by ~500 million Indians) saves all images as WebP. Android screenshots are WebP. Most modern phone cameras offer WebP.&lt;/p&gt;

&lt;p&gt;So you have a generation of users with WebP files on their phones who can't upload them to the portals they need.&lt;/p&gt;

&lt;p&gt;I built this conversion logic into &lt;a href="https://easytoolkit.in/convert-images-to-any-format/" rel="noopener noreferrer"&gt;EasyToolkit's free image converter&lt;/a&gt; — it handles WebP → JPG, PNG → JPG, and 6 other format combinations, entirely in the browser, with batch support for up to 20 files.&lt;/p&gt;

&lt;p&gt;The India-specific angle (Aadhaar, SSC, UPSC portal requirements) is baked into the tool — it's genuinely the most common reason Indian &lt;br&gt;
users need format conversion.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned Building This
&lt;/h2&gt;

&lt;p&gt;A few things that weren't obvious before I built it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TIFF files are complicated.&lt;/strong&gt; The Canvas API doesn't natively decode TIFF. You need a library like UTIF.js for TIFF input support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GIF animation doesn't survive conversion.&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;canvas.toBlob()&lt;/code&gt; captures a single frame. If someone converts an animated GIF to WebP expecting animation, they get a still image. &lt;br&gt;
Worth flagging to users upfront.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality slider UX matters more than you'd think.&lt;/strong&gt; &lt;br&gt;
Users don't understand what "quality: 0.85" means. Showing the estimated output file size as they drag the slider is far more useful than a &lt;br&gt;
percentage value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile performance is fine for single images, gets slow for batch.&lt;/strong&gt; Converting 20 x 4MB images on a mid-range Android phone in sequence takes &lt;br&gt;
longer than expected. Queuing conversions with a small delay between each one prevents the UI from freezing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;WebP is everywhere, but supported by almost no legacy platforms&lt;/li&gt;
&lt;li&gt;Server-side conversion has real privacy and   quality tradeoffs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canvas.toBlob()&lt;/code&gt; is the clean client-side fix - Fill transparent backgrounds before JPG output or you'll get black areas&lt;/li&gt;
&lt;li&gt;For India specifically: WhatsApp → WebP → government portal rejection is a daily problem for millions of users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything that touches image uploads in India, handling WebP → JPG conversion client-side is worth adding.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built the image converter as part of &lt;a href="https://easytoolkit.in/" rel="noopener noreferrer"&gt;EasyToolkit&lt;/a&gt; — a free browser-based toolkit for PDF, image, &lt;br&gt;
and document utilities. All processing happens locally. Feedback welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I was manually comparing two versions of a contract for 2 hours before I built this tool</title>
      <dc:creator>Ubed Sheikh</dc:creator>
      <pubDate>Sun, 24 May 2026 09:16:23 +0000</pubDate>
      <link>https://dev.to/ubed_sheikh_21/i-was-manually-comparing-two-versions-of-a-contract-for-2-hours-before-i-built-this-tool-a4o</link>
      <guid>https://dev.to/ubed_sheikh_21/i-was-manually-comparing-two-versions-of-a-contract-for-2-hours-before-i-built-this-tool-a4o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4e40ayax32qmiu0fx28d.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4e40ayax32qmiu0fx28d.webp" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few months ago I was helping a friend review a revised freelance contract.&lt;/p&gt;

&lt;p&gt;The client had "made a few small changes" - their words.&lt;/p&gt;

&lt;p&gt;We had two PDF versions. No track changes. No diff. Just two documents that looked almost identical.&lt;/p&gt;

&lt;p&gt;So we did what anyone does in that situation: opened both side by side and started reading. Line by line. Paragraph by paragraph.&lt;/p&gt;

&lt;p&gt;Two hours later we found three changes. One of them was a payment clause that had been quietly reworded to cap late fees.&lt;/p&gt;

&lt;p&gt;That experience stuck with me. Not because it was dramatic — but because it was completely avoidable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools that exist weren't solving my actual problem
&lt;/h2&gt;

&lt;p&gt;I knew diff checkers existed. I'd used them before for code.&lt;/p&gt;

&lt;p&gt;But when I went looking for something that could handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long-form text documents (not just code)&lt;/li&gt;
&lt;li&gt;File uploads (not just paste)&lt;/li&gt;
&lt;li&gt;URL comparison (compare two web pages directly)&lt;/li&gt;
&lt;li&gt;Something that didn't upload my content to a server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I kept running into the same problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most tools are built for developers comparing code, not people comparing documents&lt;/li&gt;
&lt;li&gt;The ones that accepted files often uploaded them to external servers — not ideal for contracts or sensitive content&lt;/li&gt;
&lt;li&gt;URL comparison either didn't exist or was buried behind a signup wall&lt;/li&gt;
&lt;li&gt;The similarity score (how similar are these two texts, as a percentage?) was almost never shown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I focused on while building it
&lt;/h2&gt;

&lt;p&gt;Browser-only processing. Everything runs in JavaScript inside your browser. No file ever touches a server. For contracts, legal documents, HR content — this matters.&lt;/p&gt;

&lt;p&gt;Three comparison modes in one tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paste text directly (Content A vs Content B)&lt;/li&gt;
&lt;li&gt;Upload two files — TXT, CSV, JSON, HTML, MD, LOG&lt;/li&gt;
&lt;li&gt;Paste two URLs and compare the live page content directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Word-level diff, not just line-level. Most diff tools highlight entire changed lines. Word-level highlighting shows you exactly which word changed inside a sentence — much more useful for documents.&lt;/p&gt;

&lt;p&gt;Similarity score. A percentage that tells you at a glance how similar two texts are. Useful when you need a quick sanity check before diving into the details.&lt;/p&gt;

&lt;p&gt;Inline and side-by-side views. Some people prefer reading changes in flow. Others prefer the two-column comparison. Both are there.&lt;/p&gt;

&lt;h2&gt;
  
  
  One thing I didn't expect
&lt;/h2&gt;

&lt;p&gt;URL comparison sounds simple. Fetch two pages, strip the HTML, compare the text.&lt;/p&gt;

&lt;p&gt;It's not simple.&lt;/p&gt;

&lt;p&gt;Cross-origin requests get blocked by a lot of websites. Some pages load content dynamically via JavaScript, which means a basic fetch only gets the shell. Others serve different content based on location, device, or login state.&lt;/p&gt;

&lt;p&gt;I ended up building a best-effort URL comparison — it works well for most public pages, but I document the limitation clearly: if a site blocks cross-origin requests, text paste is the fallback.&lt;/p&gt;

&lt;p&gt;Honest tools tell you what they can't do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who actually uses this (from real feedback)
&lt;/h2&gt;

&lt;p&gt;I built it for my own problem, but the use cases that came back surprised me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writers comparing drafts before sending to editors&lt;/li&gt;
&lt;li&gt;HR teams checking policy document versions&lt;/li&gt;
&lt;li&gt;Developers comparing API response outputs during debugging&lt;/li&gt;
&lt;li&gt;Students checking if two sources are too similar before submission&lt;/li&gt;
&lt;li&gt;Anyone dealing with government or exam portals that return "updated" documents with no change log&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is very common in India specifically. Government portals update forms silently. You download a form, fill it out, then find out the portal has a newer version with different fields. A diff checker would have caught it in 10 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm still working on
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Better handling of tables inside documents (HTML table comparison is messy)&lt;/li&gt;
&lt;li&gt;Export diff as PDF or HTML report&lt;/li&gt;
&lt;li&gt;Bulk comparison across more than two files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've run into a specific comparison problem that existing tools don't handle well — I'd genuinely like to hear it in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this sounds useful: &lt;a href="https://easytoolkit.in/content-difference-checker/" rel="noopener noreferrer"&gt;Content Difference Checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No signup. No file upload. Works in your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the most frustrating "these two documents look the same but aren't" situation you've dealt with?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm asking because half of my feature ideas come from people describing problems I hadn't thought of. The contract story above came from a friend. The government form problem came from a comment on my last post. Curious what else is out there.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>tooling</category>
    </item>
    <item>
      <title>I built an image compressor that targets an exact KB size because upload portals kept rejecting my files</title>
      <dc:creator>Ubed Sheikh</dc:creator>
      <pubDate>Sun, 17 May 2026 12:26:53 +0000</pubDate>
      <link>https://dev.to/ubed_sheikh_21/i-built-an-image-compressor-that-targets-an-exact-kb-size-because-upload-portals-kept-rejecting-my-fa4</link>
      <guid>https://dev.to/ubed_sheikh_21/i-built-an-image-compressor-that-targets-an-exact-kb-size-because-upload-portals-kept-rejecting-my-fa4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n4zak7w1yb7r8b303na.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n4zak7w1yb7r8b303na.png" alt=" " width="513" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few months ago I kept running into the same frustrating problem:&lt;/p&gt;

&lt;p&gt;Upload portals rejecting my images because the file size was just slightly over the limit.&lt;/p&gt;

&lt;p&gt;Especially on: It was frustrating re-compressing the same image over and over just to reduce a few extra KB.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Government forms&lt;/li&gt;
&lt;li&gt;Exam portals&lt;/li&gt;
&lt;li&gt;Visa applications&lt;/li&gt;
&lt;li&gt;Job applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most image compressors either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced quality too aggressively&lt;/li&gt;
&lt;li&gt;Failed to hit the required KB size&lt;/li&gt;
&lt;li&gt;Uploaded files to external servers&lt;/li&gt;
&lt;li&gt;Or required too many manual adjustments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I ended up building a browser-based image compression tool focused on one specific thing:&lt;/p&gt;

&lt;p&gt;Compressing images to an exact KB target while keeping the quality as usable as possible.&lt;/p&gt;

&lt;p&gt;A few things I focused on while building it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser-based processing&lt;/li&gt;
&lt;li&gt;No signup&lt;/li&gt;
&lt;li&gt;Adjustable KB targeting&lt;/li&gt;
&lt;li&gt;Support for JPG, PNG, and WebP&lt;/li&gt;
&lt;li&gt;Keeping the workflow simple&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing I didn’t expect during development was how difficult ultra-low KB targets become.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compressing a 2MB image to 500KB is easy&lt;/li&gt;
&lt;li&gt;Compressing that same image to 20KB without destroying it is much harder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also realized metadata removal can make a surprisingly big difference for photos taken on modern phones.&lt;/p&gt;

&lt;p&gt;The project is still improving, but it has already become one of the tools I personally use most often.&lt;/p&gt;

&lt;p&gt;I’m still improving it, but it has already become genuinely useful for handling strict upload limits:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://easytoolkit.in/compress-image-to-kb/" rel="noopener noreferrer"&gt;https://easytoolkit.in/compress-image-to-kb/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
