Partage
  • Partager sur Facebook
  • Partager sur Twitter

Text-shadow generator avec Pillow

Calcul position

Sujet résolu
    18 novembre 2021 à 19:43:28

    Bonjour, alors voila je me suis améliorer le dessin de texte avec Pillow, j'ai ajouter diverses options comme les espaces entre les lettres la hauteur des lignes, le vertical alignement, l'horizontale le baseline etc.... Tous fonctionne très bien mais le text-shadow me donne de la peine.

    J'ai essayer de m'orienter vers pywebview en fenêtre cacher pour utiliser le css directement, cela fonctionner mais le soucis c'est que pywebview a des comportements inattendu avec les thread et processus donc cela me sembler chamboule-tout juste pour du texte.

    Puis j'avais utiliser le module request pour tester avec php et cette librairie:

    https://github.com/stil/gd-texthttps://github.com/stil/gd-text

    Cela ne m'as pas paru convenant non plus vu que je ne peut ajouter le letter-spacing et les options que j'ai déjà créez avec mon code, de plus le text-shadow est limiter aussi, bien que cette petite librairie est sympa.

    Alors voila, j'ai bien réussit a effectuer un text-shadow qui reste agréable a regarder.

    Mais le soucis, dès que j'augmente le facteur cela pars en vrille voici trois démos:

    Facteur 4: qui reste encore potable.

    Facteur 8:ça commence a devenir un peu dégueu:

    Facteur 16, alors la c'est l'apothéose:

    Voici le code en test génerateur:

    def createContext(self):
            img = Image.new('RGBA', (self.width+self.paddingX, self.height+self.paddingY), self.background)
            img.putalpha(0)
            draw = ImageDraw.Draw(img)
            return img, draw
        
        def drawShadow(self):
            self.blurred, self.drawBlurred = self.createContext()
            arg = list(map(lambda func: [self.blurred, self.drawBlurred, 'black'], self.text.split('\n')))
            dede = list(map(self.drawMove, arg, self.text.split('\n'), range(len(self.text.split('\n')))))
            self.blurred = self.blurred.resize((self.width+self.paddingX, self.height+self.paddingY), Image.ANTIALIAS)
            return self.blurred
            
        def drawMove(self, arg, txt, indexi):
            ta = list(map(lambda word: self.font.getsize(word)[1], self.text.split('\n')[:indexi+1]))
            te = list(map(lambda index: sum(list(ta[:index])), range(len(ta))))
            diff = self.width - (self.font.getsize(txt)[0] + (self.letter_spacing * (len(txt)-1)))
            xBaseline = floor(diff/2) if self.baseline == 'center' else diff if self.baseline == 'right' else 0
            padX, padY = floor(self.paddingX/2), floor(self.paddingY/2)
            n, char, h, y = 0, "", 0, te[indexi] + (self.line_height * indexi)
            verticalAlign = 0 if self.vAlign == 'top' else -(self.height - arg[0].size[1]) if self.vAlign == 'bottom' else floor(-(self.height - arg[0].size[1])/2) if self.vAlign == 'center' else padY
            x, yy = 0, 0
            self.fact = 4
            factor = self.fact
            factorIter = round(factor/2)
            factorMatrice = round(factorIter/2)
            for element in txt:
                n = self.font.getsize(char)[0] + (self.letter_spacing * h) if char != "" else 0
                x, yy = padX+xBaseline+n, verticalAlign+y
                for dd in range(factorIter):
                    arg[1].text((x-factorMatrice, yy-factorMatrice), font=self.font, text=element, fill=arg[2], spacing=self.line_height)
                    arg[1].text((x+factorMatrice, yy+factorMatrice), font=self.font, text=element, fill=arg[2], spacing=self.line_height)
                    arg[1].text((x+factorMatrice, yy-factorMatrice), font=self.font, text=element, fill=arg[2], spacing=self.line_height)
                    arg[1].text((x-factorMatrice, yy+factorMatrice), font=self.font, text=element, fill=arg[2], spacing=self.line_height)
                h, char = h+1, char + element
    
            return y
        
        def compose(self, calqueTxt, calqueShadow):
            final = Image.new('RGBA', (self.width+self.paddingX, self.height+self.paddingY), self.background)
            if isinstance(calqueShadow, str):
                final.paste(calqueTxt, calqueTxt)
            else:
                #calqueShadow.paste(calqueTxt, calqueTxt)
                calqueShadow.paste(calqueTxt, (0, 0), calqueTxt)
                final.paste(calqueShadow, calqueShadow)
            final.resize((self.width+self.paddingX, self.height+self.paddingY), Image.ANTIALIAS)
            final.save('facteurX'+str(self.fact)+'.png')
            final.show()

    DrawMove est identique a la création du calque texte hormis la boucle dd.

    Bon x et yy correspondent à chaque positions de caractères original, je les dessine une a une, pour le text-shadow concrètement cela commence a partir de self.fact, le reste n'est juste des options que j'ai créez qui fonctionnent tous comme convenu.

    Puis après je compose le résultat calque texte au dessus du calque shadow et collage final sur le background.

    Donc pourquoi m'effectue t'il une telle distorsion au facteur 16?

    Et n'existe pas au autre moyen d'effectuer un text-shadow convenable avec python?

    Il ne me reste plus que le text-shadow que j'aimerais gérez comme text-shadow css(si possible), et cela faits plusieurs jours que je réfléchit.

    J'ai même envisager la détection de contour, mais je pense que ce serait utiliser beaucoup de mémoire pour un résultat brouillon je pense, car cela pourrait devenir complexe pour du texte.J'ai essayer aussi scale font, scale image et re-position, mais ça a n'allait pas.De plus les fonctions de lissage comme les filtres et tous saccage un peu le résultat. Mais bon cela est autre sujet, je verrait le lissage et la qualités une fois le text-shadow bien positionner.

    • Partager sur Facebook
    • Partager sur Twitter
      20 novembre 2021 à 15:50:41

      Problème résolut avec https://github.com/vgalin/html2image

      Ce projet merveilleux permet d’exécuter du HTML et CSS directement a partir de python en utilisant l'offline des navigateurs et fournit un screenshot du résultat.

      donc

      from html2image import Html2Image
      
      class tester:
          def __init__(self, text):
              self.font = "@font-face {font-family: 'myfont';src: url('D:/python/testi/AbrilFatface-Regular.ttf');}"
              self.image = "<p><img src='D:/python/testi/bodin.jpg' alt=''/></p>"
              self.hti = Html2Image()
              html = "<p> "+text+"</p><button>dede</button>"
              html += self.image
              css = self.font+"p{font-family:'myfont';font-size:25px;text-shadow:2px 2px 2px black;color:white;letter-spacing:5px;}button{border-radius:6px;box-shadow:6px 6px 6px black;}"
      
              self.hti.screenshot(html_str=html, css_str=css, save_as='red_page.png')


      donne

      Donc après plusieurs jours de recherches, je suis enfin content d'avoir trouver ça, je poste cette solution si comme moi vous recherchez un moyen plus sympa pour effectuer des graphismes de texte avec python.

      • Partager sur Facebook
      • Partager sur Twitter

      Text-shadow generator avec Pillow

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
      • Editeur
      • Markdown