<?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: Abdou</title>
    <description>The latest articles on DEV Community by Abdou (@bin_sys).</description>
    <link>https://dev.to/bin_sys</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4176834%2F3e0c672f-cd14-4e1f-814e-0cb67374796e.png</url>
      <title>DEV Community: Abdou</title>
      <link>https://dev.to/bin_sys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bin_sys"/>
    <language>en</language>
    <item>
      <title>Arabic PDFs are broken in most renderers. Here's how I fixed it.</title>
      <dc:creator>Abdou</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:57:15 +0000</pubDate>
      <link>https://dev.to/bin_sys/arabic-pdfs-are-broken-in-most-renderers-heres-how-i-fixed-it-3ape</link>
      <guid>https://dev.to/bin_sys/arabic-pdfs-are-broken-in-most-renderers-heres-how-i-fixed-it-3ape</guid>
      <description>&lt;p&gt;I needed to generate PDF invoices for Arabic-speaking clients from HTML templates. Sounds simple. It wasn't — most HTML-to-PDF tools mangle Arabic text in ways that are embarrassing to send to a paying client.&lt;/p&gt;

&lt;p&gt;This is the story of the three things that go wrong, and how I fixed each one in my own rendering setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: boxes instead of letters (□□□□)
&lt;/h2&gt;

&lt;p&gt;The classic. Your PDF shows empty boxes where Arabic text should be.&lt;/p&gt;

&lt;p&gt;This is almost never a bug in your HTML. It means the machine doing the rendering doesn't have an Arabic font installed. Your laptop has one, so it looks fine in your browser — but the server or Docker container doing the render has nothing, and the PDF renderer silently substitutes... nothing.&lt;/p&gt;

&lt;p&gt;The fix: install a proper Arabic font on the render machine. I use Noto Naskh Arabic (great for body text) and Noto Kufi Arabic (great for headings). On Debian:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;fonts-noto-core
fc-cache &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And verify what the renderer can actually see with &lt;code&gt;fc-list | grep -i arab&lt;/code&gt;. Don't rely on a CSS webfont alone — the PDF engine needs the font locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 2: disconnected letters
&lt;/h2&gt;

&lt;p&gt;Arabic letters change shape depending on their neighbors — that's the whole script. Some renderers don't do this "shaping" step, so you get letters standing apart like isolated blocks. It looks broken because it is broken.&lt;/p&gt;

&lt;p&gt;This is where your choice of engine matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;wkhtmltopdf&lt;/strong&gt;: uses a WebKit fork from ~2015. It does not shape Arabic correctly. I wouldn't start a new project on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WeasyPrint&lt;/strong&gt;: shapes correctly, good CSS support, no browser needed. Great if your pages don't need JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headless Chromium&lt;/strong&gt; (what I use): shapes correctly, full modern CSS/JS. Heavier, but it renders what the browser renders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your invoices need JavaScript to render, Chromium is the only serious option of the three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 3: the direction is wrong
&lt;/h2&gt;

&lt;p&gt;Even with the right font and shaping, some engines need explicit hints. Always set both on your HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ar"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"rtl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;dir="rtl"&lt;/code&gt;, mixed content (Arabic text with numbers, prices, Latin brand names) lays out in the wrong order, and you'll spend hours thinking it's a font bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;My setup: HTML invoice template → headless Chromium with Noto Arabic fonts installed in the worker → PDF out. Here's the actual invoice this produces:&lt;/p&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxn661isexns4caf4hy2t.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxn661isexns4caf4hy2t.png" alt="Arabic RTL invoice rendered to PDF" width="800" height="1131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Proper glyphs, correct right-to-left layout, connected letters, prices in دج rendering exactly where they should.&lt;/p&gt;

&lt;p&gt;I run this as a small API I built for my own freelance work (Snapframe) — POST some HTML, get a PDF back. There's a live demo where you can try it on your own page: &lt;a href="https://snapframe.mooo.com" rel="noopener noreferrer"&gt;https://snapframe.mooo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're fighting Arabic PDFs right now, check the three things in order: fonts on the render machine, an engine that shapes text, and &lt;code&gt;dir="rtl"&lt;/code&gt;. Nine times out of ten, it's one of those.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Abdelkader, a systems &amp;amp; security engineer from Algiers. I write about rendering, automation, and the unglamorous parts of running infrastructure.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
