Utilisateur:Alex brollo/djvu text to hOCR

# -*- coding: utf-8 -*-
# by Alex brollo - 2013
import os
import re
import json

'''Schemi livelli
<span class='ocrx_word' id='word_2' title='bbox 1743 931 1971 981'>TEORIA</span>
<span class='ocr_line' id='line_1' title="bbox 1502 918 3625 982">...</span>
<p class='ocr_par' dir='ltr' id='par_1' title="bbox 1502 918 3625 982">...</p>
<div class='ocr_carea' id='block_1_1' title="bbox 1502 917 3625 983">...</div>
<div class='ocr_page' id='page_1' title='image \'tiff/opere_2 - 0099.tif\'; bbox 0 0 5186 7330; ppageno 0'>...</div>

Gli id di ogni livello sono numerati progressivamente: word_1, word_2...
L'id del livello area è anomalo: block_1_1, block_2_2....
Nel title c'è sempre "bbox numero numero numero numero" tranne che in
livello pagina dove c'è "nome file; bbox numero numero numero numero"

'''

lista=type([])
stringa=type("")
s_unicode=type(u"")
tuple=type(())
dic={"word":"<span class='ocrx_word' id='word_%numero' title='bbox %coordinate'>%testo</span>\n",\
     "line":"<span class='ocr_line' id='line_%numero' title='bbox %coordinate'>\n",\
     "para":"<p class='ocr_par' dir='ltr' id='par_%numero' title='bbox %coordinate'>\n",\
     "region":"<div class='ocr_carea' id='block_%numero_%numero' title='bbox %coordinate'>\n",\
     "column":"",
     "page":"<div class='ocr_page' id='page_1' title='image \'immagine.tif\'; bbox %coordinate; ppageno 0'>\n"}




def djvu2hOCR (page,djvu="Opere matematiche (Cremona) III.djvu"):
    # calls leggiPaginaDjvu and gets hCR transform of mapped text layer
    # Please consider
    # 1. these are test scripts
    # 2. DjvuLibre routines need to be called by a os.system() call
    # 3. put a IA djvu into the same folder of this script
    # 4. by now it's tested interactively into a Idle interface
    #
    # 
    pyObject=leggiPagDjvu(page,djvu)
    hocrText=hOCR(pyObject)
    return hocrText
    

# extracts djvu-lisp code form a IA djvu file
# pagina: no. of the page
# djvu: djvu file name (in same directory)
# dependancies: DjvuLibre routines
def leggiPagDjvu(pagina,djvu):
    command='djvused "#file" -e "select #pagina;print-txt" > out.txt'\
             .replace("#file",djvu)\
             .replace("#pagina",str(pagina))
    print "Comando:",command
    os.system(command)
    testo=unicode(open("out.txt").read(),"utf-8")
    oggetto=json.loads(json.dumps(pageObj(testo)))
    return oggetto


# gets a python object containing djvu mapped text data
# returns a hOCR htlm (body html content only) that can be uploaded into a wiki page
def hOCR(pagina):
    vuota=False
    testo=u""
    nword=nline=npara=nregion=ncolumn=npage=1
    lclose=[]
    for i1 in range(len(pagina)): #livello pagina
        if i1==0:
            testo+=dic["page"].replace("%coordinate",pagina[0].split(" ",1)[1])
            #print pagina[0],testo
            lclose.insert(0,"</div>")
            continue
        for i2 in range(len(pagina[i1])): #livello colonna
            if i2==0:
                x=""
                if pagina[i1][1]=="":
                    vuota=True
                continue
            if pagina[i1][1]!="":
                for i3 in range(len(pagina[i1][i2])): #livello regione
                    if i3==0:
                        #print i1,i2
                        testo+=dic["region"].replace("%coordinate",pagina[i1][i2][0].split(" ",1)[1]).replace("%numero",str(nregion))
                        #print pagina[i1][i2][0],testo
                        nregion+=1
                        lclose.insert(0,"    </div>\n")
                        continue
                    for i4 in range(len(pagina[i1][i2][i3])): #livello paragrafo
                        if i4==0:
                            #print i1,i2,i3
                            testo+=dic["para"].replace("%coordinate",pagina[i1][i2][i3][0].split(" ",1)[1]).replace("%numero",str(npara))
                            #print pagina[i1][i2][i3][0],testo
                            npara+=1
                            lclose.insert(0,"        </p>\n")
                            continue
                        for i5 in range(len(pagina[i1][i2][i3][i4])): #livello linea
                            if i5==0:
                                #print i1,i2,i3,i4
                                testo+=dic["line"].replace("%coordinate",pagina[i1][i2][i3][i4][0].split(" ",1)[1]).replace("%numero",str(nline))
                                #print pagina[i1][i2][i3][i4][0],testo
                                nline+=1
                                lclose.insert(0,"            </span>\n")
                                continue
                            testo+=dic["word"].replace("%coordinate",pagina[i1][i2][i3][i4][i5][0].split(" ",1)[1])\
                                .replace("%numero",str(nword))\
                                .replace("%testo",pagina[i1][i2][i3][i4][i5][1])
                            nword+=1
                        testo+=lclose.pop(0) #chiusura linea
                    testo+=lclose.pop(0)
                
                testo+=lclose.pop(0)
            
        
    
    testo+=lclose.pop(0) #chiusura pagina
    return testo
                
                
			
    
# riceve un elemento oggetto python lo trasforma in elemento hOCR
def hOCR1(oggetto): 
    if type(oggetto[1]) in (stringa,s_unicode):
        tipo,coordinate=oggetto[0].split(" ",1)
        oggetto=dic[tipo][0].replace("%testo",oggetto[1]).replace("%coordinate",coordinate)
    return oggetto
    
    

# data una pagina djvu-lisp la trasforma in oggetto python (tuple annidata)
def pageObj(testo):
    p=re.compile("(page|column|region|para|line|word)\s\d+\s\d+\s\d+\s\d+")
    iteratore=p.finditer(testo)
    for i in iteratore:
        testo=testo.replace(i.group(),'"'+i.group()+'",',1)
    testo=testo.split("\n")
    for i in range(len(testo)):
        testo[i]=testo[i].strip()
    testo="\n".join(testo)
    testo=testo.replace(")\n(","),(\n").replace("\n","")
    oggetto=eval(testo)
    return oggetto
    

# lancia tesseract su una serie di pagine e ottiene hOCR modificato (solo html interno a body)
def tess(ini,fin,lang="ita",base="opere_2 - #pag.tif",hocr=True,inDir="tiff/",outDir="hOCR/"):
    for i in range(ini,fin):
        pagina=str(i).zfill(4)
        pagIn='"'+inDir+base.replace("#pag",pagina)+'"'
        pagOut=pagIn.replace(inDir,outDir).replace(".tif","")
        
        command="tesseract #pagin -l #lang tessOut hocr"\
                 .replace("#lang",lang)\
                 .replace("#pagin",pagIn)
        
        print command
        os.system(command)
        testo=open("tessOut.html").read()
        header=find_stringa(testo,"<?xml","<body>\n",1)
        footer=find_stringa(testo,"</body>","</html>",1)
        if header!="":
            testo=testo.replace(header,"")
        if footer!="":
            testo=testo.replace(footer,"")
        pagOut=pagIn[1:-1].replace(inDir,outDir).replace(".tif",".html")
        print pagOut
        open(pagOut,"w").write(testo)                      
    return
        


def djvuTxt(pagina, djvu="numi.djvu", base="Rivista italiana di numismatica 1892.djvu"):
    nomePagina=wikipedia.Page("it","Pagina:"+base+"/"+str(pagina))
    os.system("djvutxt -page=#pagina numi.djvu pagina.txt".replace("#pagina",str(pagina)))
    testo=unicode(open("pagina.txt").read(),"utf-8")\
           .replace(u"\x1f\x1d\x0b","\n").replace(u"\x0c","").replace(u"\x1f","\n")
    #print testo
    if not nomePagina.exists():
        nomePagina.put(testo,comment="caricamento OCR via bot")
        
    return #testo

def x():
    trattino=u'\u2015'
    return "―"

# Nuova versione, gestisce i tag annidati; x e' la parte "aspecifica" del
# tag di apertura (es: {{ cercando {{Intestazione| )
def find_stringa(stringa,idi,idf,dc=0,x=None,side="left"):
    if side=="right":
        idip=stringa.rfind(idi)
    else:
        idip=stringa.find(idi)
    idfp=stringa.find(idf,idip+len(idi))+len(idf)
    if idip>-1 and idfp>0:
        if x!=None:
            while stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                if stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                    idfp=stringa.find(idf,idfp)+len(idf)
                
        if dc==0:
            vvalore=stringa[idip+len(idi):idfp-len(idf)]
        else:
            vvalore=stringa[idip:idfp]
    else:
        vvalore=""
    return vvalore

def produci_lista(testo,idi,idf,dc=1,inizio=None):
    t=testo[:]
    lista=[]
    while not find_stringa(t,idi,idf,1,inizio)=="":
        el=find_stringa(t,idi,idf,1,inizio)
        t=t.replace(el,"",1)
        if dc==0:
            el=find_stringa(el,idi,idf,0,inizio)
        lista.append(el)
    return lista


# for others uses
def djvudump(djvu):
    comando="djvudump \"#djvu\" > \"#dump\""\
             .replace("#djvu",djvu)\
             .replace("#dump",djvu.replace(".djvu",".dump"))
    print comando
    os.system(comando)
    return