Jump to content

User:Alex brollo/python/djvu.py

From Wikisource
#!/usr/bin/python
# -*- coding: utf-8 -*-
# introducing pyquery

import pywikibot as wikipedia
import pywikibot.data.api as api
import pickle,gzip, sys, os, re, json 
from urllib import FancyURLopener
from scripts import *
#from pyquery import PyQuery



class MyOpener(FancyURLopener):
    version = version = 'User-Agent: Alex (+http://it.wikisource.org/wiki/Utente:Alex_brollo)'

opener=MyOpener()
lista=type("")
stringa=type("")
s_unicode=type(u"")
tuple=type(())
commons=wikipedia.getSite("commons","commons")
caratteriVietatiNomeFile='\/?:*"><|'

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"}

'''
routines per la gestione dei file djvu

commonsGrab : dato il nome di un  file djvu lo scarica da Commons nella cartella djvu
leggiPagDjvu: legge lo strato testo di una pagina djvu con djvutxt 
pageObj     : trasforma una pagina lisp-like in un oggetto python
hOCR        : trasforma un oggetto python in un hOCR (xml)
hOCR1       : variante
id2title    : ricava il titolo dall'id e inverso

'''

def id2title(id=None,title=None):
    r=api.Request(site=commons,action="query",prop="info")
    if id != None:
        r["pageids"]=id
    else:
        r["titles"]=title
    data=r.submit()
    id=data["query"]["pages"].keys()[0]
    if title==None:
        title=data["query"]["pages"][id]["title"]
    
    return {"id":id, "title":title}
    

    pageOby()
    

def commonsGrab(nomefile="File:Georgiche.djvu"):
    id=id2title(title=nomefile)["id"]
    commons=wikipedia.getSite("commons","commons")
    immagine=wikipedia.ImagePage(commons,nomefile)
    url=immagine.fileUrl()
    grab(url,"djvu/"+id+".djvu")
    return id

# 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


# dato un oggetto python-pagina lo trasforma in hOCR
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
    
#da un file djvu estrae un oggetto python a liste annidate di una pagina 
def leggiPagDjvu(pagina,djvu="Opere matematiche (Cremona) III.djvu"):
    command='djvused "#file" -e "select #pagina;print-txt" > out/out.txt'\
             .replace("#file",djvu)\
             .replace("#pagina",str(pagina))
    print "Comando:",command
    os.system(command)
    testo=unicode(open("out/out.txt").read(),"utf-8")
    oggetto=json.loads(json.dumps(pageObj(testo)))
    return oggetto
    
# dato un oggetto python lista lo trasforma in un oggetto python tuple
def list2tuple(oggettoLista):
    # ....
    return oggettoTuple


#dato un oggetto python tuple lo trasforma in un djvu lisp utf-8
def tuple2djvu(oggettoTuple):
    # ....
    return djvuLisp
    
       

# 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 "―"


def apriXml(gz="ricordidilondrad00deamuoft_abbyy.gz"):
    testo=gzip.open(gz,"r").read()
    pagine=produci_lista(testo,"<page ","</page>",1)
    return pagine 

def scriviPagina(p): # pagina è un oggetto pyquery page
    t=''
    for i1 in range(len(p("block"))):
        blocco=p("block").eq(i1)
        if blocco.attr("blockType")=="Text":
            for i2 in range(len(blocco("par"))):
                par=blocco("par").eq(i2)
                for i3 in range(len(par("line"))):
                    line=par("line").eq(i3)    
                    t+=" ".join(analizzaLinea(line))+"\n"
                t+="\n"
                
    return t
			

def analizzaLinea(linea): # linea è oggetto pyquery; page è la main class
    ln=[]
    w=[]
    caratteri=linea("charParams")
    l=eval(linea(caratteri[0]).attr("l"))
    t=eval(linea(caratteri[0]).attr("t"))
    r=eval(linea(caratteri[0]).attr("r"))
    b=eval(linea(caratteri[0]).attr("b"))
    for i in range(len(caratteri)):
        if i>0:
            if linea(caratteri[i]).attr("wordStart")=="true":
                ln.append([w,str(l)+" "+str(t)+" "+str(r)+" "+str(b)])
                l=eval(linea(caratteri[i]).attr("l"))
                t=eval(linea(caratteri[i]).attr("t"))
                r=eval(linea(caratteri[i]).attr("r"))
                b=eval(linea(caratteri[i]).attr("b"))
                
                
                w=[]
        w.append(caratteri[i])
        t=min(eval(linea(caratteri[i]).attr("t")),t)
        r=max(eval(linea(caratteri[i]).attr("r")),r)
        b=max(eval(linea(caratteri[i]).attr("b")),b)
    ln.append([w,str(l)+" "+str(t)+" "+str(r)+" "+str(b)])
    parole=[]
    parola=''
    
    for i in ln:
        for j in i[0]:
            parola+=linea(j).text()
        if linea(i[0][0]).attr("wordPenalty")!="0":
            parola='<span style="color:red" data-xy="'+i[1]+'">'+parola+"</span>"
        parole.append(parola)
        parola=''
        
    return parole

    
    

# opens a well-formed xml of a page adding original headet and documenta tag
# to <page> tag content to study xml structure
def xmlPage(base="ricordidilondrad00deamuoft_abbyy",n=1):
    lp=carica_pcl(base,"")
    xml=gzip.open(base+".gz","rb")
    xml.seek(lp[n][0])
    pagina=lp[0][0]+xml.read(lp[n][1])+lp[0][1]
    open("pagina"+str(n)+".xml","w").write(pagina)

    return

    


# all together.....
def pagineAbbyy(base="ricordidilondrad00deamuoft_abbyy", ws="Ricordi di Londra.djvu"):
    testiPagine=f=gzip.open(base+".gz","rb")
    l=carica_pcl(base,"")
    listaTesti=[]
    for pagine in range(1,len(l)):
        f.seek(l[pagine][0])
        testo=f.read(l[pagine][1])
        testoWiki=testoBlocchi(parseText2(testo))
        print pagine, len(testoWiki)                         
        listaTesti.append(["Pagina:"+ws,pagine,testoWiki])
    listaTesti=[""]+listaTesti
    salva_pcl(listaTesti,"listaTestiAbbyy","")
    
    return
def testAlign(c=10):
    ldjvu=carica_pcl("listaTestiDjvu","")
    labbyy=carica_pcl("listaTestiAbbyy","")
    for a in range(1,len(ldjvu)):
        for i in range(a,len(labbyy)):
            if simil(ldjvu[a][1],labbyy[i][2])>40 and not len(ldjvu[a][1])<20:
                #print a,i
                ldjvu[a][2]=labbyy[i][2]
                break
        if ldjvu[a][2]=="":
            ldjvu[a][2]=ldjvu[a][1]
    salva_pcl(ldjvu,"listaTestiDjvu","")
    return "Fatto"

def newcarica(baseWiki,ini,fin):
    ldjvu=carica_pcl("listaTestiDjvu","")
    if fin>len(ldjvu):
        fin=len(djvu)
    for pag in range(ini,fin):
        
        pagina=wikipedia.Page("it",baseWiki+"/"+str(pag))
        testoWiki=unicode(ldjvu[pag][2],"utf-8")
        if pagina.exists():
            noincludes=produci_lista(pagina.get(),"<noinclude>","</noinclude>",1)
            header=noincludes[0]
            footer=noincludes[len(noincludes)-1]
            user=find_stringa(header,'user="','"',1)
            header=header.replace(user,'user="Alebot"')
            testoWiki=header+testoWiki+footer
                                    
            pagina.put(testoWiki)
    return
        

			    
def pagineDjvu(fileDjvu="ricordidilondrad00deamuoft.djvu"):
    comando='djvutxt -detail=page "#f"> djvutxt.txt'
    os.system(comando.replace("#f",fileDjvu))
    t=open("djvutxt.txt").read()
    l=produci_lista(t,"(",")\n",1)
    for i in range(len(l)):
        l[i]=l[i].replace(find_stringa(l[i],"(page",'"',1),'')\
              .replace(find_stringa(l[i],'"',"\n",1,side="right"),'')\
              .replace("\\n","\n")\
              .replace("\\037","\n")\
              .replace("\\035","")\
              .replace("\\013","")\
              .replace(" \n","\n")
        l[i]=[i+1,l[i],""]
    l=['']+l
    salva_pcl(l,"listaTestiDjvu","")
    return  # lista dei testi delle pagine in utf-8; caratteri speciali
              # riconvertiti
              

def grab(url,output=None):
    page=opener.open(url+"?action=render")
    content=page.read()
    if output!=None:
        open(output,"wb").write(content)
        return "Fatto"
    else:
        return content

def IAgrab(url="http://archive.org/details/LeGeorgicheDiVirgilioCommentateDaEttoreStampiniPartePrimaLibriIEIi"):
    link=find_stringa(grab(url),"<b>All Files","</a>",1)
    link=find_stringa(link, 'href="','"',0)
    l=[]
    for i in produci_lista(grab(link),'href="','"',0):
        if i.endswith("abbyy.gz"):
            print "Grabbing abbyy.gz..."
            urlAbbyy=link+"/"+i
            grab(urlAbbyy,i)
        if i.endswith(".djvu"):
            print "Grabbing djvu..."
            urlDjvu=link+"/"+i
            grab(urlDjvu,i)
    base=urlAbbyy.replace(link+"/")
    parsePages1(base)
    
    return "Fatto"





# gets a html/xml tag code by tag name
def find_element(tag,text):
    elc=find_stringa(text,"<"+tag,">",1)
    element=find_stringa(text,elc,"</"+tag+">",1)
    return element


# gets xml of a page
def parseText2(testoPagina):
    # page=open(pagina).read()
    parole=[]
    blocchi=produci_lista(testoPagina,"<block","</block>",1)
    for i0 in range(len(blocchi)):
        blocchi[i0]=produci_lista(blocchi[i0],"<region","</text>",1)
        for i1 in range(len(blocchi[i0])):
            blocchi[i0][i1]=produci_lista(blocchi[i0][i1],"<par","</par>",1)
            for i2 in range(len(blocchi[i0][i1])):
                blocchi[i0][i1][i2]=produci_lista(blocchi[i0][i1][i2],"<line","</line>",1)
                for i3 in range(len(blocchi[i0][i1][i2])):
                    blocchi[i0][i1][i2][i3]=produci_lista(blocchi[i0][i1][i2][i3],"<charParams","</charParams>",1)
                    # blocchi[i0][i1][i2][i3] è la lista di caratteri per ogni elemento blocco.paragrafo.linea
                    parole=[]
                    parola=[]
                    for car in blocchi[i0][i1][i2][i3]: #per ogni carattere:
                        if valPar("wordStart",car)=="true":
                            if parola!=[]:
                                parole.append(parola)
                            parola=[]
                        parola.append(car)
                    parole.append(parola)
                    blocchi[i0][i1][i2][i3]=parole
    return blocchi




def valPar(par,testo):
    par=find_stringa(testo,par+'="','"',0)
    return par


def testoBlocchi(blocchi,apos=True):
    t=""
    for blocco in blocchi:        # livello blocchi
        for regione in blocco:
            for paragrafo in regione:         # livello paragrafi
                for linea in paragrafo:     #livello linea
                    for parola in linea: #livello carattere
                        tt=''
                        span=False
                        for carattere in parola:
                            tt+=find_stringa(carattere,">","<",0)
                            if valPar("wordPenalty",carattere)!="0":
                                span=True
                                spanText='<span style="color:red;">'
                        if span:
                            tt=spanText+tt+"</span>"
                        t+=tt
                            
                    t+="\n"
                t+="\n"
    return t


# new parsing page algorithm
def parsePages1(f="georgiche-stampini_abbyy.gz"):
    #l=[f]    # list of offset/length of page code into xml file; l[0] empty by now
              # to align l index to djvu page number
    offset=0  # offset initialization
    xml=gzip.open(f).read() # loading the whole fileinto a string variable
    header=xml[0:xml.find("<page")]
    footer="\n</document>"
    l=[[header,footer]]
    while True:
        offset=xml.find("<page",offset)
        if offset==-1:
            break
        endoffset=xml.find("</page>",offset)+7
        l.append([offset,endoffset-offset])
        print offset,endoffset-offset
        offset=endoffset
    # saving list of [offset, length] into offsets.pcl
    # no more need to save pages xml into files
    # to rietrieve code simply
    #    f=open(file_xml,"r+")
    #    f.seek(l[page_number][0])
    #    pagexml=f.read(l[page_number][1])
    
    salva_pcl(l,f.replace(".gz",""),"")
    return "Fatto"

        

# 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


def carica_pcl(nome_file, folder="dati/"):
    nome_file=folder+nome_file+".pcl"
    f=open(nome_file)
    contenuto=pickle.load(f)
    f.close()
    return contenuto

def salva_pcl(variabile,nome_file="dato",folder="dati/"):
    nome_file=folder+nome_file+".pcl"
    f=open(nome_file,"w")
    pickle.dump(variabile, f)
    f.close()
    print "Variabile salvata nel file "+nome_file
    return

####

def caricaPagina(numero,baseGz="ricordidilondrad00deamuoft_abbyy"):
    l=carica_pcl(baseGz,"")
    f=gzip.open(baseGz+".gz", "rb")
    f.seek(l[numero][0])
    testo=f.read(l[numero][1])
    p=PyQuery(testo)
    return p

    

def caricaPagine(baseGz="ricordidilondrad00deamuoft_abbyy"):
    l=carica_pcl(baseGz,"")
    f=gzip.open(l[0], "rb")
    lt=[""]
    for i in l[1:]:
        f.seek(i[0])
        t=f.read(i[1])
        blocchi=parseText2(t)
        lt.append(testoBlocchi(blocchi))
    return lt


def simil(a,b,c=10):
    punti=0
    if len(a)<=c or len(b)<=c:
        return -1
    for i in range(len(a)-c):
        if a[i:i+c] in b:
            punti+=1
    
    somiglianza=punti*100/(len(a)-c)
    return somiglianza