Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 04/06/2014, à 21: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, à 08:50)

Hors ligne

#2 Le 04/06/2014, à 22: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, à 22:04)

Hors ligne

#3 Le 05/06/2014, à 07: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, à 07:33)

Hors ligne

#4 Le 05/06/2014, à 07: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. smile

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, à 08:49

roger64

Re : [résolu] Changer unités de mesure sur feuille de style CSS

Bonjour

Je reconnais bien sûr mes torts.  smile  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, à 14: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, à 15:54)

Hors ligne

#7 Le 06/06/2014, à 20: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, à 21: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, à 21: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, à 21:31)

Hors ligne

#10 Le 08/06/2014, à 22: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, à 05: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, à 06:13)

Hors ligne

#12 Le 09/06/2014, à 15: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... smile
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, à 15:22)

Hors ligne

#13 Le 09/06/2014, à 18: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, à 20: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, à 15:00)

Hors ligne

#15 Le 10/06/2014, à 08:06

roger64

Re : [résolu] Changer unités de mesure sur feuille de style CSS

Et le dernier avatar du script lancé avec Calibre smile

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, à 08:08)

Hors ligne

#16 Le 14/06/2014, à 18: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)... roll  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, à 18:03)

Hors ligne