Dans cet article, nous verrons comment insérer du texte dans une une image à l'aide de la bibliothèque tierce freetype-go. Il s'agit d'un portage en golang du moteur de rendu de fonte FreeType. Deux cas seront présentés : une application console et une application web. Bien entendu, étant donné que nous sommes francophones, j'ai particulièrement veillé à ce que la bibliothèque gère correctement l'Unicode avec un cas de figure contenant des caractères non ASCII, voire non latin.
go get code.google.com/p/freetype-go/freetype go install code.google.com/p/freetype-go/freetype
Afin de tester à fond les possibilités de la bibliothèque (et notamment sa compatibilité avec les caractères non ASCII), je me suis basé sur un texte écrit en khmer (langue officielle du Cambodge) et la fonte KhmerOS. Le but étant de produire une image contenant un texte sur deux lignes, comme dans cet exemple :
Ce texte a été généré par freetype-go
Voici le code qui s'appuie sur la bibliothèque freetype-go pour charger la police de caractère, mais également sur la bibliothèque standard de go pour dessiner et écrire le résultat dans un fichier PNG. Les variables dpi, size et spacing servent à gérer la résolution, la taille et l'écart entre les lignes. Pour le reste (par exemple, pour centrer le texte), ce serait à vous de faire les calculs (en fonction de la taille de la zone et de l'espace – qui peut être variable en fonction de la police de caractères – pris par les caractères composant la ligne). Sachez qu'il existe des bibliothèques gérant ces calculs. Autrement dit, des bibliothèques qui la chapeautent afin de vous simplifier la vie lorsque vous créez un PDF ou un graphique.
package main import ( "code.google.com/p/freetype-go/freetype" "image" "image/draw" "image/png" "io/ioutil" "os" "strings" ) func main() { text := `Comment dire "ça va ?" en khmer ? Réponse : ជំរាបសួរ` var dpi float64 = 72 var size float64 = 20 var spacing float64 = 1.5 lines := strings.Split(string(text), "\n") data, err := ioutil.ReadFile("KhmerOS.ttf") if err != nil { panic(err) } font, err := freetype.ParseFont(data) if err != nil { panic(err) } i := image.NewRGBA(image.Rect(0, 0, 350, 90)) draw.Draw(i, i.Bounds(), image.White, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFontSize(size) c.SetDst(i) c.SetClip(i.Bounds()) c.SetSrc(image.Black) c.SetFont(font) pt := freetype.Pt(10, 10+int(c.PointToFix32(size)>>8)) for _, line := range lines { _, err = c.DrawString(line, pt) if err != nil { panic(err) } pt.Y += c.PointToFix32(size * spacing) } saveToPngFile("image-texte-khmer-freetype.png", i) }
On utilisera une fonction qui enregistrera le résultat dans un fichier PNG (la bibliothèque standard propose également le format JPEG et GIF sans compter toutes les bibliothèques tierces gérant les autres formats de fichier).
func saveToPngFile(filePath string, i *image.RGBA) { f, err := os.OpenFile(filePath, os.O_CREATE | os.O_WRONLY, 0666) if err != nil { panic(err) } defer f.Close() err = png.Encode(f, i) if err != nil { panic(err) } }
On pourrait très facilement créer un contrôleur (répondant, par exemple à l'adresse http://localhost:9999/image – voir cet article) retournant une image. Changer la fonction main comme suit :
func main() { http.HandleFunc("/image", imageHandler) http.ListenAndServe(":9999", nil) }
Puis créer le handler HTTP imageHandler en y déplaçant le code qui était précédemment dans la fonction main. La différence est que nous n'écrirons plus dans un fichier, mais sur le flux de retour web. Il ne faut pas oublier de préciser au navigateur le type de contenu en retour de sa requête, ici une image au format PNG (on peut facilement retourner un format GIF, JPEG ou autre, il suffit de changer l'encodeur et la valeur du champ Content-type avec le MIMETYPE approprié) :
w.Header().Set("Content-type", "image/png") err = png.Encode(w, i) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) }
Les applications sont diverses. Ce code permet en effet de gérer les cas de figure où le navigateur client ne supporterait pas la police de caractères que vous utilisez ou la gèrerait mal (les anciennes versions d'Internet Explorer ou certaines versions d'Opera Mobile par exemple). On peut aussi se servir de ce code pour écrire un captcha en déformant légèrement l'image avant de l'envoyer au navigateur. Ou tout simplement écrire dans une image "combien font 1+3 ?" et demander au visiteur (humain) de faire le calcul.
Une traduction du blog officiel de golang expliquant le mécanisme de la réflexion en Go. Lire »
Traduction d'un article du blog officiel expliquant comment échanger des données entre deux programmes golang grâce à un format natif Lire »
Préconisations officielles pour la gestion des erreurs dans un programme golang. Cet article complète les explications sur panic, defer et recover Lire »
Exemples d'utilisation du type chan et des go routines stateful et stateless Lire »
Traduction d'un article du blog officiel de golang, cet article explique comment utiliser le paquet image/draw de la bibliothèque standard de go Lire »
Soyez le premier à commenter cet article
Tous les commentaires sont soumis à modération. Les balises HTML sont pour la plupart autorisées. Les liens contextuels et intéressants sont en follow.