diff options
| author | Robert Günzler <r@gnzler.io> | 2022-11-18 17:40:06 +0100 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2022-11-18 18:38:20 +0100 |
| commit | 1647fc4a8f326feb2a4fa00598ca5c5fd24cb0aa (patch) | |
| tree | ab4081ab4e26de62a3adebfff1ba4c94aa85c2cb /bin | |
| parent | 74fe9214164db44af0aff1c871cf4098396e2293 (diff) | |
bin: add grimocr
Diffstat (limited to 'bin')
| -rwxr-xr-x | bin/grimocr | 208 | ||||
| -rw-r--r-- | bin/grimocr.requirements | 1 |
2 files changed, 209 insertions, 0 deletions
diff --git a/bin/grimocr b/bin/grimocr new file mode 100755 index 0000000..5b40257 --- /dev/null +++ b/bin/grimocr @@ -0,0 +1,208 @@ +#!/bin/bash +# adapted for wayland (grim/slurp/wl-copy) from +# https://github.com/tatsumoto-ren/dotfiles/blob/main/.local/bin/maimocr + +set -e +[ -n "$DEBUG" ] && set -x + +TESSDATA_PREFIX=$HOME/.local/share/tessdata + +langs= +method=tesseract +while getopts l:m:h opt; do + case "$opt" in + l) langs="${OPTARG}" ;; + m) method="${OPTARG}" ;; + h | ?) + printf "usage: %s [-h]\n" "$(basename "$0")" + printf "\n" + printf " -l LANG[+LANG]\n" + printf " -m METHOD\n" + printf "\n" + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +for c in curl unzip grim slurp convert wl-copy; do + if ! command -v "$c" >/dev/null; then + notify "$c must be installed." + exit 1 + fi +done + +notify() { + echo "$*" + notify-send "㊗️ grimOCR" "$*" +} + +notify_ask() { + notif_args="gdbus call --session \ + --dest org.freedesktop.Notifications \ + --object-path /org/freedesktop/Notifications" + ok_action_key=ok__$(mktemp -u | cut -d. -f2) + cancel_action_key=cancel__$(mktemp -u | cut -d. -f2) + + APP_NAME=grimocr + REPLACE_ID=0 + ICON= + SUMMARY=grimOCR + BODY="$*" + ACTIONS="[\"$ok_action_key\", \"OK\", \"$cancel_action_key\", \"Cancel\"]" + HINTS='{}' + EXPIRE_TIME=0 + + id=$($notif_args --method org.freedesktop.Notifications.Notify -- \ + "$APP_NAME" "$REPLACE_ID" "$ICON" "$SUMMARY" "$BODY" \ + "$ACTIONS" "$HINTS" "int32 $EXPIRE_TIME" | sed 's/(uint32 \([0-9]\+\),)/\1/g') + + pidfile=$(mktemp /tmp/grimocr_notification_monitor.XXXXX) + result=$(mktemp /tmp/grimocr_notification_result.XXXXX) + trap '{ kill "$(cat "$pidfile")" ; rm -- "$pidfile" "$result"; }' EXIT + ( + gdbus monitor --session \ + --dest org.freedesktop.Notifications \ + --object-path /org/freedesktop/Notifications & + printf "%d" $! >&3 + ) 3>"$pidfile" | + while read -r line; do + closed_id=$(printf "%s" "$line" | sed '/^\/org\/freedesktop\/Notifications: org.freedesktop.Notifications.NotificationClosed (uint32 \([0-9]\+\), uint32 [0-9]\+)$/!d;s//\1/') + if [ -n "$closed_id" ] && [ "$closed_id" = "$id" ]; then + $notif_args --method org.freedesktop.Notifications.CloseNotification "$id" >/dev/null + break + fi + action_invoked=$(printf "%s" "$line" | sed "/\/org\/freedesktop\/Notifications: org.freedesktop.Notifications.ActionInvoked (uint32 \([0-9]\+\), '\(.*\)')\$/!d;s//\1:\2/") + if [ -n "$action_invoked" ]; then + invoked_id=$(printf "%s" "$action_invoked" | cut -d: -f1) + action_id=$(printf "%s" "$action_invoked" | cut -d: -f2) + if [ "$invoked_id" = "$id" ]; then + case "$action_id" in + "$ok_action_key") printf "0" >"$result" ;; + "$cancel_action_key") printf "1" >"$result" ;; + esac + $notif_args --method org.freedesktop.Notifications.CloseNotification "$id" >/dev/null + break + fi + fi + done + return "$(cat "$result")" +} + +download_tessdata() { + osd_url="https://github.com/tesseract-ocr/tessdata_best/blob/main/osd.traineddata" + eng_url="https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata" + jpn_url="https://g33k.se/_matrix/media/r0/download/g33k.se/chvDlHzjiXgDEdeGTFnyOExv" + + if ! notify_ask "Downloading Tesseract data?"; then + notify "Download aborted." + exit 0 + else + notify "Download started." + fi + + # download osd tessdata + curl -LsSf -o "$TESSDATA_PREFIX/osd.tessdata" "$osd_url" + curl -LsSf -o "$TESSDATA_PREFIX/eng.tessdata" "$eng_url" + + # download jpn tessdata + jpn_zip_path=$(mktemp /tmp/grimocr_tesseract_data.XXXXX) + trap '{ rm -- "$jpn_zip_path"; }' EXIT + curl -LsSf -o "$jpn_zip_path" "$jpn_url" + mkdir -p -- "$TESSDATA_PREFIX" + unzip -o -j "$jpn_zip_path" -d "$TESSDATA_PREFIX" + + notify "Download complete. Run again..." +} + +take_screenshot() { + # https://tesseract-ocr.github.io/tessdoc/ImproveQuality.html#missing-borders + grim -g "$(slurp)" -t png -l 1 - | + convert png:- -alpha off -bordercolor White -border 10x10 png:- + + notify "recognizing..." >/dev/null +} + +installed_languages() { + if [ -n "$langs" ]; then + printf "%s" "$langs" + else + find "$TESSDATA_PREFIX" -type f -name '*.traineddata' -printf '%f+' | + sed 's|\.traineddata||g; s|\+$||' + fi +} + +tesseract_recognize() { + # https://tesseract-ocr.github.io/tessdoc/Command-Line-Usage.html + tesseract stdin stdout \ + --tessdata-dir "$TESSDATA_PREFIX" \ + -l "$(installed_languages)" \ + --psm 1 | + tr -d '\f' + + # NOTE: by removing this, we can make it work for other langs too + # tr -d ' ' | + # tr -d '\n' | + # grep -P '[ヲ-゚ァ-ヶぁ-ゞA-z0-9ァ-ン゙゚ァ-ンぁ-ん一-龯]+' +} + +mangaocr_recognize() { + python3 -c "$( + cat <<-EOF + from manga_ocr import MangaOcr + + text = MangaOcr()("/dev/stdin") + print(text) + EOF + )" +} + +recognize() { + case "${method}" in + tesseract) tesseract_recognize ;; + mangaocr) mangaocr_recognize ;; + esac +} + +run_ocr() { + result=$(take_screenshot | recognize 2>/dev/null) + if [ $? -eq 0 ]; then + printf "%s" "$result" | wl-copy -n + notify "$result" + else + notify "Failed." + fi +} + +## main + +case "${method}" in +tesseract) + if ! command -v tesseract >/dev/null; then + notify "tesseract must be installed." + exit 1 + fi + if [ ! -d "$TESSDATA_PREFIX" ]; then + download_tessdata + fi + ;; +mangaocr) + if ! command -v python3 >/dev/null; then + notify "python3 must be installed." + exit 1 + fi + notify "setting up manga-ocr..." + script_path="$(dirname "$(readlink -f "$0")")" + venv_path="${script_path}"/"$(basename "$0")".mangaocr + python3 -m venv "${venv_path}" + source "${venv_path}"/bin/activate + pip3 install -r "${script_path}"/"$(basename "$0")".requirements >/dev/null 2>&1 + ;; +*) + notify "unknown METHOD ${method}" + exit 1 + ;; +esac + +notify "select some japanese text" +run_ocr diff --git a/bin/grimocr.requirements b/bin/grimocr.requirements new file mode 100644 index 0000000..05d33ce --- /dev/null +++ b/bin/grimocr.requirements @@ -0,0 +1 @@ +manga-ocr >=0.1.7 |