#1 Le 04/06/2014, à 22:23
- roger64
[résolu] Changer unités de mesure sur feuille de style CSS
Bonjour,
Dans le domaine des livres électroniques (format EPUB), certains convertisseurs produisent des feuilles de style CSS (stylesheet.css) avec des valeurs de marge, de padding, d'indentation, etc. fixées en centimètres, millimètres, voire en pixels, c'est-à-dire avec des unités à valeur fixe. L'unité conseillée pour les EPUB est cependant l'em qui varie selon la valeur de la police choisie.
Il existe des convertisseurs centimètre vers em.
Le rapport pour une police à 100% est 1cm=2.37106301584em
Inversement: 1em=0.421175176em
Les feuilles de style sont des séries de paragraphes de ce genre:
p.Citation {
margin-left: 0.499cm;
margin-right: 0.499cm;
margin-top: 0;
margin-bottom: 0;
border: none;
padding: 0;
text-indent: 0.499cm;
text-align: justify;
font-family: "Charis SIL ModifiedLarger";
}
L'expression contenant l'unité à convertir commence toujours avec un deux-points et finit avec un point-virgule. J'aimerais disposer d'un script qui me permette de convertir en em les valeurs en centimètres contenues dans une feuille de style et je n'ai pas la moindre idée de la façon dont on peut s'y prendre.
Dernière modification par roger64 (Le 05/06/2014, à 09:50)
Hors ligne
#2 Le 04/06/2014, à 23:03
- pingouinux
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonsoir,
Le script conversion.py en python devrait convenir :
#!/usr/bin/python
import sys, re
conv=2.37106301584
unit=re.compile('([^\d.]+:\s*)([\d.]+)(cm)?(;\s*)')
with open(sys.argv[1],'r') as f :
for lig in f :
k=unit.search(lig)
if k :
deb=k.group(1)
val=str(conv*float(k.group(2)))
unite=k.group(3)
fin=k.group(4)[:-1]
unite= 'em' if unite else ''
print(deb+val+unite+fin)
else : print(lig[:-1])
À utiliser ainsi :
./conversion.py fichier.css
Résultat avec ton exemple :
p.Citation {
margin-left: 1.1831604449em;
margin-right: 1.1831604449em;
margin-top: 0.0;
margin-bottom: 0.0;
border: none;
padding: 0.0;
text-indent: 1.1831604449em;
text-align: justify;
font-family: "Charis SIL ModifiedLarger";
}
Dernière modification par pingouinux (Le 04/06/2014, à 23:04)
Hors ligne
#3 Le 05/06/2014, à 08:03
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
pingouinux ou la bonne fée! J'ai essayé sur une grosse feuille de style et cela fonctionne très bien! Merci beaucoup de ton intervention.
Il y a quelques points mineurs que je souhaiterais compléter:
1. - j'aimerais obtenir une sortie converted.txt (ou mieux converted.css) à côté du fichier converti.
2. - la valeur line-height est fréquemment donnée dans les feuilles de style de la façon suivante, sans unité de valeur:
line-height: 1.2;
Dans ce dernier cas, cependant, il ne s'agit pas de centimètres mais d'une unité relative qu'il ne faut pas convertir. Il conviendrait donc que le script ne fonctionne que lorsque l'unité de valeur (en l'occurrence ici cm) est explicitement mentionnée. Dans le cas ci-dessus, il ne devrait rien toucher.
3. - La précision avec deux décimales est suffisante. Comment obtenir un résultat à deux décimales qui minimiserait l'erreur obtenue? Ou, pour le dire différemment, vaut-il mieux ôter des décimales avant ou après conversion?
Dernière modification par roger64 (Le 05/06/2014, à 08:33)
Hors ligne
#4 Le 05/06/2014, à 08:37
- pingouinux
Re : [résolu] Changer unités de mesure sur feuille de style CSS
1. - j'aimerais obtenir une sortie converted.txt (ou mieux converted.css) à côté du fichier converti.
Je ne comprends pas ce point (qu'entends-tu par "à côté" ?). Si c'est pour créer un fichier converted.css, il suffisait que tu appelles le script ainsi :
./conversion.py fichier.css >converted.css
Pour le point 3, c'est toi qui as a donné 12 chiffres significatifs pour le coefficient de conversion.
Voici un script modifié qui tient compte de tes remarques :
#!/usr/bin/python
import sys, re
conv=2.37106301584
unit=re.compile('([^\d.]+:\s*)([\d.]+)(cm)?(;\s*)')
with open(sys.argv[1],'r') as f, open(sys.argv[2],'w') as g :
for lig in f :
k=unit.search(lig)
if k :
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
lig=k.group(1)+val+unite+k.group(4)
g.write(lig)
À appeler ainsi :
./conversion.py fichier.css converted.css
Hors ligne
#5 Le 05/06/2014, à 09:49
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
Je reconnais bien sûr mes torts. Ton script fonctionne parfaitement bien et ne modifie désormais que les unités en cm.
Merci beaucoup de ton aide, brillante, comme d'habitude!!
Hors ligne
#6 Le 06/06/2014, à 15:56
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
@pingouinux
J'ai montré ton script sur MobileRead et j'ai demandé s'il était possible d'écrire un script qui puisse modifier directement les fichiers css qui se trouvent dans un EPUB:
Voici le résultat qui fonctionne qu'il y a ait une ou plusieurs feuilles de style dans l'EPUB. La seule différence pour moi, est que pour le lancer, je dois d'abord spécifier l'interpréteur: python et la commande de lancement devient donc.
Ex;
python cm2em.py vieux.epub nouveau.epub
Encore merci pour ton aide.
#!/usr/bin/env python
import sys, re
import datetime, zipfile
class zip_info(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(zip_info, self).__init__(*args, **kwargs)
self.compress_type = compress_type
def convertcm2em(epub, stylesheet):
conv=2.37106301584
unit=re.compile('([^\d.]+:\s*)([\d.]+)(cm)?(;\s*)')
new_sheet = ''
with epub.open(stylesheet) as f:
for lig in f :
k=unit.search(lig)
if k :
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
lig=k.group(1)+val+unite+k.group(4)
new_sheet+=lig
print ' Checking: ', stylesheet
return new_sheet
def main(argv=sys.argv):
if len(argv) != 3:
print '\nUsage:'
print ' cm2em.py <infile.epub> <outfile.epub>'
return 1
if argv[2]==argv[1]:
print '\n Outfile cannot be the same as infile!'
return 1
with zipfile.ZipFile (argv[1], 'r') as zin, zipfile.ZipFile (argv[2], 'w') as zout:
for item in zin.infolist():
if (item.filename[-1:] != '/'):
buf = zin.read(item.filename)
if (item.filename[-4:] == '.css'):
converted_sheet = convertcm2em(zin, item.filename)
if converted_sheet == buf:
zout.writestr(item, buf)
else:
now = datetime.datetime.now()
zip_date = (now.year, now.month, now.day, now.hour, now.minute, now.second)
nzinfo = zip_info(item.filename, date_time=zip_date, compress_type=zipfile.ZIP_DEFLATED)
zout.writestr(nzinfo, converted_sheet)
else:
zout.writestr(item, buf)
return 0
if __name__ == '__main__':
sys.exit(main())
Je l'ai testé sur plusieurs livres et il y a un cas - rare - où la conversion ne se fait pas: c'est pour un style de bibliographie où il y a un indent négatif.
text-indent: -0.5cm;
Dernière modification par roger64 (Le 06/06/2014, à 16:54)
Hors ligne
#7 Le 06/06/2014, à 21:40
- pingouinux
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Pour prendre en compte les valeurs négatives, il suffit de remplacer cette ligne
unit=re.compile('([^\d.]+:\s*)([\d.]+)(cm)?(;\s*)')
par celle-ci (j'en ai profité pour simplifier un peu) :
unit=re.compile('(.+:\s*)(-?[\d.]+)(cm)?(;\s*)')
Hors ligne
#8 Le 06/06/2014, à 22:22
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Merci beaucoup encore une fois!
Hors ligne
#9 Le 08/06/2014, à 22:12
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
En poursuivant mes essais, je suis tombé sur une feuille de style rétive. La conversion ne se fait pas. J'ai allégé la feuille de style car il n'y a que quelques valeurs en centimètre, plutôt au début de la feuille. Les styles sont bien écrits de la même façon mais la forme est condensée comme ceci:
a:link {color:#000080;text-decoration:underline}
a:visited {}
body {font-size:1em;margin-bottom:0cm;margin-left:0.5cm;margin-right:0.5cm;margin-top:0cm}
body.nomargin {margin-bottom:0cm;margin-left:0cm;margin-right:0cm;margin-top:0cm}
div.amanuensis-center-div {margin-bottom:0cm;margin-left:0cm;margin-right:0cm;margin-top:0cm;text-align:center}
img.amanuensis-fullscreen-image {height:100%;margin-bottom:0cm;margin-left:0cm;margin-right:0cm;margin-top:0cm;max-width:100%}
p.P100 {color:#000000;font-size:1.25em;font-style:italic;font-weight:normal;margin-bottom:0em;margin-left:0em;margin-right:0em;margin-top:0.0694488188976378em;orphans:2;text-align:center;text-indent:0em;widows:2}
p.P101 {color:#000000;font-size:1em;font-style:normal;font-weight:normal;margin-bottom:0em;margin-left:0em;margin-right:0em;margin-top:0.0868110236220473em;orphans:2;text-align:center;text-indent:0em;widows:2}
p.P102 {color:#000000;font-size:1em;font-style:normal;font-weight:normal;margin-bottom:0em;margin-left:0em;margin-right:0em;margin-top:0.0868110236220473em;orphans:2;page-break-after:auto;page-break-before:auto;text-align:justify;text-indent:0em;widows:2}
On m'a demandé quelle version de Python tu avais utilisé pour écrire le script?
EDIT: en fait la version originale du script intervient sur cette feuille de style mais cause des dégâts en supprimant par exemple les mentions body, div, img....
Dernière modification par roger64 (Le 08/06/2014, à 22:31)
Hors ligne
#10 Le 08/06/2014, à 23:56
- pingouinux
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Dans ton exemple en #9, la présentation des données n'est plus du tout la même qu'en #1.
Voici une autre version du script :
#!/usr/bin/python
import sys, re
conv=2.37106301584
unit=re.compile('(:\s*)(-?[\d.]+)(cm)?(;)')
with open(sys.argv[1],'r') as f, open(sys.argv[2],'w') as g :
fic=f.read()
while True :
k=unit.search(fic)
if(k) :
g.write(fic[:k.start(1)])
g.write(k.group(1))
val=k.group(2)
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
else : unite=''
g.write(val+unite)
g.write(k.group(4))
fic=fic[k.end(4):]
else :
g.write(fic)
break
Je l'ai testé en python 2.7.3, et python 3.2.3.
Hors ligne
#11 Le 09/06/2014, à 06:09
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
Merci de répondre encore présent. Je te prie d'accepter mes excuses. Le premier script fonctionne bien pour toutes les feuilles de styles qui ont été "embellies", c'est-à-dire préalablement nettoyées par l'éditeur de Calibre et qui se présentant sous la forme que je t'avais donné dans le premier message.
C'est en élargissant les tests que je suis tombé sur ce type d'écriture condensé qui est effectivement différent même s'il suit les règles du CSS. Dans ce deuxième cas, pour que le script fonctionne, il fallait que j'"embellisse" la feuille de style au préalable pour retomber dans le cas initial.
EDIT: J'ai testé ton nouveau script sur des feuilles condensées et embellies et il fonctionne bien pour les deux. Je viens de l'adresser sur MobileRead au deuxième auteur. Pour ton information, Kovid Goyal, l'auteur de Calibre vient aussi de participer spontanément à cette discussion.
Si tu veux suivre et/ou participer à la discussion en anglais, c'est ici: http://www.mobileread.com/forums/showth … p?t=240536
L'intervention de Kovid Goyal est au post #20.
Dernière modification par roger64 (Le 09/06/2014, à 07:13)
Hors ligne
#12 Le 09/06/2014, à 16:21
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour Tamarou
On change, on ne peut pas toujours répéter la même chose...
Depuis deux ans, j'utilise LMDE 64 bits et ma liseuse Kobo Glo est aussi sur Linux.
@pingouinux
Je te cite une remarque de notre co-auteur:
"Note that pingouin's regex in the new conversion routine will miss the last property/value pair in the class (when it doesn't end with a ";").
body {font-size:1em;margin-bottom:0cm;margin-left:0.5cm;margin-right:0.5cm;margin-top:0cm}
becomes:
body {font-size:1em;margin-bottom:0.00em;margin-left:1.19em;margin-right:1.19em;margin-top:0cm}
Note the margin-top property at the end. It obviously won't matter when the value is zero, but it will when it's not."
Il fait allusion au fait que dans un paragraphe consacré à un style, il n'est pas obligatoire de mettre un point-virgule juste avant l'accolade fermante et beaucoup s'en abstiennent. Le raisonnement derrière cela est que les points-virgule ne servent qu'à séparer les arguments et qu'il n'y a plus rien de ce genre à séparer avant l'accolade fermante.
Je ne sais combien de "découvertes" de ce genre je vais encore faire et je prie Dieu pour que je n'aie pas encore épuisé tes trésors de patience... La bonne nouvelle est que l'intégration du script va être grandement facilitée par l'intervention de Kovid Goyal.
Dernière modification par roger64 (Le 09/06/2014, à 16:22)
Hors ligne
#13 Le 09/06/2014, à 19:29
- pingouinux
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Sans doute provisoire, en attendant ta prochaine "trouvaille"…
#!/usr/bin/python
import sys, re
conv=2.37106301584
unit=re.compile('(:\s*)(-?[\d.]+)(cm)?(;|})')
with open(sys.argv[1],'r') as f, open(sys.argv[2],'w') as g :
fic=f.read()
while True :
k=unit.search(fic)
if(k) :
g.write(fic[:k.start(1)])
g.write(k.group(1))
val=k.group(2)
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
else : unite=''
g.write(val+unite)
g.write(k.group(4))
fic=fic[k.end(4):]
else :
g.write(fic)
break
Hors ligne
#14 Le 09/06/2014, à 21:30
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
@pingouinux
Merci de ton aide. Je commence à avoir chaud...
Voici la nouvelle version baptisée cm2em_v3. Les deux parties ont été revues.
#!/usr/bin/env python
from __future__ import print_function
from __future__ import unicode_literals
import sys, re
import datetime, zipfile
class zip_info(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(zip_info, self).__init__(*args, **kwargs)
self.compress_type = compress_type
def convertcm2em(epub, stylesheet):
conv=2.37106301584
unit=re.compile('(:\s*)(-?[\d.]+)(cm)?(;|})')
new_sheet = ''
fic=epub.read(stylesheet).decode('utf-8')
while True :
k=unit.search(fic)
if(k) :
new_sheet+=fic[:k.start(1)]
new_sheet+=(k.group(1))
val=k.group(2)
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
else :
unite=''
new_sheet+=val+unite
new_sheet+=k.group(4)
fic=fic[k.end(4):]
else :
new_sheet+=fic
break
print (' Checking: ', stylesheet)
return new_sheet
def main(argv=sys.argv):
if len(argv) != 3:
print ('\nUsage:')
print (' cm2em.py <infile.epub> <outfile.epub>')
return 1
if argv[2]==argv[1]:
print ('\n Outfile cannot be the same as infile!')
return 1
with zipfile.ZipFile (argv[1], 'r') as zin, zipfile.ZipFile (argv[2], 'w') as zout:
for item in zin.infolist():
if (item.filename[-1:] != '/'):
buf = zin.read(item.filename)
if (item.filename[-4:] == '.css'):
converted_sheet = convertcm2em(zin, item.filename)
if converted_sheet == buf.decode('utf-8'):
zout.writestr(item, buf)
else:
now = datetime.datetime.now()
zip_date = (now.year, now.month, now.day, now.hour, now.minute, now.second)
nzinfo = zip_info(item.filename, date_time=zip_date, compress_type=zipfile.ZIP_DEFLATED)
zout.writestr(nzinfo, converted_sheet)
else:
zout.writestr(item, buf)
return 0
if __name__ == '__main__':
sys.exit(main())
Dernière modification par roger64 (Le 10/06/2014, à 16:00)
Hors ligne
#15 Le 10/06/2014, à 09:06
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Et le dernier avatar du script lancé avec Calibre
avec la commande suivante qui modifie l'epub original (copie fortement conseillée...) et implique que l'epub soit dans le répertoire de travail
calibre-debug cm2em_calibre.py file.epub
Le nouveau code
from __future__ import print_function
from __future__ import unicode_literals
import sys, regex
from calibre.ebooks.oeb.polish.container import get_container, OEB_STYLES
def convertcm2em(raw):
conv=2.37106301584
unit=regex.compile('(:\s*)(-?[\d.]+)(cm)?(;|})')
new_sheet = ''
while True :
k=unit.search(raw)
if(k) :
new_sheet+=raw[:k.start(1)]
new_sheet+=k.group(1)
val=k.group(2)
unite=k.group(3)
if unite=='cm' :
val="%.2f"%(conv*float(k.group(2)))
unite='em'
else :
unite=''
new_sheet+=val+unite
new_sheet+=k.group(4)
raw=raw[k.end(4):]
else :
new_sheet+=raw
break
return new_sheet
c = get_container(sys.argv[-1], tweak_mode=True)
for name, mt in c.mime_map.iteritems():
if mt in OEB_STYLES:
raw = c.open(name).read()
new = convertcm2em(raw)
if new != raw:
print (' Modifying:', name)
c.open(name, 'wb').write(convertcm2em(raw))
else:
print (' No changes to:', name)
c.commit()
Dernière modification par roger64 (Le 10/06/2014, à 09:08)
Hors ligne
#16 Le 14/06/2014, à 19:03
- roger64
Re : [résolu] Changer unités de mesure sur feuille de style CSS
Bonjour
@pingouinux
Cela n'a pas raté, il y a eu une autre "trouvaille" comme tu le craignais: en effet, j'avais tout simplement oublié de te signaler la notation abrégée (shorhand)... Mais rassure-toi, le problème a été réglé d'une autre façon.
Comme je te l'avais dit, Kovid Goyal est intervenu une deuxième fois. Du coup, la solution adoptée utilise une fonction de Calibre (avec Python) et non plus directement Python. Comme tu le sais, je ne maîtrises bien peu de choses dans ce domaine mais si cela t'intéresse, tu trouveras sur ce fil MobileRead en français, le texte du script nouvelle formule. Il est possible de faire du traitement par lot.
http://www.mobileread.com/forums/showth … ost2851172
Encore très sincèrement merci pour ta contribution efficace qui a permis de démarrer cela.
Dernière modification par roger64 (Le 14/06/2014, à 19:03)
Hors ligne