# OCR Japanese, Chinese, Korean & English — Images & Scanned PDFs (`masahishop/ocr-cjk`) Actor

Extract text from images and scanned PDFs in Japanese, Chinese (Simplified/Traditional), Korean and English. No stray spaces between CJK characters, vertical Japanese support, embedded PDF text used when available. Pay per page.

- **URL**: https://apify.com/masahishop/ocr-cjk.md
- **Developed by:** [Masahi Shop](https://apify.com/masahishop) (community)
- **Categories:** AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.80 / 1,000 page ocrs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## OCR Japanese, Chinese, Korean & English — Images & Scanned PDFs

Extract text from **photos, screenshots and scanned PDFs** in **Japanese, Chinese (Simplified / Traditional), Korean and English** — with output that is ready for search, translation or an LLM.

- **No stray spaces between CJK characters** (a common problem with OCR engines): `東 京 都` → `東京都`
- **Vertical Japanese** (縦書き) supported
- **Smart PDF handling**: pages that already contain text use the embedded text (exact and cheap); only scanned pages are OCR'd
- **Noise filtering**: photo edges, shadows and stamps that OCR engines misread as garbage are dropped
- **Frames and table lines removed before OCR**: characters next to borders, boxes or big brackets are not lost (`令和` stays `令和`, not `和`)
- **Pay per page** — failed downloads and unsupported files are never charged

### What can it be used for?

- Digitize **Japanese / Chinese / Korean documents**: invoices, receipts, notices, contracts, forms
- Make **scanned PDFs searchable** or feed them to an LLM / RAG pipeline
- Extract text from **screenshots and product photos** for translation
- Process **vertical Japanese text** from books, newspapers and signs
- Call it from **AI agents** via the Apify API or MCP

### Accuracy (our own measurements)

Character error rate (CER, lower is better), measured on our test set — printed text, 300 DPI:

| Test | CER |
|---|---|
| Japanese government document (4 pages incl. a framed date box, rendered at 300 DPI, compared with the original text) | 1.8% |
| English research paper page (two columns) | 0.3% |
| English paper title page (author grid, margin stamp) | 0.6% |
| Simplified Chinese sample | 0.0% |
| Traditional Chinese sample | 2.8% |
| Korean sample | 0.0% |
| Japanese "phone photo" sample (blurred, rotated, JPEG) | 2.8% |
| Vertical Japanese sample | 0.0% |

CER counts misread characters; text that is correct but in a different reading order (for example an author grid read row by row) is not counted as an error. Multi-column grids such as author lists are read row by row. Results depend on image quality. Handwriting is not supported.

### Input

| Field | Description |
|---|---|
| `fileUrls` | Direct links to images (JPEG, PNG, WebP, TIFF, GIF, BMP, AVIF) or PDFs. Only these URLs are downloaded. |
| `languages` | Any of `jpn`, `chi_sim`, `chi_tra`, `kor`, `eng` (default: `jpn` + `eng`). Choose only what you need. |
| `verticalText` | Turn on for vertical Japanese |
| `pdfTextLayer` | `auto` (default): use embedded text when present, OCR only scanned pages. `ocr`: OCR every page. |
| `pageRange` | PDF pages, e.g. `1-5, 8` |
| `dpi` | Render resolution for scanned PDF pages (default 300) |
| `includeLines` | Also return each line with confidence and bounding box |
| `password` | Password for encrypted PDFs |
| `maxPagesPerFile`, `maxFileSizeMb`, `downloadTimeoutSecs`, `maxConcurrency` | Limits |

```json
{
    "fileUrls": ["https://example.com/scan.pdf", "https://example.com/receipt.jpg"],
    "languages": ["jpn", "eng"]
}
```

### Output

One dataset item per file:

```json
{
    "url": "https://.../sample_notice_ja.jpg",
    "kind": "image",
    "status": "success",
    "languages": ["jpn", "eng"],
    "processedPages": 1,
    "ocrPages": 1,
    "textLayerPages": 0,
    "avgConfidence": 90.8,
    "charCount": 142,
    "text": "お知らせ\n来週の月曜日から、事務所の受付時間を変更します。\n\n新しい受付時間は、午前9時から午後5時30分までです。\n\nご不明な点は、総務部までお問い合わせください。\nNotice: Office hours change from next Monday (9:00-17:30).",
    "pages": [
        { "pageNumber": 1, "method": "ocr", "text": "...", "confidence": 90.8, "droppedNoiseLines": 1 }
    ],
    "warnings": []
}
```

`status` is `success`, `no_text`, `partial` (an error after some pages; those pages are included) or `failed` (with `error`). With `includeLines`, each page also has `lines: [{ text, confidence, bbox: { x0, y0, x1, y1 } }]`.

### Pricing

Pay per event — no subscription, platform usage included:

| Event | Price |
|---|---|
| Page OCR (per image or scanned PDF page) | $0.008 |
| Text-layer page (PDF page that already contains text — no OCR needed) | $0.0003 |
| Actor start (per run, Apify standard) | $0.00005 per GB of memory |

Failed downloads and unsupported files are not charged. You can cap the cost of a run with the maximum charge setting in Apify.

### Tips

- Select only the languages in your documents — e.g. `jpn` alone for pure Japanese text.
- For small text in scanned PDFs keep `dpi` at 300.
- Low `avgConfidence` (below ~60) usually means a wrong language setting or a blurry image.

### Limitations

- Handwriting is not supported.
- Tables are returned as text lines, not as structured tables.
- For PDFs that already contain text and need clean Markdown (headings, two-column papers, RAG chunks), see [PDF to Markdown for LLM & RAG](https://apify.com/masahishop/pdf-to-markdown).
- Mixed horizontal and vertical text on the same page: choose the dominant direction with `verticalText`.

### Privacy

Only the URLs you provide are downloaded. Files are processed in memory and the results are written only to your own run's dataset. Please make sure you have the right to process the documents you submit.

# Actor input Schema

## `fileUrls` (type: `array`):

Direct links to images (JPEG, PNG, WebP, TIFF, GIF, BMP, AVIF) or PDF files. Only the URLs you list are downloaded.

## `languages` (type: `array`):

Languages in the documents. Choose only what you need — fewer languages are faster and more accurate.

## `verticalText` (type: `boolean`):

Turn on for vertically written Japanese (novels, newspapers, signs). Columns are read right-to-left.

## `pdfTextLayer` (type: `string`):

<b>auto</b>: use the embedded text when a page has it (fast, cheap, exact) and OCR only scanned pages. <b>ocr</b>: OCR every page.

## `pageRange` (type: `string`):

PDF pages to process, e.g. <code>1-5, 8</code>. Empty = all pages.

## `dpi` (type: `integer`):

Resolution used to render scanned PDF pages. 300 is best for small CJK characters; 200 is faster.

## `password` (type: `string`):

Password for encrypted PDFs.

## `includeLines` (type: `boolean`):

Also return each text line with its confidence and position (x0, y0, x1, y1).

## `maxPagesPerFile` (type: `integer`):

Safety limit on pages processed per PDF.

## `maxFileSizeMb` (type: `integer`):

Larger files are skipped (and not charged).

## `downloadTimeoutSecs` (type: `integer`):

Timeout for downloading one file.

## `maxConcurrency` (type: `integer`):

Files processed at the same time. Each needs about 1 GB of memory.

## Actor input object example

```json
{
  "fileUrls": [
    "https://api.apify.com/v2/key-value-stores/SO2i30oKmzy8a1PgH/records/sample_notice_ja.jpg?signature=1z0Af2EnUr8IILOwBMSRj"
  ],
  "languages": [
    "jpn",
    "eng"
  ],
  "verticalText": false,
  "pdfTextLayer": "auto",
  "dpi": 300,
  "includeLines": false,
  "maxPagesPerFile": 100,
  "maxFileSizeMb": 50,
  "downloadTimeoutSecs": 60,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (type: `string`):

Recognized text, per-page results and metadata for each file.

## `overview` (type: `string`):

Status, pages, confidence and warnings for each file.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "fileUrls": [
        "https://api.apify.com/v2/key-value-stores/SO2i30oKmzy8a1PgH/records/sample_notice_ja.jpg?signature=1z0Af2EnUr8IILOwBMSRj"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("masahishop/ocr-cjk").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "fileUrls": ["https://api.apify.com/v2/key-value-stores/SO2i30oKmzy8a1PgH/records/sample_notice_ja.jpg?signature=1z0Af2EnUr8IILOwBMSRj"] }

# Run the Actor and wait for it to finish
run = client.actor("masahishop/ocr-cjk").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "fileUrls": [
    "https://api.apify.com/v2/key-value-stores/SO2i30oKmzy8a1PgH/records/sample_notice_ja.jpg?signature=1z0Af2EnUr8IILOwBMSRj"
  ]
}' |
apify call masahishop/ocr-cjk --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,masahishop/ocr-cjk"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/C5sOHBftU8bk4u435/builds/eFWEYAmIr01ijjzk8/openapi.json
