#!/usr/bin/env python3
"""Recorta del escaneo la banda donde esta la lectura del impreso.

Para que sirve. Una nota que dice «el impreso pone Balahhit» es una afirmacion.
La misma nota con el recorte de la pagina al lado es una prueba, y el lector no
tiene que creerse nada. Los escaneos ya estan y cada caso se adjudico mirando
esa misma pagina a 400-600 ppp, asi que el material existe: falta servirlo.

Como localiza. `pdftotext -bbox-layout` da la caja de cada palabra en puntos PDF;
se busca la palabra del ancla en la pagina indicada, se convierte a pixeles con
la escala del render y se recorta una banda de tres o cuatro lineas alrededor.
Se recorta a lo ancho entero: una banda de texto se lee, un rectangulo pegado a
la palabra no.

Uso:
    python3 recortar_nota.py <pdf> <pagina> <palabra> <salida.png> [--ppp 220]
"""
import re, sys, subprocess, pathlib


def caja(pdf, pagina, palabra):
    xml = subprocess.run(['pdftotext', '-bbox-layout', '-f', str(pagina), '-l', str(pagina),
                          pdf, '-'], capture_output=True, text=True).stdout
    pag = re.search(r'<page width="([\d.]+)" height="([\d.]+)"', xml)
    if not pag: return None
    W, H = float(pag.group(1)), float(pag.group(2))
    # la palabra puede venir partida por guion a final de linea; se prueba entera
    # y luego por su primera mitad
    for busca in (palabra, palabra[:max(4, len(palabra) // 2)]):
        m = re.search(r'<word xMin="([\d.]+)" yMin="([\d.]+)" xMax="([\d.]+)" yMax="([\d.]+)">'
                      + re.escape(busca), xml)
        if m:
            return [float(g) for g in m.groups()] + [W, H]
    return None


def main():
    if len(sys.argv) < 5: print(__doc__); return 1
    pdf, pagina, palabra, salida = sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4]
    ppp = int(sys.argv[sys.argv.index('--ppp') + 1]) if '--ppp' in sys.argv else 220
    from PIL import Image
    tmp = '/tmp/_recorte'
    subprocess.run(['pdftoppm', '-f', str(pagina), '-l', str(pagina), '-r', str(ppp),
                    '-png', pdf, tmp], check=True)
    png = next(iter(sorted(pathlib.Path('/tmp').glob('_recorte*.png'))), None)
    if not png: print('no se pudo renderizar la pagina'); return 1
    im = Image.open(png)
    c = caja(pdf, pagina, palabra)
    if not c:
        print(f'AVISO: «{palabra}» no aparece en la capa de texto de la p.{pagina}; '
              f'se guarda la pagina entera')
        im.save(salida); png.unlink(); return 0
    x0, y0, x1, y1, W, H = c
    sy = im.height / H
    # tres lineas por encima y por debajo, para que la frase se entienda sola
    alto = (y1 - y0) * sy
    im.crop((0, max(0, int(y0 * sy - alto * 2.2)),
             im.width, min(im.height, int(y1 * sy + alto * 2.2)))).save(salida)
    png.unlink()
    print(f'{salida}  (p.{pagina} de {pathlib.Path(pdf).name}, «{palabra}»)')
    return 0


if __name__ == '__main__':
    sys.exit(main())
