Crop an ayah as an image

You want a picture of one verse for a share card, a slide or an email — somewhere you do not control the fonts. Quran PNG is a live service: one GET, no key, and the letterforms are the printed muṣḥaf’s, not a font’s.

Platforms
Anything that can make an HTTP GET
Time
About 7 minutes

One tool, one edition

Quran PNG is a tool, not one of the eight blocks. It is built on the artwork Quran SVG Elements publishes, and it is the shortest path from a reference to a picture of it. Reach for it when the destination cannot lay out Arabic: Canva, Figma, Keynote, a PDF generator, a social card.

It serves one edition: the KFGQPC Madani muṣḥaf in the riwayah of Ḥafṣ. There is no parameter to choose another, so every ayah number in a URL here is Kufan numbering. If you already render pages with Quran Engine and want a crop without a network, skip to the offline alternative.

  1. Make one request

    curl -o kursi.png \
      "https://png.quran.ws/api/v1/image/2/255.png?layout=fit&aspect=wide&width=1400"
    

    That is āyat al-Kursī, 1400 pixels wide, repacked into a 16:9 card, transparent background, as a PNG. The same URL is an <img> source — Access-Control-Allow-Origin: * is set.

    <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"
    />
    
  2. Build the path

    GET /api/v1/image/{surah}/{range}.{png|svg|pdf}
    

    surah is 1–114. range is one ayah (255), a closed range (255-257) or an open range to the end of the surah (1-). Ranges never cross a surah boundary, and a range past the end is rejected rather than clamped. The extension chooses the format; a format= query parameter is only read when there is no extension, so /2/255.png?format=webp returns a PNG.

    A query-string form exists for callers who would rather not build a path:

    GET /api/v1/image?surah=112&from=1&to=4&format=svg
    
  3. Choose the layout and the look

    Two layouts, because the artwork is only ever moved, never scaled. mushaf (the default) keeps every word at its printed x, so the aspect ratio is whatever the printed lines give. fit repacks the same artwork into justified lines filling an aspect you choose.

    ParameterValuesDefaultNotes
    layoutmushaf · fitmushaf
    aspectsquare post story wide banner, or w:hsquarefit only; 2.5:1 is accepted though /api/v1/options lists only the five names
    aligncenter · right · leftcenterfit only
    justify0 to switch offonfit only; gaps move, letters never stretch
    wordSpacing0.3 – 41multiplier on the printed gap; fit only
    lineSpacing0.6 – 31multiplier on the printed line height
    width64 – 80002000output pixels; PNG only — SVG and PDF are vector
    colorhex, # optional#231f20the ink
    backgroundhextransparentomit it and you get alpha
    padding0 – 40024artwork units, not pixels
    basmalah0 to omitononly affects a range starting at ayah 1
    vany valueunpinnedchanges caching only — see below

    A story card in this site’s colours, the whole of surah 112:

    curl -o ikhlas.png "https://png.quran.ws/api/v1/image/112/1-.png?layout=fit&aspect=story&color=15705D&background=F8F5ED&padding=48&width=1080"
    # 200 image/png · x-quran-lines: 4 · x-quran-words: 15
    

    The service draws the basmalah for a range starting at ayah 1, as the plate does, and knows the two exceptions: /9/1.png has none (surah 9 prints none — 9 words, 1 line), and in al-Fātiḥa it is ayah 1, so /1/1.png?basmalah=0 still returns those 4 words.

  4. Read the layout back before you commit

    Two headers tell you how the range laid out, so you can pick an aspect before you place the image:

    x-quran-lines: 5      ← 2:255 under layout=fit&aspect=wide
    x-quran-words: 50
    

    The same verse is 6 lines under the plate (layout=mushaf) and 4 lines at aspect=2.5:1. A HEAD request carries the headers without the bytes.

  5. Check the status before you write the file

    Every rejection is a 400 with content-type: application/json — not an image:

    curl -s "https://png.quran.ws/api/v1/image/2/300.png"
    # {"error":"surah 2 has 286 ayahs, got 300-300"}
    
    curl -s "https://png.quran.ws/api/v1/image/2/255.png?width=9000"
    # {"error":"width must be between 64 and 8000, got 9000"}
    

    In code, the guard is one line, and skipping it produces a .png file that is JSON inside and fails somewhere much later:

    const res = await fetch("https://png.quran.ws/api/v1/image/2/255.png?layout=fit&aspect=wide&width=1400");
    if (!res.ok) throw new Error((await res.json()).error);   // "surah 2 has 286 ayahs, got 300-300"
    
    const lines = Number(res.headers.get("x-quran-lines"));   // 5
    const blob = await res.blob();                            // image/png
    

    Over the per-IP rate limit you get 429 with {"error":"too many requests, slow down"}; the deployed limit is not readable from outside, so throttle a bulk export and treat a 429 as expected.

Pinning, and what v actually does

Without v, the response revalidates: the edge serves cache-control: public, max-age=14400, stale-while-revalidate=604800. With any v, it becomes public, max-age=31536000, immutable.

v pins the cache, not the renderer

The parameter is documented as pinning a renderer version, and /api/v1/options says “pass v=3 to pin this renderer”. The service treats v as present-or-absent: ?v=1 and ?v=9 both return today’s renderer, x-render-version: 3. So a URL you froze in a printed document keeps serving the old bytes from caches while a cold fetch after a renderer correction returns the new layout. Pin v when the image must not change under you, and understand you have taken responsibility for re-pinning when x-render-version moves.

Without a server: Quran Engine

If your app already renders pages with Quran Engine, a crop is an engine call and needs no network. Run against page 001 on this site:

page.cropSvg("1:1", { pad: 2 });
// '<svg xmlns="http://www.w3.org/2000/svg" viewBox="111.62 216.07 122.23 28.98" width="122.23" height="28.98">…'

The result is a standalone SVG in the page’s current colours — the same artwork, from the same decomposition, with no rate limit. It is the right choice inside a reader app; Quran PNG is the right choice when the caller is a design tool or a curl.

What this is not for

You wantUse
Warsh, Qālūn or any riwayah other than ḤafṣQuran SVG — five muṣḥafs, and you crop the polygon yourself
The words as text, to search or storeQuran Text
A tappable page in a browserQuran SVG Elements
A translation, a tafsīr, or a partial wordNot here — a range is drawn in full or refused
Try it live

Pick a surah, a range, a layout and an ink colour, and watch the URL and the live image change together.

How this works

The service holds no font. It loads the word and mark shapes that Quran SVG Elements publishes (the decomposition of the KFGQPC Madani plates, keyed surah:ayah:word), 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. GET /api/v1/surahs reports the edition: "hafs-kfgqpc", "KFGQPC Madani mushaf, V4 1441H", "render_version": 3.