# Changelog of Arabic Image OCR & Saudi Invoice QR Reader (`saif-tools/arabic-image-ocr`) Actor

- **URL**: https://apify.com/saif-tools/arabic-image-ocr/changelog.md
- **Full Actor documentation**: https://apify.com/saif-tools/arabic-image-ocr.md

## Changelog

### 0.2 revisions (unreleased, local build only), 23 Oct 2026

boi's answers of 23 Oct 2026 and hitler's review fixes.

- **Dense pages:** the small loss per dense page (about −$0.0008) is accepted for v1. The decision is recorded in PRICING.md.
- **Charging:** `chargedEvents` in each row is built only from events actually charged (`ChargeResult.charged_count`) by the new `save_row` helper. The extra `exact-qr-fields` event is charged first. The row is then pushed together with `plain-text-ocr`. If the cap is hit between the two, the row lists only the event that went through, and it is saved free if `plain-text-ocr` no longer fits.
  - New e2e cases `cap-between-qr-charged` and `cap-between-text-charged` cover this. They use the test-only env hook `TEST_RESERVE_MAIN_EVENT_ONLY=1`, which is never set on the platform; normal runs reserve both events up front.
- **Refactor:** preprocessing moved to the new shared `imageprep.py`, and the text-direction helpers moved to `textutil.py`. `ocr.py` now holds only Tesseract and the digit splice, and re-exports the moved names. `check_shared.py` lists the real shared files.
- **Sample fallback in the status message:** when the bundled sample stands in, the run's status message and `OUTPUT.note` say so, for example "Input image failed to download; returned built-in sample instead".
- **Cross-links** now point to `https://apify.com/saif-tools/arabic-receipt-reader`.
- `exact-qr-fields` ($0.01) is unchanged in this actor.
- **Pinned dependencies:** `requirements.txt` pins every direct dependency to the tested version.

### 0.2 (unreleased, local build only), 22 Oct 2026

boi's decisions of 22 Oct 2026 (11:39 PM), plus hitler's review notes.

- **Split.** Full-OCR / receipt mode moved to the new actor `arabic-receipt-reader`. This actor keeps:
  - `text`: Tesseract plain text;
  - `qr`: exact QR fields.
- **No EasyOCR or torch dependency.** The Docker image only adds the Tesseract binary. The local venv is 326 MB with no torch.
- **Memory: 1024 MB minimum and default** (max 4096).
- **Events:** `plain-text-ocr` ($0.003) and `exact-qr-fields` ($0.01). The SDK's `apify-default-dataset-item` event stays unpriced.
- **Every image is downscaled to at most 4 MP before OCR**, and OCR upscaling is capped at the same 4 MP. Each row has `imageSize` with:
  - `original`
  - `processed`
  - `downscaledBy`
  - `maxProcessedMegapixels`
    Boxes and QR points stay in original-image pixels.
- **Renamed field:** `exactQrFields.signatureVerified` is now `signatureChecked` (always `false`).
- **Bundled sample images** (`sample/`) are used when the input has no images, or when the Store example URL can't be downloaded (e.g. a 403 from Wikimedia):
  - `sample-arabic-text.png` in text mode;
  - `sample-zatca-qr.png` in qr mode.
    Sample rows carry `sample: true` plus `sampleReason`, and are free.
- **`imageUrls` is no longer required.**
- **`mode: "full"` now ends with a clear message** pointing to Arabic Receipt Reader. The Console and CLI already reject it through the input schema enum.
- **Removed inputs:** `confidenceThreshold` and `sumToleranceCents` (they belonged to receipt mode).
- **Shared modules are copied into both actors**, and `test/check_shared.py` checks the copies are identical:
  - `ocr`, `qr`, `zatca`, `digits`, `textutil`, `pipeline_common` and the digit model;
  - the tests `make_fixtures` and `test_qr`.

### 0.1 (unreleased, local build only)

- Three modes: `text` (Tesseract), `full` (EasyOCR with the digit classifier) and `qr`.
- Arabic-Indic and Persian digit second pass, RTL line order, QR masking, ZATCA TLV decoding, full-OCR receipt fields.
- Pay-per-event charging with a worst-case budget reservation and a clean stop at the spending limit.

### 2026-10-23

- Pinned every dependency to the exact versions tested locally so the first Apify build matches.
- Added constraints.txt (full pip freeze of the tested venv) so transitive dependencies are locked too; the Dockerfile installs with -c constraints.txt.
