> Source: https://txtfetch.com/tools/image-ocr-check > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # Will this image OCR cleanly? Drop it below and find out, before you burn a request finding out the hard way. This tool measures resolution, focus, skew, and inversion from the actual pixels. It runs entirely in your browser. Nothing is uploaded. Drop an image below to check it. It runs in your browser, and nothing is uploaded. ## what-this-check-looks-at This never runs OCR. It never bundles an OCR engine, a vision model, or any kind of AI. It works by byte parsing plus textbook image analysis. Four checks make up that analysis. An Otsu threshold separates ink from background. A projection-profile search measures skew. A Laplacian-variance check measures focus. An 8-pixel grid check spots JPEG compression damage. Every one of those checks is deterministic. Every number the report shows is labelled a **heuristic** where it is one. That means a prediction of whether OCR is likely to succeed, not a guarantee. One detail decides whether the answer is any good. This tool measures contrast, ink coverage, focus, and compression damage on your image's **full-resolution pixels**, never on a shrunken copy. Only the line-finding step, which measures skew and text-line height, works on a reduced copy. That step reduces a map of where the ink is, not an average of the greys. A thin ink stroke stays visible instead of blending into the paper around it. That distinction matters more than it sounds. Averaging a 300 dpi page down to 700 pixels turns hairline strokes into mid-greys. Any tool that measures contrast on _that_ will confidently tell you a perfectly good scan contains no text at all. The report names the reduced size it used for line geometry so you can see exactly which numbers came from where. It's also honest about what it can't do: [TIFF isn't decodable by any mainstream browser's canvas](https://txtfetch.com/formats). HEIC/AVIF only decode in Safari. So those formats, elsewhere, get a metadata-only report instead of a pixel-based verdict. That's still useful. TIFF's own metadata carries page count, fax compression, and whether the image is stored inverted. But it stops short of a confident pixel-level answer. ## dpi-is-the-wrong-number Tesseract's own documentation is specific about resolution: it [says plainly](https://tesseract-ocr.github.io/tessdoc/ImproveQuality.html) that it "works best on images which have a DPI of at least 300 dpi." That's real, citable guidance. But DPI is a number stored in a file's metadata, not a measurement of the pixels themselves. The two frequently disagree. A phone photo commonly declares 72 dpi, a leftover screen-resolution default from decades of cameras. But it often has plenty of real detail, once you account for how close the lens was to the page. An upscaled low-quality fax, resaved through an image editor, can just as easily declare "300 dpi." But the actual text can be a handful of blurry pixels tall. Resizing a file rewrites its dimensions and can rewrite its DPI tag. It cannot add detail that was never captured. What actually predicts OCR quality is how many pixels tall the text is once decoded. Simple arithmetic connects the two. At Tesseract's recommended 300 dpi, ordinary 11pt body text renders at roughly 11⁄72 × 300 ≈ 46 pixels of em height. (11pt is a common size for a scanned letter or invoice.) The ink itself occupies around three quarters of that height. This tool measures that ink band height directly, from a projection profile of the text lines. It then reports the DPI this _implies_, labelled "effective resolution" and marked as a heuristic. The conversion constant behind it was calibrated by measuring real rendered pages at 75, 150, and 300 dpi. It is this tool's own empirical figure, not a citation of Tesseract's numbers. Tesseract's numbers state a DPI floor and say nothing about point size. One constant stands in for every type size and typeface. So the figure is deliberately reported as a rough "~N dpi." When the measurement lands somewhere physically implausible, the report says "couldn't measure" instead of printing a number nobody could defend. When the file's declared DPI and the measured effective DPI disagree, that disagreement is the most useful thing on the page. The report says so directly, rather than picking one number to show. ## why-your-ocr-output-is-garbage Roughly in order of how often each one turns out to be the actual cause: - **Too small.** Effective resolution under Tesseract's 300 dpi floor. This is the most common cause by far, and the one declared DPI hides best. - **Too blurred.** Out-of-focus phone photos, or a low-quality scan pass. OCR relies on sharp character edges to separate similar letter shapes. Focus is judged _relative to the size of the text_, not on an absolute sharpness score. A half-pixel of softness is nothing on a 600 dpi scan, and fatal on a 100 dpi one. Measuring it without accounting for scale would flag good high-resolution scans and miss bad low-resolution ones. - **Skewed.** A few degrees of rotation from a sheet feeder is routine, and usually self-corrects internally. Several more degrees than that starts merging or dropping characters at line ends. - **Inverted.** Light text on a dark background. Most OCR engines, Tesseract included, are tuned for the opposite. They read an inverted page far less accurately without a pre-processing invert. - **JPEG-crushed.** Heavy or repeated re-compression leaves visible 8-pixel blocking that erases the fine edge detail small text depends on. - **Noisy.** Dust on a scanner glass or a bad fax line leaves isolated ink specks OCR can mistake for punctuation or accents. - **Sideways.** EXIF says the image should display rotated. But most OCR pipelines read the raw pixel grid and ignore that tag. The page stays sideways unless something rotates it first. ## fix-it-before-you-upload Every advisory this tool raises comes with a runnable fix: an `ImageMagick` command and the equivalent Pillow (Python) snippet. Both actually ran against a real file before this page shipped. Two examples come up constantly: ``` magick in.jpg -auto-orient -colorspace Gray -deskew 40% -resize 200% out.png ``` equivalent in Pillow: ``` from PIL import Image, ImageOps img = ImageOps.exif_transpose(Image.open("in.jpg")) img = img.convert("L").resize((img.width * 2, img.height * 2), Image.LANCZOS) img.save("out.png") ``` The exact fix depends on what's actually wrong. That's what the checker above is for: each advisory it raises names its own command rather than a generic cure-all. ## text-already-in-the-file Some images already carry real, extractable text that has nothing to do with OCR. That includes EXIF `ImageDescription`, IPTC caption/headline fields written by photo editors, XMP `dc:description`/`dc:title`, and PNG `tEXt`/`zTXt`/`iTXt` chunks. txtfetch's API returns this metadata alongside whatever OCR finds. It costs nothing extra and needs no separate request. If this tool finds any, it lists it under "text already stored in this file's metadata" above, separate from the OCR verdict. That's a genuinely different thing: metadata Tika reads directly, present or absent, independent of whether the pixels are OCR-clean. ## what-this-cannot-tell-you This tool predicts OCR-readiness from measurable pixel properties. It does not run OCR. So it cannot tell you what the text actually says. It cannot tell whether the text is in a script or language Tesseract's language packs cover. And it cannot tell whether handwriting is present, which defeats printed-text OCR engines regardless of resolution. A perfect "ocr-ready" verdict means the image has the resolution, focus, and orientation OCR needs to have a fair shot. It is not a promise about the accuracy of whatever comes back. That accuracy still depends on font, language, and layout complexity. See [measured extraction accuracy](https://txtfetch.com/benchmarks) by document category for how that plays out on real documents. ## what-to-do-next Once your image is ready, the call is the same shape as every other format: curl ```curl curl -X POST https://api.txtfetch.com/v1/extract \ -H "Authorization: Bearer $TXTFETCH_KEY" \ -F file=@scanned-invoice.jpg ``` Python ```python import os import requests with open("scanned-invoice.jpg", "rb") as f: r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, files={"file": f}, ) print(r.json()["extracted_text"]) ``` JavaScript ```javascript import { readFile } from "node:fs/promises"; const file = new Blob([await readFile("scanned-invoice.jpg")]); const form = new FormData(); form.append("file", file, "scanned-invoice.jpg"); const res = await fetch("https://api.txtfetch.com/v1/extract", { method: "POST", headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` }, body: form, }); const { extracted_text } = await res.json(); console.log(extracted_text); ``` Go ```go package main import ( "bytes" "encoding/json" "fmt" "io" "mime/multipart" "net/http" "os" ) type extractResponse struct { Status string `json:"status"` ExtractedText string `json:"extracted_text"` } func main() { f, err := os.Open("scanned-invoice.jpg") if err != nil { panic(err) } defer f.Close() var body bytes.Buffer writer := multipart.NewWriter(&body) part, err := writer.CreateFormFile("file", "scanned-invoice.jpg") if err != nil { panic(err) } if _, err := io.Copy(part, f); err != nil { panic(err) } writer.Close() req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY")) req.Header.Set("Content-Type", writer.FormDataContentType()) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result extractResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } fmt.Println(result.ExtractedText) } ``` Multi-page fax TIFFs read differently. See [the TIFF extraction guide](https://txtfetch.com/extract/tiff) for walking the full page chain. For a scanned PDF rather than a bare image, see [scanned-PDF OCR](https://txtfetch.com/extract/scanned-pdf). Or check whether it has a text layer at all, with [the PDF text-layer checker](https://txtfetch.com/tools/pdf-text-check). [Get your key →](https://app.txtfetch.com/signup) ## faq **What DPI do I need for OCR to work well?**: Tesseract's own documentation says it "works best on images which have a DPI of at least 300 dpi" (see tessdoc's ImproveQuality page). But DPI is a metadata tag, not a pixel measurement. What actually decides OCR quality is how many pixels tall your text is once decoded. This tool measures that directly, instead of trusting the file's declared resolution. **Why is my OCR output gibberish even though the image looks fine to me?**: This tool checks five common causes, in order. The text can be too small in pixel terms: low effective resolution, even if the file claims high DPI. The image can be soft or out of focus. The page can be rotated more than a couple of degrees. The text can be light-on-dark instead of dark-on-light. Or heavy JPEG compression can have crushed the fine edges OCR relies on. This tool measures all five and tells you which ones apply to your file. **Does declared DPI in a file's metadata mean anything for OCR?**: Sometimes, but it lies in both directions. A phone photo often declares 72 dpi, a leftover screen-resolution default, despite having plenty of real detail. An upscaled fax can declare 300 dpi while the actual text is a handful of blurry pixels tall. This tool reports both numbers and tells you plainly when they disagree. The measured number is the one that predicts what OCR will actually do. **Can this tool run OCR on my image?**: No, on purpose. It never bundles an OCR engine or a model of any kind. It predicts whether OCR is likely to succeed using classical image analysis: Otsu thresholding, projection profiles, and focus measurement. All of that runs entirely in your browser. If the verdict is good, use the extraction API below to actually run it. **Does this tool upload my image anywhere?**: No. Reading the file's bytes, decoding pixels, and analysing them all happen locally in your browser, using the Canvas and File APIs. Nothing is sent over the network. The only thing that leaves your browser is the report, and only if you choose to copy it. **Why does it say "metadata only" instead of giving a verdict?**: TIFF isn't decodable by any mainstream browser's . HEIC/AVIF only decode in Safari. So for those files, outside Safari, this tool can only read the container's own metadata: dimensions, compression, declared resolution, and embedded text, not the pixels. That's still useful, especially for TIFF, whose metadata carries page count, fax compression, and photometric interpretation. But it can't tell you about blur, skew, or contrast without decoding pixels it structurally cannot get to. **What does "inconclusive" mean here?**: It means this scan's signals didn't clearly match a known good or bad pattern. Often that's an unusual layout, an image that's mostly non-text content, or a case outside what this tool's heuristics were calibrated against. Like the other checkers on this site, it's built to say "couldn't tell" rather than guess and be confidently wrong. ## That was one file. The API does the queue. This page read your scan on your own machine. The API reads a folder of them. [Read the quickstart →](https://txtfetch.com/docs) [Get an API key →](https://app.txtfetch.com/signup)