<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[PassportPhotoBox Blog]]></title><description><![CDATA[PassportPhotoBox Blog]]></description><link>https://passportphotobox.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 26 Oct 2026 11:10:06 GMT</lastBuildDate><atom:link href="https://passportphotobox.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How I Built an In-Browser Passport Photo Studio with Next.js and MediaPipe]]></title><description><![CDATA[Building a privacy-first tool to format, check, and print biometric document photos directly on the client side.]]></description><link>https://passportphotobox.hashnode.dev/how-i-built-an-in-browser-passport-photo-studio-with-next-js-and-mediapipe</link><guid isPermaLink="true">https://passportphotobox.hashnode.dev/how-i-built-an-in-browser-passport-photo-studio-with-next-js-and-mediapipe</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[showcase]]></category><dc:creator><![CDATA[Rajendra Sahu]]></dc:creator><pubDate>Wed, 21 Oct 2026 11:32:31 GMT</pubDate><content:encoded><![CDATA[<p>Getting an official passport photo is still an inconvenient process. Most people either drive to a local pharmacy and spend 15 to 25 dollars for two physical prints, or try taking a selfie on their phone and risk rejection because the head size, eye level, background color, or paper dimensions were off by a few millimeters.</p>
<p>To solve this, I created PassportPhotoBox (<a href="https://passportphotobox.com">https://passportphotobox.com</a>), an online tool that helps users prepare, check, and export passport and visa photos directly from their browser.</p>
<p>Here is an overview of why I built it, how the architecture works, and the technical decisions behind it.</p>
<h2>The Problem with Existing Solutions</h2>
<p>Different governments enforce strict and varying biometric photo guidelines:</p>
<ul>
<li><p>United States and India: 2 by 2 inches (51 by 51 mm), with the head occupying 50 to 69 percent of total image height.</p>
</li>
<li><p>United Kingdom and Schengen Area: 35 by 45 mm, with the face height strictly measured between 32 and 36 mm.</p>
</li>
<li><p>Canada: 50 by 70 mm, with precise chin-to-crown proportions.</p>
</li>
</ul>
<p>Most existing online photo makers have major drawbacks. Some require recurring subscriptions for a one-time task. Others spam the screen with ads. Most critically, many tools upload raw selfies to remote servers for processing, which introduces serious privacy concerns for personal identity documents.</p>
<p>I designed PassportPhotoBox around three core principles:</p>
<ol>
<li><p>Support official standards for more than 100 countries.</p>
</li>
<li><p>Maintain strict user privacy by processing images directly in the browser.</p>
</li>
<li><p>Provide print-ready 300 DPI templates so users can print multiple photos at standard kiosks for pocket change.</p>
</li>
</ol>
<h2>The Technical Stack</h2>
<p>The platform is built with a modern, lightweight web stack:</p>
<ul>
<li><p>Framework: Next.js (App Router), React 19, and TypeScript</p>
</li>
<li><p>Styling: Tailwind CSS and Radix UI primitives</p>
</li>
<li><p>Computer Vision: MediaPipe Vision Tasks for client-side face landmark detection</p>
</li>
<li><p>Canvas Processing: Native HTML5 Canvas API</p>
</li>
<li><p>Document Generation: pdf-lib for exact 300 DPI print-ready layouts</p>
</li>
<li><p>Backend and Auth: Supabase (PostgreSQL, Auth, and Edge Functions)</p>
</li>
</ul>
<h2>System Pipeline and Workflow</h2>
<p>The photo preparation pipeline consists of four main stages:</p>
<h3>1. Client-Side Landmark Detection</h3>
<p>Instead of sending image files across the network, the browser loads a lightweight MediaPipe model. When an image is selected, the model detects essential facial landmarks on the local device, including the top of the head, eye line, nose bridge, and chin boundary.</p>
<h3>2. Geometric Dimension Matching</h3>
<p>Once the face geometry is calculated, the system evaluates the selected country preset. If a user needs a US passport, the canvas enforces a square 1:1 aspect ratio with head boundaries within the required percentage. If they select a Schengen visa, it shifts to a 35:45 ratio. Manual controls remain available for users who want to fine-tune cropping, rotation, or alignment.</p>
<h3>3. Background and Lighting Adjustment</h3>
<p>Official guidelines require neutral, uniform backgrounds. The app provides automated background removal tools alongside brightness, exposure, and contrast controls so users can meet official document standards.</p>
<h3>4. 300 DPI Multi-Photo Print Sheets</h3>
<p>Consular offices require physical prints with sharp resolution. Using pdf-lib and high-density canvas rendering, the application generates a standard 4R (4 by 6 inch) layout containing multiple copies at exactly 300 DPI. Users can download this file, upload it to any local pharmacy or print kiosk, and print multiple passport photos as a regular photograph for under 50 cents.</p>
<h2>Key Takeaways</h2>
<p>Processing files locally in the browser immediately reassures users who care about the privacy of their biometric photos. Balancing automated cropping with manual control sliders proved vital, since variations in camera angles and hair volume require human verification. Finally, translating physical millimeter dimensions into high-resolution digital print files required strict unit conversion and canvas scaling.</p>
<p>The project is live at <a href="https://passportphotobox.com">https://passportphotobox.com</a>. If you are working on client-side vision models or document generation in the browser, feel free to share your thoughts in the comments.</p>
]]></content:encoded></item></channel></rss>