diff --git a/Analyse.adoc b/Analyse.adoc deleted file mode 100644 index 1431da7273b19dacfc24db061c1fa241dce129f2..0000000000000000000000000000000000000000 --- a/Analyse.adoc +++ /dev/null @@ -1,55 +0,0 @@ -= Analyse des résultats de pdf2blocs -Stéphan Bernard <stephan.bernard@irstea.fr> - -== Ordonnancement des blocs -Le premier élément qui saute aux yeux est un problème dans l'ordre des blocs -de la sortie. Par exemple, la page suivante : - -image:img/01_page.png[Page de BSV] - -reçoit les blocs dans l'ordre suivant (après suppression d'éléments parasites) : - -image:img/02_page_blocs.png[Ordre de lecture] - -[NOTE] -Lier un paragraphe à son titre devient difficile. Il n'est donc pas permis -de déduire une relation implicite d'une description qui ferait référence -à l'élément cité comme titre. - -== Gestion des caractères gras et indentation -Deux erreurs sont observées sur les paragraphes suivants : - -image:img/03_paragraphe.png[Ordre de lecture] - -La majeure partie du texte se retrouve dans deux blocs successifs : ----- -Nos stations n’ont pas enregistré de pluie mais des averses orageuses ont -localement été observées entre samedi 14 et dimanche 15/07. Elles ont pu -provoquer des contaminations mais, avec le temps sec, leur expression -devrait être limitée. ----- -et ----- -encore complètement atteinte. -tardives avec les pluies annoncées pour la fin de semaine. ----- - -[NOTE] -Les portions de phrase manquantes n'ont pas été retrouvées dans le document -(pas même faisant l'objet d'un autre bloc). - -Deux choix sont probablement à l'origine de ce phénomène : - -* L'absence d'espace vertical entre les deux paragraphes n'a pas permis -d'interpréter la première ligne du second paragraphe comme étant une -première ligne, et son non-alignement dû à l'indentation l'a exclue -de l'ensemble (exclusion destinée à gérer le multi-colonnes). - -* La mise en gras de texte en cours de ligne («Soyez donc vigilant») -faisant l'objet d'un changement de police de caractère a exclu cette -portion du bloc, mais la ligne suivante étant correctement alignée, -le changement de police de caractère n'est pas pris en compte. - -[NOTE] -À d'autres endroits du document la mise en gras n'a pas provoqué de -sortie de bloc. Le phénomène est donc un peu plus complexe à interpréter. diff --git a/Notes_SB.asciidoc b/Notes_SB.asciidoc deleted file mode 100644 index 34d2fb55187f4a938ed69d19fd651ab252d7fee9..0000000000000000000000000000000000000000 --- a/Notes_SB.asciidoc +++ /dev/null @@ -1,86 +0,0 @@ -Notes à propos du code de Tayeb -=============================== -Stéphan Bernard <stephan.bernard@irstea.fr> - -Tests ------ -Récupération d'un jeu de 195 BSVs sur la viticulture, dans -`/home/phan/Boulot/Ontology/BSV/tmp/viti`. Création d'une archive -dans le répertoire parent, pour pouvoir se permettre d'y mettre le zbeul. - -Exécution du code de Tayeb : - -[source,sh] -------------------------- -java -jar pdftoxml.jar ../tmp/viti/ -------------------------- - -Problèmes rencontrés -~~~~~~~~~~~~~~~~~~~~ - -Erreur d'exécution -^^^^^^^^^^^^^^^^^^ -Pour le fichier `BSV_viti_bilan_2018_cle8556d4.pdf`, isolé dans un répertoire -`FaitPlanter`. Il semblerait que le xml généré par pdf2html ne soit pas -consistant. À creuser. - -Problème avec les caractères gras -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Rencontré dans le fichier `20180801_LOR_BSV_Viticulture_cle857461.pdf` -en page 2 (les retours à la ligne du fichier pdf sont ici matérialisés par -un nouveau paragraphe) : - -==== -La coloration des baies a débuté timidement sur les parcelles du réseau. Elles se sont également ramollies et vont - -maintenant entrer en maturation. Le stade moyen observé est compris entre L33 « fermeture » et *L 35 « début* - -*véraison ».* - -En 2017, la fermeture s’était achevée vers le 7 aout avec la véraison. -==== - -La partie en gras en fin de ligne a disparu, mais "véraison »", qui est en gras -est présent, sans doute parce que le mot est en début de ligne. - -[source,xml] ----- -<bloc page="2" top="609" left="59" height="17" width="777" font="0" lignes="4"> - <text top="609" left="59" width="777" height="17" font="0">La coloration (…) vont</text> - <text top="630" left="59" width="681" height="17" font="0">maintenant (…) compris entre L33 « fermeture » et</text> - <text top="652" left="59" width="79" height="17" font="9">véraison ».</text> - <text top="673" left="59" width="466" height="17" font="0">En 2017, la fermeture (…)).</text> -</bloc> ----- - -Diagnostic -++++++++++ -Très probablement, le changement de _font_ dû au gras (on passe de `font="0"` -à `font="9"`), avec un non-alignement (autre valeur de `left`) en est la cause. -Voici les _font_ correspondantes : - -[source,xml] ----- -<fontspec id="0" size="14" family="ABCDEE+Calibri" color="#000000"/> -<fontspec id="9" size="14" family="ABCDEE+Calibri,Bold" color="#000000"/> ----- - -Si la mise en gras n'était pas en fin de paragraphe, la suite de la ligne, -à partir du premier caractère non gras, devrait être escamoté. - -Solutions -+++++++++ -Compliquées. Reconnaître qu'une _font_ est juste une mise en gras est possible, -mais le fichier généré par pdf2html créant deux blocs de texte du fait du -changement de police de caractères, on se retrouve toujours avec une portion -de texte non alignée. - - -Intéressant : -------------- -Regarder la sortie de - -[source,sh] ----- -pdftotext -bbox-layout ../tmp/viti/20180801_LOR_BSV_Viticulture_cle857461.pdf ----- diff --git a/README.md b/README.md index a5c933f527f07344f3de6faf033973e70db3b330..4424ab2111e6f99b31ef051c57091d1a4c451dac 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,3 @@ La fonction qui permet de construire les blocs est la fonction bar. Elle prend e -> src/ressources/mots_vides.txt : liste de mots vides en français ; -> src/ressources/ponctuation.txt : liste de caractères de ponctuation. - -### Idées, TODO, ... -- Plutôt que d'enlever les pied de page, les marquer. -- De même, marquer le "texte petit". -- Dans les blocs, passer de ligne à ligne à phrase par -phrase. \ No newline at end of file diff --git a/img/01_page.png b/img/01_page.png deleted file mode 100644 index 9347cd5eb18bec5e1812f317dcc17cac7e4a94e3..0000000000000000000000000000000000000000 Binary files a/img/01_page.png and /dev/null differ diff --git a/img/02_page_blocs.png b/img/02_page_blocs.png deleted file mode 100644 index 7207b02f159945ccd4ea56424350423869a5046a..0000000000000000000000000000000000000000 Binary files a/img/02_page_blocs.png and /dev/null differ diff --git a/img/03_paragraphe.png b/img/03_paragraphe.png deleted file mode 100644 index 2ed76a8b7a8d714a33f916a9845e56240ee9bf7a..0000000000000000000000000000000000000000 Binary files a/img/03_paragraphe.png and /dev/null differ diff --git a/src/py/analyse.py b/src/py/analyse.py deleted file mode 100644 index 5ce096577bf18201f165eea7a6ac2cd2195d520f..0000000000000000000000000000000000000000 --- a/src/py/analyse.py +++ /dev/null @@ -1,330 +0,0 @@ -# https://docs.python.org/fr/3/library/xml.etree.elementtree.html#module-xml.etree.ElementTree -# -# Lit les fichiers xml générés par pdftotext : -# pdftotext -bbox-layout ../tmp/viti/20180801_LOR_BSV_Viticulture_cle857461.pdf -# et fait une sortie destinées à être lue rapidement sur un terminal, -# avec une délimitation des blocs. -# -import xml.etree.ElementTree as ET -import os -import sys -import re - -# https://unix.stackexchange.com/questions/238180/execute-shell-commands-in-python -import subprocess - -### Parameters -CMD_PDFTOTEXT = '/usr/sbin/pdftotext' -CMD_PDFTOHTML = '/usr/sbin/pdftohtml' - - -### Entering MAIN process - -#### Getting pdf filename as a parameter. -if (len(sys.argv) < 1): - print("-U-> Usage : python analyse.py <fichier_pdf>") - sys.exit(-1) -#print('Parsing %s' % sys.argv[1]) - -basename = os.path.splitext(sys.argv[1])[0] - -#### Calling pdftotext command and getting its standard output -cmd = [CMD_PDFTOTEXT, '-bbox-layout', '-eol', 'unix', '%s.pdf' % basename, '-'] -proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -o, e = proc.communicate() -if (proc.returncode != 0): - print('-S-> Command pdftotext returned an error :') - print(' ' + e.decode('utf8')) - sys.exit(-2) - -xml = o.decode('utf8') -root = ET.fromstring(xml) - - - -#### Extract xml to lists and dictionaries for faster and easier access. -# -# Data format : -# flow=[{page, blocks = [{page, lines:[{height, text}]}] -# Rq : page is redundant but for now we don't know which is the best -# -page_num = 0 -flow = [] -for body in root: - if (body.tag.endswith('body')): - for doc in body: - if (doc.tag.endswith('doc')): - for page in doc: - if (page.tag.endswith('page')): - page_num += 1 - for fl in page: - if (fl.tag.endswith('flow')): - blocks = [] - for bloc in fl: - if (bloc.tag.endswith('block')): - bl = {'page':page_num, 'lines':[]} - bwords = 0 - bcars = 0 - for line in bloc: - if (line.tag.endswith('line')): - h = float(line.get('yMax')) - float(line.get('yMin')) - li = '' - lwords = 0 - last_nbcar = 0 - last_h = 0 - for word in line: - if (word.tag.endswith('word')): - hword = float(word.get('yMax')) - float(word.get('yMin')) - if ((hword != last_h) - and (last_nbcar < 2)): - last_h = hword - li = "%s%s" % (li, word.text) - else: - li = "%s %s" % (li, word.text) - last_nbcar = len(word.text) - lwords += 1 - bl['lines'].append({ - 'height':h, - 'text':li.strip(), - 'nb_cars': len(li.strip()), - 'nb_words':lwords}) - bwords += lwords - bcars += len(li.strip()) - bl['nb_words'] = bwords - bl['nb_cars'] = bcars - blocks.append(bl) - flow.append({'page':page_num, 'blocks':blocks}) - - - - -#### Now, calls pdftohtml to improve font attributes -cmd = [CMD_PDFTOHTML, '-xml', '-i', '-stdout', '%s.pdf' % basename] -proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -o, e = proc.communicate() -if (proc.returncode != 0): - print('-S-> Command pdftohtml returned an error :') - print(' ' + e.decode('utf8')) - sys.exit(-2) - -xml = o.decode('utf8') -root = ET.fromstring(xml) - -#### Extracts font information (id, size, family, color) -#### and the link between lines of text and their font. -fontspec = [] -p2x_text = [] -for page in root: - if (page.tag.endswith('page')): - pg = int(page.get('number')) - for tg in page: - if (tg.tag.endswith('fontspec')): - fontspec.append({ - 'id': int(tg.get('id')), - 'size': int(tg.get('size')), - 'family': tg.get('family'), - 'color': tg.get('color') - }) - elif (tg.tag.endswith('text')): - fnt = int(tg.get('font')) - while (tg.text is None) and (len(tg) > 0): - tg = tg[0] # remove html style tags (like <b>, …) - if (tg.text is not None): - li = "%s" % (tg.text) - if (len(li.strip()) > 0): - p2x_text.append({ - 'page': pg, - 'font': fnt, - 'text': li.strip() - }) - - - -#### Try to find fontspec of flow's lines -###### 1. By line recognition -for fl in flow: - for bl in fl['blocks']: - for li in bl['lines']: - nocc = 0 - fo = 0 - for ligne in p2x_text: - if (ligne['text'] == li['text']) and (ligne['page'] == fl['page']): - nocc += 1 - if (nocc == 2) and (ligne['font'] == fo): - nocc = 1 - fo = ligne['font'] - if (nocc == 1): - li['font'] = fo - else: - li['font'] = None -###### 2. Block uniformization -for fl in flow: - for bl in fl['blocks']: - for li in bl['lines']: - if (li['font'] is None): - h = round(li['height']) - fnt = None - for li2 in bl['lines']: - if (fnt is None) \ - and (round(li2['height']) == h) \ - and (li2['font'] is not None): - fnt = li2['font'] - if (fnt is not None): - li['font'] = fnt - - -#### Page bottom detection -pb = 'dummy' -if (flow[-1]['page'] == 1): pb = None -while (pb is not None): - pb = None - last_lines = [] - last_read_page = flow[0]['page'] - last_read_line = 'Foo' - for fl in flow: - if (fl['page'] != last_read_page): - last_lines.append(re.sub(r'[^a-zA-Z]', '', last_read_line)) - last_read_line = fl['blocks'][-1]['lines'][-1]['text'] - last_read_page = fl['page'] - last_lines.append(re.sub(r'[^a-zA-Z]', '', last_read_line)) - - ### Is last_lines filled with the same string ? - pb = last_lines[0] - for li in last_lines[1:]: - if (pb is not None) and (pb != li): pb = None - - ### Yes, so mark these lines to be removed - if (pb is not None): - print("#####> %s" % pb) - last_read_page = flow[0]['page'] - last_read_flow = flow[0] - for fl in flow[1:]: - if (fl['page'] != last_read_page): - print(' xxx> %s' % last_read_flow['blocks'][-1]['lines'][-1]['text']) - del last_read_flow['blocks'][-1]['lines'][-1] - if not last_read_flow['blocks'][-1]['lines']: # ie it's empty - del last_read_flow['blocks'][-1] - #print('****> %d' % len(last_read_flow['blocks'])) - #if last_read_page == 1: print(' **> %s' % flow) - if not last_read_flow['blocks']: - flow.remove(last_read_flow) - #if last_read_page == 1: print(' ··> %s' % flow) - last_read_flow = fl - last_read_page = fl['page'] - print(' xxx> %s' % last_read_flow['blocks'][-1]['lines'][-1]['text']) - del last_read_flow['blocks'][-1]['lines'][-1] - if not last_read_flow['blocks'][-1]['lines']: # ie it's empty - del last_read_flow['blocks'][-1] - #print('****> %d' % len(last_read_flow['blocks'])) - if not last_read_flow['blocks']: - flow.remove(last_read_flow) - - - - -#### Calcultate some stats -font_sizes = {} -pipe = [] -bl_num = 0 -fl_num = 0 -for fl in flow: - for bl in fl['blocks']: - for li in bl['lines']: - h = round(li['height']) - if (pipe == []): - pipe.append(h) - else: - #if (h != pipe[-1]): - pipe.append(h) - if (font_sizes.get(h) is None): - font_sizes[h] = {'nb_lines':1, 'nb_cars':li['nb_cars'], - 'nb_words':li['nb_words'], 'blocks':[bl_num], - 'flows':[fl_num]} - else: - font_sizes[h]['nb_lines'] += 1 - font_sizes[h]['nb_cars'] += li['nb_cars'] - font_sizes[h]['nb_words'] += li['nb_words'] - if (font_sizes[h]['blocks'][-1] != bl_num): - font_sizes[h]['blocks'].append(bl_num) - if (font_sizes[h]['flows'][-1] != fl_num): - font_sizes[h]['flows'].append(fl_num) - bl_num += 1 - fl_num += 1 - - -#### Choose "normal" fontsize. -print('') -normal_font = 0 -nf_nword = 0 -for ft in sorted(font_sizes.keys()): - f = font_sizes.get(ft) - if (f['nb_words'] > nf_nword): - normal_font = ft - nf_nword = f['nb_words'] - - - - - -#### Prints p2x_text content -for fnt in fontspec: - print(fnt) -#print('=============================================>') -#for li in p2x_text: -# print('[p. %d][%d] %s' % (li['page'], li['font'], li['text'])) -print('<=============================================') -print('') - - -#### Prints font stats -print('') -for ft in sorted(font_sizes.keys()): - f = font_sizes.get(ft) - print("[%d] ====> %d flows, %d blocks, %d lines, %d words, %d cars" %(ft, - len(f['flows']), len(f['blocks']), - f['nb_lines'], f['nb_words'], f['nb_cars'])) -print('') -print('---> %d' % normal_font) -print('') -print('=============================================') - - -#### Prints flow content, but just for normal and bigger than normal text. -#for fl in flow: -# print('') -# print('[p. %d]' % fl['page']) -# for bl in fl['blocks']: -# h = 0.0; -# for li in bl['lines']: h += li['height'] -# n = len(bl['lines']) -# print(' ---------------------------------------> [%d]' % round(h/n)) -# for li in bl['lines']: -# if (li['font'] is not None): -# print(' [%2d] (%d) %s' % (li['font'], round(li['height']), li['text'])) -# else: -# print(' (%d) %s' % (round(li['height']), li['text'])) -# print(' <---------------------------------------') - -BIG_ONLY = True -print('') -nb_blocks = 0 -for fl in flow: - if (nb_blocks > 0): - print('') - #print('[p. %d]' % fl['page']) - nb_blocks = 0 - for bl in fl['blocks']: - h = 0.0; - for li in bl['lines']: h += li['height'] - n = len(bl['lines']) - h = round(h/n) - if (h >= normal_font) or not BIG_ONLY: - nb_blocks += 1 - print(' <---------------------------------------- (p. %d)' % bl['page']) - for li in bl['lines']: - if (li['font'] is not None): - print(' [%2d] (%d) %s' % (li['font'], round(li['height']), li['text'])) - else: - print(' (%d) %s' % (round(li['height']), li['text'])) - if (nb_blocks > 0): - print(' ---------------------------------------->')