z230
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import fitz
|
import fitz
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
BASE_DIR = Path(r"z:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeFlattenStamp")
|
BASE_DIR = Path(r"u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeFlattenStamp")
|
||||||
|
|
||||||
def flatten_pdf_rasterize(input_pdf: Path):
|
def flatten_pdf_rasterize(input_pdf: Path):
|
||||||
print(f"Processing: {input_pdf.name}")
|
print(f"Processing: {input_pdf.name}")
|
||||||
|
|||||||
74
AdobeFlatten/20 FlattenAdobe.py
Normal file
74
AdobeFlatten/20 FlattenAdobe.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import fitz
|
||||||
|
from pathlib import Path
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
|
||||||
|
HOSTNAME = platform.node().upper()
|
||||||
|
|
||||||
|
if HOSTNAME in {"SESTRA", "POHODA"}:
|
||||||
|
DROPBOX_DRIVE = Path(r"Z:\\")
|
||||||
|
elif HOSTNAME == "Z230":
|
||||||
|
DROPBOX_DRIVE = Path(r"U:\\")
|
||||||
|
else:
|
||||||
|
print(f"❌ Unknown computer name: {HOSTNAME}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
BASE_DIR = (
|
||||||
|
DROPBOX_DRIVE
|
||||||
|
/ "Dropbox"
|
||||||
|
/ "Ordinace"
|
||||||
|
/ "Dokumentace_ke_zpracování"
|
||||||
|
/ "AdobeFlattenStamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
def flatten_pdf_rasterize_overwrite(input_pdf: Path):
|
||||||
|
print(f"Processing: {input_pdf.name}")
|
||||||
|
|
||||||
|
doc = fitz.open(input_pdf)
|
||||||
|
new_doc = fitz.open()
|
||||||
|
|
||||||
|
for page in doc:
|
||||||
|
pix = page.get_pixmap(dpi=400)
|
||||||
|
new_page = new_doc.new_page(
|
||||||
|
width=page.rect.width,
|
||||||
|
height=page.rect.height
|
||||||
|
)
|
||||||
|
new_page.insert_image(new_page.rect, pixmap=pix)
|
||||||
|
|
||||||
|
# safe overwrite
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
suffix=".pdf",
|
||||||
|
delete=False,
|
||||||
|
dir=input_pdf.parent
|
||||||
|
) as tmp:
|
||||||
|
tmp_path = Path(tmp.name)
|
||||||
|
|
||||||
|
new_doc.save(tmp_path, deflate=True)
|
||||||
|
new_doc.close()
|
||||||
|
doc.close()
|
||||||
|
|
||||||
|
os.replace(tmp_path, input_pdf)
|
||||||
|
print(f" ✔ Overwritten: {input_pdf.name}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"🖥 Running on: {HOSTNAME}")
|
||||||
|
print(f"📁 Base directory: {BASE_DIR}")
|
||||||
|
|
||||||
|
if not BASE_DIR.exists():
|
||||||
|
print("❌ Base directory does not exist!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
pdfs = list(BASE_DIR.glob("*.pdf"))
|
||||||
|
if not pdfs:
|
||||||
|
print("No PDF files found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
for pdf in pdfs:
|
||||||
|
flatten_pdf_rasterize_overwrite(pdf)
|
||||||
|
|
||||||
|
print("\n✅ All files processed and originals overwritten.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
145
MakeSmallerPDF/06 OCR Tesseract.py
Normal file
145
MakeSmallerPDF/06 OCR Tesseract.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
import pytesseract
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# --- NASTAVENÍ ---
|
||||||
|
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
|
||||||
|
OUTPUT_FOLDER = os.path.join(INPUT_FOLDER, '_HOTOVO_ULTIMATE')
|
||||||
|
|
||||||
|
# Cesta k Tesseractu
|
||||||
|
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
||||||
|
|
||||||
|
# 1. Jak moc "ošklivý" (malý) má být viditelný obrázek?
|
||||||
|
VISUAL_DPI = 150
|
||||||
|
VISUAL_THRESHOLD = 150
|
||||||
|
|
||||||
|
# 2. Jak kvalitní má být předloha pro čtení (OCR)?
|
||||||
|
OCR_DPI = 300
|
||||||
|
|
||||||
|
|
||||||
|
def setup_tesseract():
|
||||||
|
if not os.path.exists(PATH_TO_TESSERACT):
|
||||||
|
print(f"CHYBA: Tesseract nenalezen na: {PATH_TO_TESSERACT}")
|
||||||
|
return False
|
||||||
|
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_rc_from_text(text):
|
||||||
|
"""Najde RČ v textu a vrátí ho bez lomítka."""
|
||||||
|
# Hledá formát: 6 čísel, volitelně lomítko/mezera, 3-4 čísla
|
||||||
|
matches = re.findall(r'\b(\d{6})\s*[\/]?\s*(\d{3,4})\b', text)
|
||||||
|
for head, tail in matches:
|
||||||
|
full_rc = f"{head}{tail}"
|
||||||
|
# Základní kontrola délky a čísel
|
||||||
|
if len(full_rc) in [9, 10] and full_rc.isdigit():
|
||||||
|
return full_rc
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def process_ultimate_method():
|
||||||
|
if not setup_tesseract():
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.exists(OUTPUT_FOLDER):
|
||||||
|
os.makedirs(OUTPUT_FOLDER)
|
||||||
|
|
||||||
|
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
|
||||||
|
print(f"Startuji 'ULTIMATE' zpracování {len(files)} souborů.")
|
||||||
|
print("-" * 70)
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
input_path = os.path.join(INPUT_FOLDER, filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"Zpracovávám: {filename} ...")
|
||||||
|
|
||||||
|
doc_src = fitz.open(input_path)
|
||||||
|
final_doc = fitz.open()
|
||||||
|
|
||||||
|
detected_rc = None
|
||||||
|
|
||||||
|
for page_num, page in enumerate(doc_src):
|
||||||
|
# --- KROK A: OCR (Vysoká kvalita pro čtení) ---
|
||||||
|
# 1. Vyrenderujeme kvalitní obrázek pro Tesseract
|
||||||
|
mat_ocr = fitz.Matrix(OCR_DPI / 72, OCR_DPI / 72)
|
||||||
|
pix_ocr = page.get_pixmap(matrix=mat_ocr, colorspace=fitz.csGRAY)
|
||||||
|
img_ocr = Image.frombytes("L", [pix_ocr.width, pix_ocr.height], pix_ocr.samples)
|
||||||
|
|
||||||
|
# 2. Tesseract vytvoří PDF stránku (Text + Velký obrázek)
|
||||||
|
pdf_bytes = pytesseract.image_to_pdf_or_hocr(img_ocr, extension='pdf', lang='ces')
|
||||||
|
|
||||||
|
# 3. Otevřeme tuto stránku v paměti
|
||||||
|
ocr_page_doc = fitz.open("pdf", pdf_bytes)
|
||||||
|
ocr_page = ocr_page_doc[0]
|
||||||
|
|
||||||
|
# Přečteme text pro hledání RČ
|
||||||
|
if not detected_rc:
|
||||||
|
text_content = ocr_page.get_text()
|
||||||
|
detected_rc = get_rc_from_text(text_content)
|
||||||
|
|
||||||
|
# --- KROK B: Visual (Nízká kvalita pro oči/úsporu) ---
|
||||||
|
# 1. Vyrenderujeme malý obrázek
|
||||||
|
mat_vis = fitz.Matrix(VISUAL_DPI / 72, VISUAL_DPI / 72)
|
||||||
|
pix_vis = page.get_pixmap(matrix=mat_vis, colorspace=fitz.csGRAY)
|
||||||
|
img_vis = Image.frombytes("L", [pix_vis.width, pix_vis.height], pix_vis.samples)
|
||||||
|
|
||||||
|
# 2. Binarizace (Threshold)
|
||||||
|
img_vis_bw = img_vis.point(lambda x: 255 if x > VISUAL_THRESHOLD else 0, mode='1')
|
||||||
|
|
||||||
|
# 3. Uložíme do bufferu
|
||||||
|
buffer_vis = io.BytesIO()
|
||||||
|
img_vis_bw.save(buffer_vis, format="PNG", optimize=True)
|
||||||
|
|
||||||
|
# --- KROK C: Výměna (The Switch) ---
|
||||||
|
# 1. Smažeme velký obrázek z Tesseract stránky (text zůstane)
|
||||||
|
images = ocr_page.get_images()
|
||||||
|
if images:
|
||||||
|
xref = images[0][0]
|
||||||
|
ocr_page.delete_image(xref)
|
||||||
|
|
||||||
|
# 2. Vložíme náš malý obrázek
|
||||||
|
# Použijeme rect (rozměry) stránky, aby obrázek seděl přesně na celou stranu
|
||||||
|
ocr_page.insert_image(ocr_page.rect, stream=buffer_vis.getvalue(), keep_proportion=True)
|
||||||
|
|
||||||
|
# 3. Vložíme upravenou stránku do finálního PDF
|
||||||
|
final_doc.insert_pdf(ocr_page_doc)
|
||||||
|
|
||||||
|
# --- KROK D: Uložení ---
|
||||||
|
if detected_rc:
|
||||||
|
new_filename = f"{detected_rc}.pdf"
|
||||||
|
print(f" -> Nalezeno RČ: {detected_rc}")
|
||||||
|
else:
|
||||||
|
new_filename = f"{os.path.splitext(filename)[0]}_ocr.pdf"
|
||||||
|
print(f" -> RČ nenalezeno.")
|
||||||
|
|
||||||
|
# Řešení duplicit (pokud soubor už existuje)
|
||||||
|
counter = 1
|
||||||
|
base_name_check = os.path.splitext(new_filename)[0]
|
||||||
|
while os.path.exists(os.path.join(OUTPUT_FOLDER, new_filename)):
|
||||||
|
new_filename = f"{base_name_check}_{counter}.pdf"
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
output_path = os.path.join(OUTPUT_FOLDER, new_filename)
|
||||||
|
|
||||||
|
# Uložení s kompresí
|
||||||
|
final_doc.save(output_path, garbage=4, deflate=True)
|
||||||
|
final_doc.close()
|
||||||
|
doc_src.close()
|
||||||
|
|
||||||
|
# Výpis velikosti
|
||||||
|
size_kb = os.path.getsize(output_path) / 1024
|
||||||
|
print(f" -> Uloženo: {new_filename} ({size_kb:.1f} kB)")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CHYBA u {filename}: {e}")
|
||||||
|
|
||||||
|
print("\nHOTOVO.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
process_ultimate_method()
|
||||||
205
MakeSmallerPDF/07 OCR tesseract lepší.py
Normal file
205
MakeSmallerPDF/07 OCR tesseract lepší.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
import pytesseract
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import fdb # Firebird database library
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# KONFIGURACE
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
# 1. Cesty k souborům
|
||||||
|
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
|
||||||
|
OUTPUT_FOLDER = os.path.join(INPUT_FOLDER, '_HOTOVO_MEDICUS')
|
||||||
|
|
||||||
|
# 2. Tesseract OCR
|
||||||
|
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
||||||
|
|
||||||
|
# 3. Kvalita výstupu (Ultimate metoda)
|
||||||
|
VISUAL_DPI = 150 # Pro zobrazení (malé)
|
||||||
|
VISUAL_THRESHOLD = 150 # Práh černé
|
||||||
|
OCR_DPI = 300 # Pro čtení (velké)
|
||||||
|
|
||||||
|
# 4. Databáze MEDICUS (Firebird)
|
||||||
|
DB_CONFIG = {
|
||||||
|
'host': "192.168.1.4",
|
||||||
|
'port': 3050,
|
||||||
|
'database': r"z:\Medicus 3\data\MEDICUS.FDB",
|
||||||
|
'user': "SYSDBA",
|
||||||
|
'password': "masterkey",
|
||||||
|
'charset': "WIN1250" # Čeština ve Windows
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# FUNKCE
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
def setup_tesseract():
|
||||||
|
if not os.path.exists(PATH_TO_TESSERACT):
|
||||||
|
print(f"CHYBA: Tesseract nenalezen na: {PATH_TO_TESSERACT}")
|
||||||
|
return False
|
||||||
|
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_rc_candidates(text):
|
||||||
|
"""Vrátí seznam RČ nalezených v textu, očistěných od mezer a lomítek."""
|
||||||
|
candidates = set()
|
||||||
|
# Regex bere i mezery: 75 05 12 / 1234
|
||||||
|
pattern = r'\b\d{2}\s*\d{2}\s*\d{2}\s*[\/]?\s*\d{3,4}\b'
|
||||||
|
matches = re.findall(pattern, text)
|
||||||
|
|
||||||
|
for match in matches:
|
||||||
|
# Odstraníme vše kromě čísel -> vznikne čisté RČ pro DB
|
||||||
|
clean = re.sub(r'[^\d]', '', match)
|
||||||
|
if len(clean) in [9, 10]:
|
||||||
|
candidates.add(clean)
|
||||||
|
return list(candidates)
|
||||||
|
|
||||||
|
|
||||||
|
def get_patient_from_db(rc_clean):
|
||||||
|
"""
|
||||||
|
Vrátí (True, "Prijmeni, Jmeno") pokud najde RČ v tabulce KAR.
|
||||||
|
"""
|
||||||
|
con = None
|
||||||
|
try:
|
||||||
|
con = fdb.connect(**DB_CONFIG)
|
||||||
|
cur = con.cursor()
|
||||||
|
|
||||||
|
# Medicus má RČ bez lomítka, takže se ptáme rovnou
|
||||||
|
sql = "SELECT prijmeni, jmeno FROM kar WHERE rodcis = ?"
|
||||||
|
cur.execute(sql, (rc_clean,))
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
if row:
|
||||||
|
# row[0] = Prijmeni, row[1] = Jmeno
|
||||||
|
# .strip() je nutný, databáze vrací mezery na konci (CHAR field)
|
||||||
|
prijmeni = str(row[0]).strip()
|
||||||
|
jmeno = str(row[1]).strip()
|
||||||
|
|
||||||
|
formatted_name = f"{prijmeni}, {jmeno}"
|
||||||
|
return True, formatted_name
|
||||||
|
else:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [DB ERROR] {e}")
|
||||||
|
return False, None
|
||||||
|
finally:
|
||||||
|
if con:
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
|
||||||
|
def process_medicus_final():
|
||||||
|
if not setup_tesseract():
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.exists(OUTPUT_FOLDER):
|
||||||
|
os.makedirs(OUTPUT_FOLDER)
|
||||||
|
|
||||||
|
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
|
||||||
|
print(f"Startuji zpracování {len(files)} souborů.")
|
||||||
|
print(f"Výstupní formát: 'RC Prijmeni, Jmeno.pdf'")
|
||||||
|
print("-" * 70)
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
input_path = os.path.join(INPUT_FOLDER, filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"Zpracovávám: {filename}")
|
||||||
|
|
||||||
|
doc_src = fitz.open(input_path)
|
||||||
|
final_doc = fitz.open()
|
||||||
|
|
||||||
|
found_rc = None
|
||||||
|
found_name = None
|
||||||
|
|
||||||
|
# --- 1. PRŮCHOD STRÁNKAMI ---
|
||||||
|
for page_num, page in enumerate(doc_src):
|
||||||
|
|
||||||
|
# A) PŘÍPRAVA OCR VRSTVY (High Res)
|
||||||
|
mat_ocr = fitz.Matrix(OCR_DPI / 72, OCR_DPI / 72)
|
||||||
|
pix_ocr = page.get_pixmap(matrix=mat_ocr, colorspace=fitz.csGRAY)
|
||||||
|
img_ocr = Image.frombytes("L", [pix_ocr.width, pix_ocr.height], pix_ocr.samples)
|
||||||
|
|
||||||
|
# Tesseract vytvoří PDF stránku
|
||||||
|
pdf_bytes = pytesseract.image_to_pdf_or_hocr(img_ocr, extension='pdf', lang='ces')
|
||||||
|
ocr_page_doc = fitz.open("pdf", pdf_bytes)
|
||||||
|
ocr_page = ocr_page_doc[0]
|
||||||
|
|
||||||
|
# B) HLEDÁNÍ PACIENTA (pokud ještě nemáme)
|
||||||
|
if not found_rc:
|
||||||
|
text = ocr_page.get_text()
|
||||||
|
candidates = get_rc_candidates(text)
|
||||||
|
|
||||||
|
for cand in candidates:
|
||||||
|
print(f" -> Ověřuji v DB: {cand} ...", end=" ")
|
||||||
|
exists, name_str = get_patient_from_db(cand)
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
print(f"NALEZEN: {name_str}")
|
||||||
|
found_rc = cand
|
||||||
|
found_name = name_str
|
||||||
|
break # Máme ho!
|
||||||
|
else:
|
||||||
|
print("Nenalezen.")
|
||||||
|
|
||||||
|
# C) PŘÍPRAVA VIZUÁLNÍ VRSTVY (Low Res - Zmenšení)
|
||||||
|
mat_vis = fitz.Matrix(VISUAL_DPI / 72, VISUAL_DPI / 72)
|
||||||
|
pix_vis = page.get_pixmap(matrix=mat_vis, colorspace=fitz.csGRAY)
|
||||||
|
img_vis = Image.frombytes("L", [pix_vis.width, pix_vis.height], pix_vis.samples)
|
||||||
|
# Threshold
|
||||||
|
img_vis_bw = img_vis.point(lambda x: 255 if x > VISUAL_THRESHOLD else 0, mode='1')
|
||||||
|
|
||||||
|
buffer_vis = io.BytesIO()
|
||||||
|
img_vis_bw.save(buffer_vis, format="PNG", optimize=True)
|
||||||
|
|
||||||
|
# D) PROHOZENÍ OBRÁZKŮ (Ultimate trick)
|
||||||
|
images = ocr_page.get_images()
|
||||||
|
if images:
|
||||||
|
xref = images[0][0]
|
||||||
|
ocr_page.delete_image(xref) # Smaže velký
|
||||||
|
|
||||||
|
# Vloží malý
|
||||||
|
ocr_page.insert_image(ocr_page.rect, stream=buffer_vis.getvalue(), keep_proportion=True)
|
||||||
|
|
||||||
|
# Přidá stránku do finálního PDF
|
||||||
|
final_doc.insert_pdf(ocr_page_doc)
|
||||||
|
|
||||||
|
# --- 2. ULOŽENÍ SOUBORU ---
|
||||||
|
if found_rc and found_name:
|
||||||
|
# Formát: 1234567890 NOVAK, JAN.pdf
|
||||||
|
# Odstraníme případné nepovolené znaky ve jméně (pro jistotu)
|
||||||
|
safe_name = re.sub(r'[\\/*?:"<>|]', "", found_name)
|
||||||
|
new_filename = f"{found_rc} {safe_name}.pdf"
|
||||||
|
else:
|
||||||
|
new_filename = f"{os.path.splitext(filename)[0]}_neovereno.pdf"
|
||||||
|
|
||||||
|
# Řešení konfliktů (kdyby soubor už existoval)
|
||||||
|
counter = 1
|
||||||
|
base_name = os.path.splitext(new_filename)[0]
|
||||||
|
while os.path.exists(os.path.join(OUTPUT_FOLDER, new_filename)):
|
||||||
|
new_filename = f"{base_name}_{counter}.pdf"
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
output_path = os.path.join(OUTPUT_FOLDER, new_filename)
|
||||||
|
|
||||||
|
final_doc.save(output_path, garbage=4, deflate=True)
|
||||||
|
final_doc.close()
|
||||||
|
doc_src.close()
|
||||||
|
|
||||||
|
size_kb = os.path.getsize(output_path) / 1024
|
||||||
|
print(f" -> Uloženo: {new_filename} ({size_kb:.1f} kB)")
|
||||||
|
print("-" * 70)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CHYBA: {e}")
|
||||||
|
|
||||||
|
print("\nHOTOVO.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
process_medicus_final()
|
||||||
66
MakeSmallerPDF/2 MakeSmaller.py
Normal file
66
MakeSmallerPDF/2 MakeSmaller.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def compress_and_grayscale_pdf(input_path, quality=60, dpi=150):
|
||||||
|
"""
|
||||||
|
input_path: Cesta k souboru
|
||||||
|
quality: Kvalita JPG komprese (1-100). 60 je dobrý kompromis pro čitelnost a velikost.
|
||||||
|
dpi: Rozlišení. 150 DPI stačí pro čtení na monitoru/běžný tisk. Pro menší velikost zkuste 96 nebo 72.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Kontrola existence souboru
|
||||||
|
if not os.path.exists(input_path):
|
||||||
|
print(f"Chyba: Soubor nebyl nalezen: {input_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Otevření zdrojového PDF
|
||||||
|
doc = fitz.open(input_path)
|
||||||
|
new_doc = fitz.open() # Vytvoření nového prázdného PDF
|
||||||
|
|
||||||
|
print(f"Zpracovávám: {os.path.basename(input_path)}")
|
||||||
|
print(f"Původní velikost: {os.path.getsize(input_path) / 1024:.2f} KB")
|
||||||
|
|
||||||
|
for page_num, page in enumerate(doc):
|
||||||
|
# Nastavení matice pro změnu rozlišení (DPI)
|
||||||
|
# Standardní PDF má 72 DPI. Zoom = požadované DPI / 72
|
||||||
|
zoom = dpi / 72
|
||||||
|
matrix = fitz.Matrix(zoom, zoom)
|
||||||
|
|
||||||
|
# 1. Renderování stránky do obrázku (Pixmap)
|
||||||
|
# colorspace=fitz.csGRAY zajistí převod do černobílé (Grayscale)
|
||||||
|
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
|
||||||
|
|
||||||
|
# 2. Vytvoření nové stránky v cílovém dokumentu se stejnými rozměry
|
||||||
|
# Používáme původní rozměry stránky (rect), aby se PDF "nezmenšilo" vizuálně na monitoru
|
||||||
|
new_page = new_doc.new_page(width=page.rect.width, height=page.rect.height)
|
||||||
|
|
||||||
|
# 3. Vložení zmenšeného a odbarveného obrázku zpět
|
||||||
|
# stream=pix.tobytes("jpg") zajistí silnou kompresi
|
||||||
|
new_page.insert_image(page.rect, stream=pix.tobytes("jpg", jpg_quality=quality))
|
||||||
|
|
||||||
|
# Vytvoření názvu výstupního souboru
|
||||||
|
output_path = input_path.replace(".pdf", "_bw_small.pdf")
|
||||||
|
|
||||||
|
# Uložení s garbage collection (odstranění nepotřebných dat) a deflací
|
||||||
|
new_doc.save(output_path, garbage=4, deflate=True)
|
||||||
|
new_doc.close()
|
||||||
|
doc.close()
|
||||||
|
|
||||||
|
# Výpis výsledku
|
||||||
|
new_size = os.path.getsize(output_path)
|
||||||
|
print(f"Hotovo. Uloženo jako: {output_path}")
|
||||||
|
print(f"Nová velikost: {new_size / 1024:.2f} KB")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Došlo k chybě: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- SPUŠTĚNÍ ---
|
||||||
|
# Použití raw stringu (r''), aby Python neinterpretoval zpětná lomítka jako escape znaky
|
||||||
|
file_path = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
|
||||||
|
|
||||||
|
# Můžete experimentovat s parametry.
|
||||||
|
# Pokud bude text nečitelný, zvyšte dpi na 200. Pokud je soubor moc velký, snižte quality na 40.
|
||||||
|
compress_and_grayscale_pdf(file_path, quality=50, dpi=120)
|
||||||
37
MakeSmallerPDF/3 MakeSmaller.py
Normal file
37
MakeSmallerPDF/3 MakeSmaller.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
|
||||||
|
file_path = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
|
||||||
|
|
||||||
|
doc = fitz.open(file_path)
|
||||||
|
|
||||||
|
print(f"Soubor: {file_path}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
for i, page in enumerate(doc):
|
||||||
|
# Získání seznamu obrázků na stránce
|
||||||
|
images = page.get_images(full=True)
|
||||||
|
|
||||||
|
# Rozměry stránky v palcích (PDF body / 72)
|
||||||
|
page_w_inch = page.rect.width / 72
|
||||||
|
page_h_inch = page.rect.height / 72
|
||||||
|
|
||||||
|
if images:
|
||||||
|
for img in images:
|
||||||
|
xref = img[0]
|
||||||
|
base_img = doc.extract_image(xref)
|
||||||
|
w = base_img["width"]
|
||||||
|
h = base_img["height"]
|
||||||
|
ext = base_img["ext"]
|
||||||
|
|
||||||
|
# Výpočet DPI (Pixely / Palce)
|
||||||
|
dpi_x = w / page_w_inch
|
||||||
|
dpi_y = h / page_h_inch
|
||||||
|
|
||||||
|
print(f"Strana {i + 1}:")
|
||||||
|
print(f" - Rozměry obrázku: {w} x {h} px")
|
||||||
|
print(f" - Formát: {ext}")
|
||||||
|
print(f" - Reálné DPI: cca {int(dpi_x)}")
|
||||||
|
else:
|
||||||
|
print(f"Strana {i + 1}: Žádný vložený obrázek (vektorový text).")
|
||||||
|
|
||||||
|
print("-" * 40)
|
||||||
87
MakeSmallerPDF/4 MakeSmaller.py
Normal file
87
MakeSmallerPDF/4 MakeSmaller.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
|
# --- NASTAVENÍ ---
|
||||||
|
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
|
||||||
|
|
||||||
|
# 1. Prahové hodnoty: Zúžíme výběr na nejpravděpodobnější rozsah
|
||||||
|
THRESHOLDS = [110, 130, 150, 170]
|
||||||
|
|
||||||
|
# 2. DPI Varianty k testování
|
||||||
|
# 131 = Přesná polovina originálu (váš nápad)
|
||||||
|
# 150 = Standard
|
||||||
|
# 200 = Vysoká kvalita
|
||||||
|
# 262 = Originál (žádná ztráta detailů, jen ztráta barev)
|
||||||
|
DPI_LIST = [131, 150, 200, 262]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_final_matrix():
|
||||||
|
if not os.path.exists(INPUT_FILE):
|
||||||
|
print(f"Chyba: Soubor nenalezen.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Příprava složky
|
||||||
|
base_folder = os.path.dirname(INPUT_FILE)
|
||||||
|
filename = os.path.basename(INPUT_FILE)
|
||||||
|
name_without_ext = os.path.splitext(filename)[0]
|
||||||
|
|
||||||
|
output_dir = os.path.join(base_folder, "_TEST_DPI_MATH")
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
|
print(f"Generuji varianty do: {output_dir}")
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"{'DPI':<5} | {'Práh':<6} | {'Velikost':<12} | {'Poznámka'}")
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
doc = fitz.open(INPUT_FILE)
|
||||||
|
|
||||||
|
for dpi in DPI_LIST:
|
||||||
|
# Přednačtení stránek v daném DPI
|
||||||
|
pages_at_dpi = []
|
||||||
|
for page in doc:
|
||||||
|
zoom = dpi / 72
|
||||||
|
matrix = fitz.Matrix(zoom, zoom)
|
||||||
|
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
|
||||||
|
pages_at_dpi.append(pix)
|
||||||
|
|
||||||
|
for t in THRESHOLDS:
|
||||||
|
new_doc = fitz.open()
|
||||||
|
|
||||||
|
for i, pix in enumerate(pages_at_dpi):
|
||||||
|
# Binarizace
|
||||||
|
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
|
||||||
|
img_bw = img.point(lambda x: 255 if x > t else 0, mode='1')
|
||||||
|
|
||||||
|
# Uložení
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
img_bw.save(buffer, format="PNG", optimize=True)
|
||||||
|
|
||||||
|
# Vložení zpět
|
||||||
|
orig_rect = doc[i].rect
|
||||||
|
new_page = new_doc.new_page(width=orig_rect.width, height=orig_rect.height)
|
||||||
|
new_page.insert_image(orig_rect, stream=buffer.getvalue())
|
||||||
|
|
||||||
|
# Uložení
|
||||||
|
output_name = f"dpi{dpi}_t{t}.pdf"
|
||||||
|
output_path = os.path.join(output_dir, output_name)
|
||||||
|
new_doc.save(output_path, garbage=4, deflate=True)
|
||||||
|
new_doc.close()
|
||||||
|
|
||||||
|
# Výpis
|
||||||
|
size_kb = os.path.getsize(output_path) / 1024
|
||||||
|
|
||||||
|
note = ""
|
||||||
|
if dpi == 131: note = "(Polovina originálu)"
|
||||||
|
if dpi == 262: note = "(Originální rozlišení)"
|
||||||
|
|
||||||
|
print(f"{dpi:<5} | {t:<6} | {size_kb:<9.2f} KB | {note}")
|
||||||
|
|
||||||
|
doc.close()
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_final_matrix()
|
||||||
95
MakeSmallerPDF/5 MakeSmaller.py
Normal file
95
MakeSmallerPDF/5 MakeSmaller.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
# --- VAŠE VÍTĚZNÉ NASTAVENÍ ---
|
||||||
|
CHOSEN_DPI = 150
|
||||||
|
CHOSEN_THRESHOLD = 150
|
||||||
|
|
||||||
|
# Cesty
|
||||||
|
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
|
||||||
|
OUTPUT_SUBFOLDER = '_HOTOVO'
|
||||||
|
|
||||||
|
|
||||||
|
def process_all_files():
|
||||||
|
# Vytvoření výstupní složky
|
||||||
|
output_dir = os.path.join(INPUT_FOLDER, OUTPUT_SUBFOLDER)
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
|
# Nalezení všech PDF (ignorujeme již hotové v podsložkách)
|
||||||
|
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
|
||||||
|
|
||||||
|
print(f"Startuji zpracování {len(files)} souborů.")
|
||||||
|
print(f"Nastavení: DPI={CHOSEN_DPI}, Práh={CHOSEN_THRESHOLD}")
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
input_path = os.path.join(INPUT_FOLDER, filename)
|
||||||
|
|
||||||
|
# Přidáme '_bw' do názvu, aby se to nepletlo
|
||||||
|
name_without_ext = os.path.splitext(filename)[0]
|
||||||
|
output_filename = f"{name_without_ext}_bw.pdf"
|
||||||
|
output_path = os.path.join(output_dir, output_filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Zpracování jednoho souboru
|
||||||
|
process_single_pdf(input_path, output_path)
|
||||||
|
|
||||||
|
# Výpis výsledku
|
||||||
|
orig_size = os.path.getsize(input_path) / 1024
|
||||||
|
new_size = os.path.getsize(output_path) / 1024
|
||||||
|
ratio = (1 - (new_size / orig_size)) * 100
|
||||||
|
|
||||||
|
print(f"[OK] {filename}")
|
||||||
|
print(f" {orig_size:.1f} kB -> {new_size:.1f} kB (úspora {ratio:.0f} %)")
|
||||||
|
success_count += 1
|
||||||
|
|
||||||
|
# --- VOLITELNÉ: SMAZÁNÍ ORIGINÁLU ---
|
||||||
|
# Pokud chcete, aby skript po úspěchu smazal původní velký soubor,
|
||||||
|
# odkomentujte následující řádek (odstraňte mřížku #):
|
||||||
|
# os.remove(input_path)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[CHYBA] {filename}: {e}")
|
||||||
|
|
||||||
|
print("-" * 60)
|
||||||
|
print(f"Hotovo. Úspěšně zpracováno {success_count} z {len(files)} souborů.")
|
||||||
|
print(f"Výstupy jsou ve složce: {output_dir}")
|
||||||
|
|
||||||
|
|
||||||
|
def process_single_pdf(input_path, output_path):
|
||||||
|
doc = fitz.open(input_path)
|
||||||
|
new_doc = fitz.open()
|
||||||
|
|
||||||
|
for page in doc:
|
||||||
|
# 1. Renderování stránky (Downsampling na 150 DPI)
|
||||||
|
zoom = CHOSEN_DPI / 72
|
||||||
|
matrix = fitz.Matrix(zoom, zoom)
|
||||||
|
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
|
||||||
|
|
||||||
|
# 2. Binarizace (Threshold 150)
|
||||||
|
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
|
||||||
|
img_bw = img.point(lambda x: 255 if x > CHOSEN_THRESHOLD else 0, mode='1')
|
||||||
|
|
||||||
|
# 3. Uložení 1-bitového obrázku
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
img_bw.save(buffer, format="PNG", optimize=True)
|
||||||
|
|
||||||
|
# 4. Vložení do nového PDF
|
||||||
|
# Zachováme fyzické rozměry stránky (aby se netiskla jako známka)
|
||||||
|
new_page = new_doc.new_page(width=page.rect.width, height=page.rect.height)
|
||||||
|
new_page.insert_image(page.rect, stream=buffer.getvalue())
|
||||||
|
|
||||||
|
# Uložení s maximální kompresí
|
||||||
|
new_doc.save(output_path, garbage=4, deflate=True)
|
||||||
|
new_doc.close()
|
||||||
|
doc.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
process_all_files()
|
||||||
67
MakeSmallerPDF/99 TestOCR.py
Normal file
67
MakeSmallerPDF/99 TestOCR.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
import pytesseract
|
||||||
|
from PIL import Image
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# --- NASTAVENÍ ---
|
||||||
|
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
||||||
|
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\6ed31e44-0e7d-4118-8912-c3e583781459.pdf'
|
||||||
|
|
||||||
|
# Nastavíme Tesseract
|
||||||
|
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
|
||||||
|
|
||||||
|
|
||||||
|
def debug_ocr_output():
|
||||||
|
if not os.path.exists(INPUT_FILE):
|
||||||
|
print(f"Soubor nenalezen: {INPUT_FILE}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ANALÝZA SOUBORU: {os.path.basename(INPUT_FILE)}")
|
||||||
|
doc = fitz.open(INPUT_FILE)
|
||||||
|
|
||||||
|
# Projdeme první stranu (RČ bývá tam)
|
||||||
|
for i, page in enumerate(doc):
|
||||||
|
if i > 0: break # Stačí nám 1. strana pro test
|
||||||
|
|
||||||
|
print(f"\n--- STRANA {i + 1} (300 DPI) ---")
|
||||||
|
|
||||||
|
# 1. Renderování ve vysoké kvalitě (stejně jako v 'Ultimate' skriptu)
|
||||||
|
# Pokud je sken nekvalitní, Tesseract potřebuje velké rozlišení
|
||||||
|
zoom = 300 / 72
|
||||||
|
matrix = fitz.Matrix(zoom, zoom)
|
||||||
|
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
|
||||||
|
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
|
||||||
|
|
||||||
|
# 2. OCR - Získání surového textu
|
||||||
|
# config='--psm 3' je standardní automatická segmentace stránky
|
||||||
|
raw_text = pytesseract.image_to_string(img, lang='ces', config='--psm 3')
|
||||||
|
|
||||||
|
print(">>> SUROVÝ TEXT Z TESSERACTU (ZAČÁTEK) <<<")
|
||||||
|
print("-" * 50)
|
||||||
|
print(raw_text)
|
||||||
|
print("-" * 50)
|
||||||
|
print(">>> SUROVÝ TEXT Z TESSERACTU (KONEC) <<<")
|
||||||
|
|
||||||
|
# 3. Test Regexu na tomto textu
|
||||||
|
print("\n--- TEST HLEDÁNÍ RČ ---")
|
||||||
|
|
||||||
|
# Standardní Regex
|
||||||
|
strict_pattern = r'\b\d{6}\s*[\/]?\s*\d{3,4}\b'
|
||||||
|
strict_matches = re.findall(strict_pattern, raw_text)
|
||||||
|
print(f"Přísný filtr (očekává jen čísla): {strict_matches}")
|
||||||
|
|
||||||
|
# Volnější Regex (hledá i chyby OCR jako 'O' místo '0' nebo 'l' místo '1')
|
||||||
|
# \d -> číslice
|
||||||
|
# [O0] -> nula nebo O
|
||||||
|
# [lI1] -> jednička, malé L nebo velké i
|
||||||
|
loose_pattern = r'\b[0-9O]{6}\s*[\/ilI1]?\s*[0-9O]{3,4}\b'
|
||||||
|
loose_matches = re.findall(loose_pattern, raw_text)
|
||||||
|
|
||||||
|
if loose_matches and not strict_matches:
|
||||||
|
print(f"⚠️ POZOR: Našel jsem RČ jen pomocí volného filtru (obsahuje překlepy OCR): {loose_matches}")
|
||||||
|
print(" -> Bude potřeba upravit čistící funkci.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
debug_ocr_output()
|
||||||
67
MakeSmallerPDF/991 test oCR.py
Normal file
67
MakeSmallerPDF/991 test oCR.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import fitz # PyMuPDF
|
||||||
|
import pytesseract
|
||||||
|
from PIL import Image
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# --- NASTAVENÍ ---
|
||||||
|
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
||||||
|
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\9b79f621-30ad-4468-85fe-6f2fd76289ce.pdf'
|
||||||
|
|
||||||
|
# Nastavíme Tesseract
|
||||||
|
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
|
||||||
|
|
||||||
|
|
||||||
|
def debug_ocr_output():
|
||||||
|
if not os.path.exists(INPUT_FILE):
|
||||||
|
print(f"Soubor nenalezen: {INPUT_FILE}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ANALÝZA SOUBORU: {os.path.basename(INPUT_FILE)}")
|
||||||
|
doc = fitz.open(INPUT_FILE)
|
||||||
|
|
||||||
|
# Projdeme první stranu (RČ bývá tam)
|
||||||
|
for i, page in enumerate(doc):
|
||||||
|
if i > 0: break # Stačí nám 1. strana pro test
|
||||||
|
|
||||||
|
print(f"\n--- STRANA {i + 1} (300 DPI) ---")
|
||||||
|
|
||||||
|
# 1. Renderování ve vysoké kvalitě (stejně jako v 'Ultimate' skriptu)
|
||||||
|
# Pokud je sken nekvalitní, Tesseract potřebuje velké rozlišení
|
||||||
|
zoom = 300 / 72
|
||||||
|
matrix = fitz.Matrix(zoom, zoom)
|
||||||
|
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
|
||||||
|
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
|
||||||
|
|
||||||
|
# 2. OCR - Získání surového textu
|
||||||
|
# config='--psm 3' je standardní automatická segmentace stránky
|
||||||
|
raw_text = pytesseract.image_to_string(img, lang='ces', config='--psm 3')
|
||||||
|
|
||||||
|
print(">>> SUROVÝ TEXT Z TESSERACTU (ZAČÁTEK) <<<")
|
||||||
|
print("-" * 50)
|
||||||
|
print(raw_text)
|
||||||
|
print("-" * 50)
|
||||||
|
print(">>> SUROVÝ TEXT Z TESSERACTU (KONEC) <<<")
|
||||||
|
|
||||||
|
# 3. Test Regexu na tomto textu
|
||||||
|
print("\n--- TEST HLEDÁNÍ RČ ---")
|
||||||
|
|
||||||
|
# Standardní Regex
|
||||||
|
strict_pattern = r'\b\d{6}\s*[\/]?\s*\d{3,4}\b'
|
||||||
|
strict_matches = re.findall(strict_pattern, raw_text)
|
||||||
|
print(f"Přísný filtr (očekává jen čísla): {strict_matches}")
|
||||||
|
|
||||||
|
# Volnější Regex (hledá i chyby OCR jako 'O' místo '0' nebo 'l' místo '1')
|
||||||
|
# \d -> číslice
|
||||||
|
# [O0] -> nula nebo O
|
||||||
|
# [lI1] -> jednička, malé L nebo velké i
|
||||||
|
loose_pattern = r'\b[0-9O]{6}\s*[\/ilI1]?\s*[0-9O]{3,4}\b'
|
||||||
|
loose_matches = re.findall(loose_pattern, raw_text)
|
||||||
|
|
||||||
|
if loose_matches and not strict_matches:
|
||||||
|
print(f"⚠️ POZOR: Našel jsem RČ jen pomocí volného filtru (obsahuje překlepy OCR): {loose_matches}")
|
||||||
|
print(" -> Bude potřeba upravit čistící funkci.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
debug_ocr_output()
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user