Image OCR

Extracts text from images.

Utilities · Image OCR

Details

IDImage OCR
ProviderOpen Source
CategoryUtilities
From Version5.0.0
Docker Imagedemisto/tesseract:1.0.0.11009641
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

Use the Image OCR integration to extract text from images. The integration utilizes the open-source tesseract OCR engine.

Use Cases

  • Extract text from images included in emails during a phishing investigation.
  • Extract text from images included in an html page.

Configure Image OCR in Cortex

Parameter Description Required
A CSV of language codes of the language to use for OCR (leave empty to use defaults). The default language used for OCR is English. Use this parameter to specify a list of additional languages. For example, eng,fra. To see all supported language codes, use the image-ocr-list-languages command. False
Skip on corrupted images If true, will not raise an error if the image is corrupted and could not be processed. False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

image-ocr-list-languages


Lists supported languages for which the integration can extract text.

Base Command

image-ocr-list-languages

Input

There are no input arguments for this command.

Command Example

!image-ocr-list-languages

Human Readable Output

Image OCR Supported Languages

  • ara
  • chi_sim
  • chi_sim_vert
  • chi_tra
  • chi_tra_vert
  • deu
  • eng
  • fra
  • heb
  • ita
  • jpn
  • jpn_vert
  • pol
  • por
  • rus
  • spa
  • swe
  • tur

image-ocr-extract-text


Extracts text from an image.

Base Command

image-ocr-extract-text

Input

Argument Name Description Required
entryid A comma-separated list of Entry IDs of image files to process. Required
langs A CSV of language codes of the language to use for OCR. Overrides the default configured language list. Optional
verbose Turn on verbose flag to display tesseract and other used libraries versions. Optional

Context Output

Path Type Description
File.Text String Extracted text from the passed image file.

Command Example

!image-ocr-extract-text entryid="922@e84104f7-b235-4d82-860a-ea09f5dc0559"

Context Example

{
    "File": {
        "Text": "The quick brown fox\njumped over the 5\nlazy dogs!\n\f", 
        "EntryID": "922@e84104f7-b235-4d82-860a-ea09f5dc0559"
    }
}

Human Readable Output

Image OCR Extracted Text for Entry ID 1613@1e6b4a55-33e7-433b-8f6f-2c0751c8c444

The quick brown fox
jumped over the 5
lazy dogs!

Configuration parameters

  • langs — A CSV of language codes of the language to use for OCR (leave empty to use defaults).
  • skip_corrupted — Skip on corrupted images

Commands (2)

  • image-ocr-extract-text

    Extract text from images.

  • image-ocr-list-languages

    Lists supported languages for which the integration can extract text.

import subprocess

import demistomock as demisto
from CommonServerPython import *

TESSERACT_EXE = "tesseract"
CORRUPTED_ERRORS = ("pix not read", "truncated file")
CORRUPTED_ERR = CORRUPTED_ERRORS[0]  # kept for backward compatibility
CORRUPTED_MSG = "WARNING: failed to extract text - image is corrupted"
EMPTY_FILE_MSG = "WARNING: failed to extract text - file is empty"


def list_languages() -> list[str]:
    lang_out = subprocess.check_output([TESSERACT_EXE, "--list-langs"], universal_newlines=True)
    if not lang_out:  # something went wrong
        raise ValueError("No output from --list-langs")
    lines = lang_out.splitlines()
    if len(lines) <= 1:
        raise ValueError("No output from --list-langs")
    return sorted(lines[1:])  # ignore first line


def extract_text(image_path: str, languages: list[str] = [], verbose: bool = False) -> str:
    exe_params = [TESSERACT_EXE, image_path, "stdout"]
    if verbose:
        exe_params.extend(["-v"])

    if languages:
        exe_params.extend(["-l", "+".join(languages)])

    res = subprocess.run(exe_params, capture_output=True, check=True, text=True)
    if res.stderr:
        demisto.debug(f"tesseract returned ok but stderr contains warnings: {res.stderr}")

    return res.stdout


def list_languages_command() -> CommandResults:
    langs = list_languages()
    return CommandResults(
        readable_output="## Image OCR Supported Languages\n\n" + "\n".join(["* " + s for s in langs]), raw_response=langs
    )


def extract_text_command(args: dict, instance_languages: list, skip_corrupted: bool) -> tuple[list, list]:
    langs = argToList(args.get("langs")) or instance_languages
    verbose = argToBoolean(args.get("verbose", False))
    demisto.debug(f"Using langs settings: {langs}")
    results, errors = [], []

    entry_ids = argToList(args.get("entryid"))
    for entry_id in entry_ids:
        try:
            file_path = demisto.getFilePath(entry_id)
            if not file_path:
                raise DemistoException(f"Couldn't find entry id: {entry_id}")

            if os.path.getsize(file_path["path"]) == 0:
                demisto.debug(f"File with entry ID {entry_id} is empty, skipping OCR.")
                results.append(
                    CommandResults(
                        readable_output=f"## Could not process file with entry ID {entry_id} - file is empty",
                        outputs_prefix="File",
                        outputs_key_field="EntryID",
                        outputs={"EntryID": entry_id, "Text": EMPTY_FILE_MSG},
                        entry_type=EntryType.WARNING,
                    )
                )
                continue

            demisto.debug(f"Extracting text from file: {file_path}")
            res = extract_text(file_path["path"], langs, verbose)
            file_entry = {"EntryID": entry_id, "Text": res}
            results.append(
                CommandResults(
                    readable_output=f"## Image OCR Extracted Text for Entry ID {entry_id}\n\n" + res,
                    outputs_prefix="File",
                    outputs_key_field="EntryID",
                    outputs=file_entry,
                    raw_response=res,
                )
            )
        except subprocess.CalledProcessError as cpe:
            if any(err in cpe.stderr for err in CORRUPTED_ERRORS) and skip_corrupted:
                file_entry = {"EntryID": entry_id, "Text": CORRUPTED_MSG}
                results.append(
                    CommandResults(
                        readable_output=f"## Could not process file with entry ID {entry_id} - image is corrupted",
                        outputs_prefix="File",
                        outputs_key_field="EntryID",
                        outputs=file_entry,
                        entry_type=EntryType.WARNING,
                    )
                )
            else:
                errors.append(
                    f"An error occurred while trying to process {entry_id=}: "
                    f"Failed {cpe.cmd} execution. Return status: {cpe.returncode}.\n"
                    f"Error:\n{cpe.stderr}\n"
                    f"Stdout:\n{cpe.stdout}"
                )
        except Exception as e:
            errors.append(f"An error occurred while trying to process {entry_id=}: {e}")

    return results, errors


def run_test_module(instance_languages: list) -> str:
    try:
        supported_langs = list_languages()
        if instance_languages:
            for language in instance_languages:
                if language not in supported_langs:
                    raise DemistoException(f"Unsupported language configured: {language}")
        return "ok"
    except Exception as exception:
        raise Exception(f"Failed testing {TESSERACT_EXE}: {exception}")


def main() -> None:
    command = demisto.command()
    args = demisto.args()
    params = demisto.params()
    instance_languages = argToList(params.get("langs"))
    skip_corrupted = params.get("skip_corrupted")
    try:
        if command == "test-module":
            return_results(run_test_module(instance_languages))
        elif command == "image-ocr-list-languages":
            return_results(list_languages_command())
        elif command == "image-ocr-extract-text":
            results, errors = extract_text_command(args, instance_languages, skip_corrupted)
            return_results(results)
            if errors:
                raise DemistoException("\n".join(errors))
        else:
            raise NotImplementedError(f"Command {command} was not implemented.")
    except Exception as err:
        return_error(f"Failed with error(s): {err}")


# python2 uses __builtin__ python3 uses builtins
if __name__ in ("__builtin__", "builtins", "__main__"):
    main()