AI-Powered Text Extraction & Editing

Image Text Editor

Extract, edit, and export text from images

Text Blocks

No text blocks. Click 'Extract Text' to detect text.

Drop your image here

or click to browse

Supports: JPG, PNG, WebP, GIF, BMP

Properties

How to Use

  • 1. Upload an image
  • 2. Click "Extract Text" to detect text
  • 3. Click a region to select it
  • 4. Edit text in the panel
  • 5. Export when done

Image Text Editor — Frequently Asked Questions

Extract Text hands the image's data URL to a Tesseract.js v6 worker running WebAssembly off the main thread. The tool walks the returned block, paragraph and line tree and keeps every line whose trimmed text is non-empty and whose confidence is above 30. Each survivor becomes a text block placed at its OCR bounding box: x, y, width and height come straight from that box, and font size is estimated at 80% of the line height with a 12 px floor. If the tree comes back empty but raw text exists, a fallback splits on newlines and stacks 24 px blocks 30 px apart down the left edge at x = 20, font size 16, stamped with a flat confidence of 80 rather than a measured one. Every OCR block keeps its original string, printed as Original above the editing controls.

The pixels never leave your machine. The file is read with FileReader.readAsDataURL, recognition runs in a worker compiled to WebAssembly, and the export is produced by canvas.toDataURL and handed to an anchor element's download attribute. No upload endpoint, no account, no credit counter, no server round trip, and nothing written to storage - closing the tab discards the blocks and the undo stack with them. One honest caveat: the first Extract Text run fetches the tesseract.js WASM core and the English eng.traineddata model from its CDN. That is a download into your browser, not an upload of your image, and you can watch it in the network tab. It matters because the files people most often need to edit - invoices, dashboards holding real customer data, internal tooling screenshots, ID scans - are exactly the ones that should not sit in a stranger's processing queue.

Selecting a block, on the canvas or in the Text Blocks panel, opens eight controls in Properties, plus direct dragging on the canvas. Any change flags the block as modified, which is what makes it eligible for export and switches its outline from blue to green; the selected block outlines in violet. Unmodified blocks show as translucent blue boxes over the original pixels, and modified ones render your new text live in the preview. The Hide button drops every overlay so you can check the result against the untouched image at any point.

Text content

Three-row textarea. Canvas export wraps on spaces only, so use one block per output line.

Font size

Slider from 8 to 72 px, seeded by OCR at 80% of the detected line height with a 12 px floor.

Font family

Arial, Helvetica, Times New Roman, Georgia, Courier New, Verdana, Impact - system fonts, so preview and export match.

Weight

Normal/bold toggle, applied to both the preview span and the canvas ctx.font string.

Text and background colour

Swatch plus editable hex field for each. Background defaults to #ffffff and is the fill that hides the original pixels.

Width and height

Numeric boxes in source-image pixels; width also decides where the export wraps lines.

Position

Drag in Select mode. Coordinates are clamped at zero and stored at native resolution, not preview scale.

Export composites onto a hidden canvas sized to the image's original pixel dimensions, not the scaled preview you were working in - the preview is capped at 700 px wide or 70% of the window height and never upscales past 100%. The canvas draws the source image first, then for each modified block fills a rectangle in that block's background colour and paints the new text on top with ctx.fillText, textBaseline 'top' and a 2 px inset. Wrapping is measured with ctx.measureText against the block width, and lines sit at 1.2x the font size. Blocks you never edited are skipped entirely, so untouched regions keep their exact original pixels. The file downloads as edited- plus your full original filename plus .png, which means photo.jpg returns as edited-photo.jpg.png. With zero modified blocks the button stays disabled, because extraction alone changes nothing.

The replacement strategy is a solid rectangle plus new text, and that one fact decides the fit. On screenshots, UI mockups, error dialogs, slide exports, diagrams and scanned documents with flat backgrounds, the patch is invisible and the workflow beats reopening a design file. On photographs, gradients, textures or type set over imagery, the rectangle reads as a rectangle - match the background colour first, or reach for a dedicated inpainting tool. Three other hard edges: only the English model is loaded, so other scripts come back garbled; dragging listens to mouse events with no touch or pointer fallback, so repositioning wants a cursor; and drag-and-drop works on the empty drop zone only, so swapping images means clearing the current one with the trash button first. Re-running Extract Text also wipes the blocks you were editing, so export before you retry.

No. The file is read in the browser with FileReader.readAsDataURL, OCR runs in a local worker compiled to WebAssembly, and the export comes from canvas.toDataURL fired through an anchor element's download attribute. There is no upload endpoint and no account. The one network request is tesseract.js pulling its WASM core and the English eng.traineddata model from its CDN on your first Extract Text run - that is a download into your browser, not an upload of your picture. Nothing is persisted, so closing the tab discards every block and every undo step.

Tesseract.js v6, initialised with createWorker('eng') - English only. Recognition is called with the blocks option on, so results arrive as a block, paragraph and line tree instead of a flat string. The tool walks that tree and creates one editable element per line, taking x, y, width and height from the line's bounding box. Tesseract supports 100+ languages, but this page loads a single English traineddata file to keep the first-run download small. Other scripts will come back low-confidence or garbled, and lines scoring 30 or below are dropped entirely.

It paints over it. On export each modified block first fills a rectangle in that block's background colour, default #ffffff, across the block's full width and height, then draws your new string on top with ctx.fillText. There is no inpainting or generative fill. That makes the technique invisible on flat backgrounds - screenshots, UI mockups, dialogs, slides, receipts - and visible as a rectangle over photographs, gradients or textures. On a busy background, set the block's background colour to a sampled match before exporting, or accept the patch.

The file input accepts image/*, and the drop zone lists JPG, PNG, WebP, GIF and BMP - anything the browser can decode into an HTMLImageElement loads. A non-image file throws "Invalid file type" before anything renders. Animated GIFs export as a single frame. No file size cap exists in the code; the real ceiling is browser memory, since the image is held as a base64 data URL and decoded a second time for the canvas export. Scans past roughly 20-30 megapixels make OCR slow and strain memory on phones.

PNG, at the image's original pixel dimensions - the export canvas is sized from the source width and height, not the scaled-down preview. The underlying export function also accepts JPEG or WebP at 0.92 quality plus a scale multiplier, but the Export button does not expose them. One quirk worth knowing: the download name is edited- plus your full original filename plus .png, so photo.jpg comes back as edited-photo.jpg.png. Untouched regions are byte-for-byte the pixels you loaded, because only modified blocks get repainted.

Export stays disabled until at least one block is flagged modified. A block flips to modified the instant you change any property - text, font size, family, weight, colour, background, width or height - or drag it, and blocks you add yourself are modified from creation. Running OCR alone changes no pixels, so there is nothing to bake in. The button shows the count in parentheses, for example Export (3), the Image Info panel tracks the same number, and modified blocks turn from a blue outline to a green one on the canvas.

Seven families: Arial, Helvetica, Times New Roman, Georgia, Courier New, Verdana and Impact. All are system-safe, so the canvas export matches the on-screen preview without waiting on a webfont. Font size is a slider from 8 to 72 px, and weight is a normal/bold toggle. OCR seeds each block's size at 80% of its detected line height with a 12 px floor, which usually lands close but is worth nudging by eye. There is no italic, no letter-spacing, no stroke and no text alignment control.

It is Tesseract's own certainty score for that line, 0-100. Lines scoring 30 or below are discarded during extraction and never become blocks. Survivors are colour-coded in the Text Blocks panel: above 80 green, above 50 amber, the rest red. Read amber and red lines against the original before editing them. Blocks you add by hand are stored at 100, so the Text Blocks panel shows 100% while the Properties readout hides it - that panel only prints a score below 100. The newline fallback path stamps a flat 80 rather than a measured score.

Yes. Switch the toolbar to Add Text and click anywhere on the image. A 150x30 px block containing "New Text" drops at that point, already selected and already flagged modified, and the mode snaps back to Select so your next click selects rather than adds. Click coordinates are divided by the current preview scale, so the block lands at the right spot in the full-resolution export. Use it for captions, labels, or lines Tesseract skipped because contrast was too low.

The stack holds up to 50 past states and drops the oldest beyond that. Undo and redo sit at the left of the toolbar, and the Image Info panel shows position as current/total. Any new edit clears the redo branch, and a state that serialises identically to the previous one is not pushed. One caveat: dragging a block records a state on every mouse-move, so a single long drag can eat most of the 50 slots. Loading a new image or re-running Extract Text resets the stack and discards existing blocks.

The preview renders each block as an HTML element with whitespace-pre-wrap and 1.1 line height, while the export wraps on canvas using ctx.measureText against the block width with a 2 px inset and 1.2x line spacing. The consequence: canvas wrapping splits on spaces only, so a line break you typed into the textarea shows in the preview but not in the exported PNG. For multi-line output use one block per line. Text longer than the block height still paints, so widen or heighten a block if it looks clipped.

It works best on flat backgrounds. Screenshots, UI mockups, error dialogs, slide exports, diagrams and scanned documents edit cleanly because the solid background rectangle blends in. Photographs, gradients and type set over imagery show the patch, since there is no content-aware fill. OCR accuracy tracks source quality the same way, and the per-line confidence score tells you which lines the engine struggled with before you commit. Dragging is wired to mouse events only, with no touch or pointer handlers, so repositioning wants a real cursor.

Customer Reviews

0 out of 5 stars

Based on 0 reviews

Review data

5 star reviews

0%

4 star reviews

0%

3 star reviews

0%

2 star reviews

0%

1 star reviews

0%

Share your thoughts

If you've used this tool, share your thoughts with other users

Recent reviews

Latest Articles

Tips, guides, and insights from our blog