From APK Teardown to A7 Booklet
Most “compact Quran” PDFs online are screenshots of screenshots - soft edges, compression artifacts, uneven margins. I wanted the actual source calligraphy, so I went straight to where a Quran app stores its rendering data, pulled it out, and built a layout and print pipeline around it: a pocket-sized A7 booklet that prints double-sided on ordinary A4 paper. This walks through the pipeline, including the wrong turns.
Getting the Source Assets
My assumption going in was that the app rendered verses as text with a custom Arabic font - pull the font, pull the layout rules, re-render. That didn’t survive contact with the file system. Every line of the Mushaf turned out to be stored as an individual SVG file, one per line:
mv QuranApp.xapk QuranApp.zip
unzip QuranApp.zip -d QuranApp_bundle
An XAPK is just a ZIP bundling the base APK with config APKs and asset packs. The 474 MB asset_pack_0.apk was the obvious target - base APKs are usually a few MB of code; anything in the hundreds of MB is media. APKs are ZIPs too, so:
mkdir asset_pack_0
unzip asset_pack_0.apk -d asset_pack_0
find asset_pack_0 -type f | head
asset_pack_0/assets/lines/a03966.svg
asset_pack_0/assets/lines/a08833.svg
One SVG per Qur’anic line, not per page. That’s a real advantage over text rendering or screenshots: infinite scaling with no upsampling artifacts, no JPEG degradation, and the original mushaf’s exact word-spacing and line breaks survive untouched - which matters since Quranic line breaks are traditionally fixed.
Before writing any layout logic, I built the simplest possible viewer to sanity-check ordering:
<img class="line" src="asset_pack_0/assets/lines/a03966.svg">
Then split the full line list into fixed-size page chunks:
grep '<img class="line"' mushaf.html > lines_only.txt
split -l 22 -a 4 lines_only.txt page_
Worth knowing: split’s default suffix length is 2 characters, capping you at 676 files. With thousands of lines, that ceiling gets hit and split just fails - -a 4 widens it and avoids the problem entirely.
Two Targets, One Source
With clean SVG lines in hand, I split the project into two tracks: a Kindle version at 6 lines per page, and a print version at 4 lines per page - because the print target wasn’t a full page at all, it was A7 (74mm × 105mm, postcard-sized), where 4 lines was the ceiling before the script got too small to read.
The A7 Booklet Problem
Nobody’s home printer prints A7 - it prints A4. So the real task was: tile many A7 pages onto one A4 sheet, print both sides, and end up with something that cuts and folds into a mini book in the correct reading order. This is an imposition problem, the same category print shops solve for saddle-stitch binding.
Getting there took a few wrong turns:
- Wrong grid: first attempt tiled 4 images in a 2×2 grid on landscape A4. The actual target, confirmed against a reference photo, was 8 cells - a 2×4 grid.
- Wrong axis: with the grid corrected, the sheet itself needed to be landscape (4 columns × 2 rows), with each portrait A7 page rotated 90° to sit in a landscape cell. Cell content is portrait; cell arrangement is landscape - easy to mix up, and getting the rotation direction wrong puts the text upside down relative to the fold.
The hardest part was double-sided pairing: each page’s reverse side needs to show the next page, like a real book. The naive approach - pages 1-8 on the front, 9-16 on the back, same grid order - fails because flipping a sheet horizontally mirrors its columns. The top-left cell on the front doesn’t end up behind the top-left cell on the back; it ends up behind whatever’s in the top-right, since that’s what lands over it after the flip.
The layout that actually works: one continuous PDF where page 1 holds the odd-numbered mini-pages in forward order, and page 2 holds the even-numbered mini-pages in fully reversed order:
| PDF Page 1 (odd) | PDF Page 2 (even, reversed) |
|---|---|
| 1 | 8 |
| 3 | 6 |
| 5 | 4 |
| 7 | 2 |
| 9 | 16 |
| 11 | 14 |
| 13 | 12 |
| 15 | 10 |
Printed double-sided with “flip on long edge,” page 1 lands exactly over page 2, page 3 over page 4, and so on - the printer’s duplex mechanism handles the physical flip, and the reversed order on the even page compensates for it in software.
One more subtlety: rotation direction. Clockwise and counter-clockwise both technically rotate 90°, but only one produces correctly-oriented Arabic once the booklet is assembled. This was resolved empirically - print a test sheet, hold it the way it’ll actually be read, and rotate until it’s right.
Margins: a late visual issue was uneven whitespace around the images in their cells. Shifting the image in the cell fixes it cosmetically; cropping the source image asymmetrically actually removes the excess pixels. Cropping was the correct fix, but the crop amount had to be scaled from the preview resolution to the true print resolution - a margin measured on a downscaled preview doesn’t transfer 1:1 to the source file.
Two output variants came out of this: a guided-cut version (preserves aspect ratio, adds cutting-guide grid lines, configurable margins) for precision, and an edge-to-edge version (stretches each page to fill its cell, no margins or gridlines) for maximum use of the page. Neither is strictly better - different trade-offs, kept as separate outputs rather than one parameterized script.
Takeaways
- Inspect before you build - one
findcommand overturned the entire starting assumption. - Common “special” container formats (XAPK, APK) are usually just ZIP in disguise.
- Imposition bugs are invisible in code review and only show up on paper - a physical test print catches what reading the code can’t.
- State the physical end-state (“what’s behind what after cutting”) explicitly before coding it; the pairing logic only clicked once framed that way.
- Small utility defaults (like
split’s suffix length) are tuned for the common case, not yours, and only bite at scale.