How to Extract Text From an Image in Python

Jul 11, 2026 7 min read

How to extract text from an image in Python: use pytesseract for offline OCR, or POST the image to an OCR API for structured fields and tables as JSON. Code for both.

// Try it now

PDF, JPG, PNG, BMP, HEIC, TIFF

Upload a document to extract

Last updated July 2026.

To extract text from an image in Python, you have two paths. For offline work on clean images, install pytesseract, which wraps the Tesseract engine, and call pytesseract.image_to_string(Image.open('photo.png')) to get the text back as a string. For messy photos, handwriting or business documents where you need labeled fields and tables rather than a wall of text, send the image to an OCR API and read structured JSON back with the requests library. The library route is free and local; the API route is more accurate on real-world images and returns data your code can use directly.

Reading text off an image is one of those tasks that looks trivial until you hit a real photo. A flat, high-contrast scan reads almost perfectly. A phone snapshot of a crumpled receipt under warehouse lighting is a different problem. Which tool you reach for in Python depends far more on the quality of your images and what you plan to do with the text than on the language itself.

The two ways to extract text from an image in Python

Every approach falls into one of two buckets, and picking the right bucket first saves a lot of wasted effort.

ApproachHow it runsReturnsBest for
pytesseract (Tesseract)Local library, offlinePlain text stringClean scans, offline, no per-page cost
EasyOCR / PaddleOCRLocal, deep-learning, GPU helpsText plus boxesHarder images without a cloud, if you can host a model
OCR API (hosted)HTTPS call with requestsNamed fields, tables, confidence as JSONPhotos, handwriting, business documents at volume

The dividing line is what you need back. If you only want the raw words to search or display, a local library is enough. If you need to know that "INV-4021" is the invoice number and that a block of numbers is a table of line items, you want a document API that returns those as structured data instead of you writing the parsing.

How do I extract text from an image in Python with pytesseract?

Install Tesseract on the machine, then the Python wrapper, and you can read a clean image in three lines. On most systems that is apt install tesseract-ocr (or brew install tesseract on macOS), then pip install pytesseract pillow. Then:

from PIL import Image
import pytesseract

text = pytesseract.image_to_string(Image.open("invoice.png"))
print(text)

That returns the recognized text as a single string. Tesseract is genuinely good on clean, straight, high-contrast documents and it is free with no per-page cost, which is why it is the default for offline and low-volume jobs. Its weaknesses show up on photographs: skew, shadows, low resolution and handwriting all pull accuracy down fast, and it gives you text with no sense of which value is a total and which is a date. You end up writing regular expressions to find the fields you care about, and those break the moment a vendor changes their layout.

How do I improve Tesseract accuracy on a photo?

Preprocess the image before you hand it to Tesseract. The engine was built for scanned pages, so the closer a photo looks to a clean scan, the better it reads. In practice the highest-impact steps are converting to grayscale, increasing contrast, and deskewing so the text sits horizontal. A common OpenCV preprocessing block looks like this:

import cv2

img = cv2.imread("receipt.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
text = pytesseract.image_to_string(thresh)

Upscaling small images to roughly 300 DPI and removing background noise help too. Even with all of this, a bad photo has a ceiling, and no amount of preprocessing turns a blurry, folded receipt into clean text. That ceiling is the point where teams usually move to a hosted model.

How do I extract structured data from an image, not just text?

Send the image to an OCR API that returns named fields and tables, then read the JSON in Python with requests. This is the path when you need the values, not just the words: an invoice should come back as an invoice number, a date and a total, and a table should come back as rows. With a REST API like the image to text API, there is no SDK to install. You upload the image, start extraction, and poll for the result:

import time, requests

API_KEY = "YOUR_API_KEY"
BASE = "https://docuocr.com/api/documents"
headers = {"Authorization": f"Bearer {API_KEY}"}

with open("receipt.jpg", "rb") as f:
    file_id = requests.post(f"{BASE}/upload", headers=headers,
                            files={"file": f}).json()["file_id"]

job = requests.post(f"{BASE}/extract", headers=headers,
                    json={"file_id": file_id}).json()["extraction_hash"]

while True:
    res = requests.get(f"{BASE}/extraction/{job}", headers=headers).json()
    if res["status"] == "completed":
        break
    time.sleep(2)

for field in res["fields"]:
    print(field["name"], field["value"], field["confidence"])

Because the response is JSON, response.json() gives you a Python dict of fields, table rows and a confidence score on each value, so you can flag anything below a threshold for review instead of trusting every read. The Python OCR API walkthrough covers batching, retries and webhooks for when you are processing thousands of images rather than one.

Which is more accurate, a local library or an OCR API?

On clean, printed scans the gap is small and Tesseract is fine. On real-world photos, handwriting and low-quality scans, hosted models from the major providers are meaningfully more accurate because they are trained on far more varied data than a local engine. Cloud vision services also read handwriting, which Tesseract handles poorly. The honest tradeoff is cost and dependency: a local library is free and runs on your own machine, while an API costs per page (roughly $1.50 per 1,000 pages for raw text, more for structured fields) and needs a network call. For a weekend script on tidy PDFs, use pytesseract. For a product that ingests whatever a user uploads, an API earns its cost by not failing on the messy 20 percent.

Can Python read text from a scanned PDF the same way?

Yes, with one wrinkle. A digital PDF has a real text layer you can read directly with pdfplumber or PyPDF, no OCR needed. A scanned PDF is really a stack of page images, so you either rasterize each page with pdf2image and run OCR, or send the whole PDF to an OCR API that detects image-only pages and OCRs them for you. A document API keeps this to one code path: you POST the file whether it is a photo, a scan or a native PDF, and it returns the same JSON shape. That matters once your inputs are mixed, which they almost always are in a real pipeline. If those documents are financial and headed for accounting, a purpose-built tool can take a statement PDF and turn it straight into a clean spreadsheet without any of the OCR plumbing.

The short version

For offline OCR on clean images in Python, pytesseract in three lines does the job, and OpenCV preprocessing pushes its accuracy further. When the images are photos or handwriting, or when you need labeled fields and tables rather than a raw string, send them to an OCR API and read structured JSON with requests. Start with the library, and move to the API at the point where accuracy or structure, not price, becomes the thing that is slowing you down. You can test the API path on your own image with the tool at the top of the image to text API page before you write any code.

Extract your documents with DocuOCR

Upload a document and get clean, structured data in seconds. No template setup required.

Start free

← Back to all articles