Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

103 rindas
3.5KB

  1. """Extract and OCR every image referenced by an EPUB's reading spine.
  2. Usage: python tools/ocr_epub_images.py "<Book Title>"
  3. Writes extracted images to library/<Book Title>/images/ and OCR results to
  4. library/<Book Title>/ocr-embedded-images.json.
  5. """
  6. import json
  7. import posixpath
  8. import sys
  9. import zipfile
  10. from collections import Counter
  11. from pathlib import Path
  12. from xml.etree import ElementTree as ET
  13. import cv2
  14. import numpy as np
  15. from lxml import html
  16. from rapidocr_onnxruntime import RapidOCR
  17. ROOT = Path(__file__).resolve().parent.parent / "library"
  18. XLINK = "{http://www.w3.org/1999/xlink}href"
  19. def epub_spine(epub):
  20. container = ET.fromstring(epub.read("META-INF/container.xml"))
  21. opf_path = container.find(".//{*}rootfile").attrib["full-path"]
  22. opf = ET.fromstring(epub.read(opf_path))
  23. base = posixpath.dirname(opf_path)
  24. manifest = {
  25. item.attrib["id"]: item.attrib
  26. for item in opf.findall(".//{*}manifest/{*}item")
  27. }
  28. return [
  29. posixpath.normpath(posixpath.join(base, manifest[item.attrib["idref"]]["href"]))
  30. for item in opf.findall(".//{*}spine/{*}itemref")
  31. ]
  32. def image_refs(epub, documents):
  33. refs = []
  34. for document in documents:
  35. root = html.fromstring(epub.read(document))
  36. for element in root.xpath("//*[local-name()='img' or local-name()='image']"):
  37. href = element.get("src") or element.get(XLINK) or element.get("xlink:href") or element.get("href")
  38. if href:
  39. refs.append(posixpath.normpath(posixpath.join(posixpath.dirname(document), href)))
  40. return refs
  41. def main(book):
  42. book_root = ROOT / book
  43. epub_path = book_root / "source-file.epub"
  44. output_path = book_root / "ocr-embedded-images.json"
  45. images_root = book_root / "images"
  46. images_root.mkdir(exist_ok=True)
  47. engine = RapidOCR()
  48. with zipfile.ZipFile(epub_path) as epub:
  49. documents = epub_spine(epub)
  50. refs = image_refs(epub, documents)
  51. counts = Counter(refs)
  52. unique_refs = list(dict.fromkeys(refs))
  53. recovered = (
  54. json.loads(output_path.read_text(encoding="utf-8"))
  55. if output_path.exists()
  56. else {}
  57. )
  58. print(f"EPUB images for {book}: {len(unique_refs)} unique, {len(refs)} references", flush=True)
  59. for index, ref in enumerate(unique_refs, start=1):
  60. cached = recovered.get(ref)
  61. if cached and (images_root / Path(cached["asset"]).name).exists():
  62. print(f"{index}/{len(unique_refs)} {ref}: cached", flush=True)
  63. continue
  64. data = epub.read(ref)
  65. asset_name = Path(ref).name
  66. (images_root / asset_name).write_bytes(data)
  67. image = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
  68. if image is None:
  69. lines = []
  70. else:
  71. result, _ = engine(image)
  72. lines = [item[1].strip() for item in (result or []) if item[1].strip()]
  73. recovered[ref] = {
  74. "asset": f"/library/{book}/images/{asset_name}",
  75. "references": counts[ref],
  76. "text": "\n".join(lines),
  77. }
  78. print(f"{index}/{len(unique_refs)} {ref}: {len(lines)} OCR lines", flush=True)
  79. output_path.write_text(
  80. json.dumps(recovered, ensure_ascii=False, indent=2) + "\n",
  81. encoding="utf-8",
  82. newline="\n",
  83. )
  84. print(f"Wrote {output_path} and {images_root}", flush=True)
  85. if __name__ == "__main__":
  86. main(sys.argv[1])

Powered by TurnKey Linux.