Quran PNG
A URL in, an image out. Any range of ayat as a transparent PNG, an SVG or a print-ready PDF of the actual printed muṣḥaf — no font to install, no shaping engine, no key.
What this is
Quran PNG is a tool, not one of the eight building blocks. It is a service built on the artwork that Quran SVG Elements publishes, and it exists to be the shortest possible path from a reference to a picture of that reference.
Reach for it when the destination cannot lay out Arabic text for you: Canva, Figma, Illustrator, Keynote, a PDF generator, an email template, a social card. Nothing in the response is typeset. Every word is vector artwork lifted from the printed plate and moved onto a new canvas.
Get an image now
curl -o kursi.png \
"https://png.quran.ws/api/v1/image/2/255.png?layout=fit&aspect=wide&width=1400"
The same URL works as an <img> source. Access-Control-Allow-Origin: * is set, so a browser can fetch it directly.
<img
src="https://png.quran.ws/api/v1/image/2/255.png?layout=fit&aspect=wide&width=1400"
alt="Surah 2, ayah 255, from the printed Madani muṣḥaf"
/>
That is the whole API surface for the common case.
Try it livePick a surah, a range, a layout and an ink colour, and watch the URL and the live image change together.
Addressing an image
GET /api/v1/image/{surah}/{range}.{png|svg|pdf}
surah is 1–114. Anything outside that returns 400 with {"error":"surah must be 1..114"}.
range takes three forms:
| Form | Example | Meaning |
|---|---|---|
| A single ayah | /2/255.png | Ayah 255 only |
| A closed range | /2/255-257.svg | Ayat 255 to 257 |
| An open range | /112/1-.pdf | Ayah 1 to the end of the surah |
Ranges do not cross a surah boundary. A range beyond the end of the surah is rejected rather than clamped:
/2/300.png returns 400 with {"error":"surah 2 has 286 ayahs, got 300-300"}.
There is a second, equivalent form for callers who would rather not build a path:
GET /api/v1/image?surah=112&from=1&to=4&format=svg
The format is taken from the extension, or from format= when there is no extension. png, svg and pdf are the
only three; anything else returns 400.
Every image comes from the KFGQPC Madani muṣḥaf in the riwayah of Ḥafṣ — GET /api/v1/surahs reports
"edition": "hafs-kfgqpc" and "print": "KFGQPC Madani mushaf, V4 1441H". There is no parameter to select another
riwayah, so ayah numbers here are Kufan numbering throughout. If you need Warsh or Qālūn artwork, this is not the
service; see Quran SVG.
The two layouts
Because the shapes are only ever moved, never scaled or stretched, there are two ways to lay a range out. layout=mushaf is the default.
mushaf | fit | |
|---|---|---|
| What it does | Reproduces the plate: every word keeps the x it has on the printed page | Repacks the same artwork, at the same size, into justified lines |
| Aspect ratio | Determined by the printed lines | You choose it with aspect |
align, wordSpacing, justify | Ignored — the printed line has no alignment to choose | Apply |
| Use it when | You want fidelity to the page | You want the ayah to fill a card, a story or a banner |
Justification in fit moves the gaps only. The printed muṣḥaf stretches letters to justify a line, and doing that here
would distort the artwork, so a line that would need more than three times its natural word spacing is left ragged
instead.
aspect accepts the five named ratios or any explicit w:h:
| Name | Ratio |
|---|---|
square | 1:1 |
post | 4:5 |
story | 9:16 |
wide | 16:9 |
banner | 3:1 |
# a named ratio
curl -o story.png "https://png.quran.ws/api/v1/image/112/1-.png?layout=fit&aspect=story"
# an explicit one — anything matching w:h
curl -o odd.png "https://png.quran.ws/api/v1/image/112/1-.png?layout=fit&aspect=2.5:1"
Every parameter
Read from apps/api/params.mjs in the repository, which is the single place the service validates a query string.
| Parameter | Values | Default | Notes |
|---|---|---|---|
layout | mushaf · fit | mushaf | |
aspect | square · post · story · wide · banner · w:h | square | fit only |
align | center · right · left | center | fit only |
justify | 0 to switch off | on | fit only |
wordSpacing | 0.3 – 4 | 1 | Multiplier on the printed word gap; fit only |
lineSpacing | 0.6 – 3 | 1 | Multiplier on the printed line height |
width | 64 – 8000 | 2000 | Output pixel width; PNG only |
color | Any hex, # optional | #231f20 | The ink |
background | Any hex | transparent | Omit it and you get alpha |
padding | 0 – 400 | 24 | Margin in artwork units, not pixels |
basmalah | 0 to omit | on | Only relevant to a range starting at ayah 1 |
v | Any value | unpinned | Changes caching only — see below |
Out-of-range values are rejected, not clamped, and the message names the parameter:
curl "https://png.quran.ws/api/v1/image/2/255.png?width=9000"
# {"error":"width must be between 64 and 8000, got 9000"}
0, false, no and off all read as false for justify and basmalah. Any other value is true.
The basmalah switch
For this service the basmalah rule is concrete, because it only ever serves Ḥafṣ:
- A range starting at ayah 1 opens with the basmalah, as the plate does.
- In al-Fātiḥa the basmalah is ayah 1, so
/1/1.pngis the basmalah by itself. - At-Tawbah, surah 9, has none.
GET /api/v1/surahs/9reports"has_basmalah": false.
بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ
Pass basmalah=0 when you are composing a range into a design that already carries one.
Caching, and the v parameter
Renders are cached server-side and every response carries an ETag, so a conditional request costs you a 304.
curl -s -D - -o /dev/null "https://png.quran.ws/api/v1/image/2/255.png?v=3" | grep -i 'cache-control\|etag'
# cache-control: public, max-age=31536000, immutable
# etag: "hpOQJwwEfZQModXXT1FHhaLjcI4"
Without v, the response is cacheable but short-lived and revalidates, so a layout correction reaches you. With v,
it is immutable for a year. Pin it when the image is embedded in something that must not change under you — a
printed document, a published asset, a design file someone else owns.
The service treats v as present-or-absent. Any value flips the response to immutable; it does not select a
renderer version. ?v=3 and ?v=9 both return today's renderer — both respond with x-render-version: 3.
So if the renderer is corrected, a URL you froze for a year keeps serving the old bytes from caches while a fresh
fetch returns the new layout, and two readers see different images. Treat a pinned URL as a snapshot, and re-pin
when x-render-version changes.
Response headers worth reading
| Header | Example | What it tells you |
|---|---|---|
etag | "iJn_wTYVArS4E8TyvsS-5VUynsc" | Send it back as If-None-Match for a 304 |
x-render-version | 3 | The renderer that produced these bytes |
x-quran-lines | 5 | How many lines the range laid out to |
x-quran-words | 50 | How many words are in the image |
content-disposition | inline; filename="quran-2-255.png" | A sensible filename if the user saves it |
x-quran-lines and x-quran-words are useful before you commit to a layout: the same range is 5 lines under
layout=fit&aspect=wide and 6 lines under the plate, which is enough to change whether it fits your card.
Limits
- Rate limit. Requests are limited per IP; over the limit you get
429with{"error":"too many requests, slow down"}. The service's own default is 120 requests a minute, but it is set by an environment variable, so the deployed number is not something you can read from outside. Treat a429as expected, back off, and throttle a bulk export yourself. - Errors are JSON, not images. Every rejection is a
400with{"error": "..."}andcontent-type: application/json. Check the status before you write the body to a.pngfile — otherwise you get a file that is JSON with a PNG extension, and it will fail somewhere much later. widthis PNG only. SVG and PDF are vector; scale them at use.- No riwayah, no translation, no tafsīr. Only Ḥafṣ artwork.
Related blocks
| You want | Use |
|---|---|
| The Qur'an as characters, searchable, with word numbering | Quran Text |
| A complete printed page with a tappable ayah layer | Quran SVG |
| The word and mark shapes themselves, to compose your own renderer | Quran SVG Elements |
| The same pages rendered fast inside a mobile app | Quran Engine |
How this works
The service holds no font. It loads the word and mark shapes that Quran SVG Elements publishes — the same
decomposition of the KFGQPC Madani plates, keyed surah:ayah:word, 77,432 words for Ḥafṣ — and a render
collects the shapes in your range and translates them onto a new canvas; PNG is that SVG rasterised, PDF the same
vector, page-sized. It runs as a live HTTP service at png.quran.ws, and the same picker also runs as a Canva side
panel.