vendredi 22 février 2008
Chargement dynamique de polices avec Flash et Actionscript 3
Actionscript/Flash/Flex - Lien permanent
Ayant eu récemment besoin de faire ce genre de choses sur un projet, voici un tutoriel sur le chargement dynamique de polices de caractères en Actionscript 3. Ceci peut être particulièrement utile dans le cas par exemple de sites multilingues comportant des langues asiatiques, les polices de caractères chinoises ou japonaises pouvant être particulièrement lourdes à charger...
Le principe sera le suivant :
- La police de caractère est contenue dans un fichier SWF externe.
- Dans ce SWF, la police est exportée et est disponible sous la forme d'une classe héritant de la classe Font.
- Le SWF principal charge ce SWF avec un objet Loader, puis enregistre la classe de police dans la liste des polices disponibles.
- La police est ensuite utilisable dans l'application principale, dans un objet TextFormat ou pour un style CSS avec l'objet StyleSheet, comme vous voulez.
Création du SWF contenant la police
Pour générer le fichier de police, vous pouvez utiliser au choix Flex ou Flash. Le résultat est similaire, en revanche Flex permet de choisir une plage limitée de caractères à exporter (par exemple uniquement les minuscules, uniquement les caractères cyrilliques, etc...). Ceci permet donc d'optimiser au mieux le poids de votre SWF en fonction de vos besoins. Avec Flash en revanche, vous êtes contraint d'embarquer tous les caractères de la police dans le SWF final, c'est tout ou rien :)
Je vais détailler les deux méthodes, en commençant par Flex :
Avec Flex
Nous allons ici utiliser le SDK de Flex pour générer ce fichier. Voici ce à quoi va ressembler notre classe pour générer le fichier SWF contenant la police. j'ai au préalable placé le fichier de police Futura.ttf dans un dossier "assets".
package{
import flash.display.Sprite;
[SWF(backgroundColor='0xFFFFFF', width='100', height='100')]
public class Futura extends Sprite {
[Embed(source = "assets/Futura.ttf", fontName = "Futura")]
public static var Futura:Class;
}
}
Compilez et vous obtenez un magnifique SWF vide, mais contenant bien la police embarquée.
En bonus, choisir la plage de caractères :
Pour limiter l'exportation à une plage prédéfinie de caractères, la première chose à faire est d'éditer le fichier flex-config.xml présent dans le dossier "frameworks", à l'intérieur du dossier d'installation du SDK Flex. Ouvrez également le fichier flash-unicode-table.xml qui se trouve dans le même dossier.
Dans flex-config.xml, rendez-vous dans la balise <fonts>, c'est ici que vous allez pouvoir créer des plages de caractères personnalisées, de cette manière :
<fonts> [...] <languages> <language-range> <lang>Uppercase</lang> <range>U+0020,U+0041-U+005A</range> </language-range> </languages> [...] </font>
Comme vous le voyez, il suffit de créer un noeud <language-range> avec à l'intérieur une balise <lang> pour donner un nom à votre plage, et une balise <range> pour spécifier les plages de caractères unicodes. Bien bien, mais comment connaitre ces plages ? C'est le moment d'ouvrir le fichier flash-unicode-table.xml qui se trouve juste à coté :) Vous y trouverez plein de plages prédéfinies (majuscules uniquement, Kanji japonais, etc...) que vous pouvez copier-coller dans votre flex-config.xml.
Revenez ensuite à votre classe, et modifiez le metatag Embed comme ceci :
[Embed(source = "assets/Futura.ttf", fontName = "Futura", unicodeRange="Uppercase")]
Compilez et c'est prêt !
Avec Flash CS3
Si vous optez pour Flash, voici la procédure :
- Créer un nouveau document
- Créez un nouveau symbole de police dans la librairie (clic droit -> "Nouvelle police...")
- Dans le champ Nom, donnez lui... un nom (de préférence le même que le nom original de la police, ça évitera les confusions...)
- Vous pouvez choisir les version gras, italique, ou gras italique en cochant les cases appropriées, puis cliquez sur OK. Attention il s'agit d'un choix exclusif, si vous voulez que la police soit disponible en version normale et gras par exemple, vous devrez avoir 2 symboles de police dans votre bibliothèque, comme deux polices distinctes.
- Faites ensuite un clic droit sur le symbole de police, puis cliquez sur "Liaison..."
- Choisissez un nom de classe pour votre police, puis cliquez sur OK.
Voilà, votre police est désormais exportée pour Actionscript et sera donc exportée et utilisable lors de la compilation du SWF. Cette police sera disponible sous la forme d'une classe héritant de la classe Font.
Compilez et votre fichier SWF de police est prêt.
Création de l'animation principale
L'application principale sera composée d'un simple champ texte auquel on va appliquer un objet TextFormat avec notre police chargée dynamiquement.
- Créez un nouveau document FLA
- Placez un champ texte dynamique sur la scène, et donnez lui "message_txt" comme nom d'occurrence.
Voici ensuite le code à placer sur la première frame de l'application (vous pouvez bien sûr créer une classe d'application à la place, je vous laisse adapter le code en fonction)
Première étape, charger le fichier SWF contenant la police, avec la classe Loader :
var loader:Loader;
function init(){
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontCompleteHandler);
loader.load(new URLRequest("Futura.swf"));
}
Lorsque le chargement est fini, nous allons enregistrer la classe correspondant au symbole de police dans la liste des polices disponibles :
function fontCompleteHandler(event:Event){
var domain:ApplicationDomain = loader.contentLoaderInfo.applicationDomain;
var font:Class = domain.getDefinition("Futura") as Class;
Font.registerFont(font);
initStyles();
}
Petite subtilité ici, la classe Futura n'est pas directement disponible dans le contexte de l'application principale. En effet, chaque SWF contient son propre "domaine d'application, c'est à dire que chaque classe est "rangée" dans un domaine distinct pour chaque SWF chargé, ceci pour éviter par exemple des conflits entre classes.
Ici on récupère donc la classe en allant chercher le domaine d'application du SWF chargé, puis avec la méthode getDefinition(). Le paramètre à passer ici est le nom de la classe tel que vous l'avez renseigné dans la boite de dialogue Liaison.
Enfin il nous reste à créer l'objet TextFormat, et à remplir et styler notre champ texte :
function initStyles(){
var tf:TextFormat = new TextFormat("Futura",16,0xFF0000);
message_txt.embedFonts = true;
message_txt.antiAliasType = AntiAliasType.ADVANCED;
message_txt.text = "Lorem ipsum dolor sit amet";
message_txt.setTextFormat(tf);
}
Attention ici, le nom de la police à utiliser pour l'objet TextFormat est le nom que vous avez défini dans la boite de dialogue "Propriétés".
Voici donc le code complet de l'application :
var loader:Loader;
init();
function init(){
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontCompleteHandler);
loader.load(new URLRequest("Futura.swf"));
}
function fontCompleteHandler(event:Event){
var domain:ApplicationDomain = loader.contentLoaderInfo.applicationDomain;
var font:Class = domain.getDefinition("Futura") as Class;
Font.registerFont(font);
initStyles();
}
function initStyles(){
var tf:TextFormat = new TextFormat("Futura",16,0xFF0000);
message_txt.embedFonts = true;
message_txt.antiAliasType = AntiAliasType.ADVANCED;
message_txt.text = "Hello Futura !";
message_txt.setTextFormat(tf);
}
Commentaires
Ca a l'air bien mais je n'arrive pas à le faire fonctionner, si tu peux mettre les fichiers à dispos je verrais ou se situe l'erreur merci. Sinon le site de lacroix est vraiment superbe bravo !!
Salut Quentin,
pas de souci, je vais mettre en ligne les fichiers dans les prochain jours, stay tuned :)
Et voilà, j'ai mis à jour le billet avec en annexe les fichiers d'exemple pour Flash et pour Flex
C'est cool comme petit tuto, j'ai bien compris comment ça fonctionne... Je l'ai adapté aux projet sur lequel je bosse... sans résultats. Donc j'ai testé tes fichiers sources(Flash), qui fonctionnent très bien. Seulement je commence à me poser des questions, j'ai fait différents tests, jusqu'à me rendre compte que lorsque je recompilais tes .fla, sans en changer une ligne, les .swf ne fonctionnaient plus... Une petite idée d'où peu venir mon problème? Parcque je pense que c'est ce qui fait que le chargement de la police ne se fait pas non plus dans mon projet
Salut a toi Grand Pablo
super tuto, en fait ca fait plusieurs jours que je recherche qq chose qui ressemble à ca... donc mille fois merci..
J'ai une question....
Si on veut mettre plusieurs police différentes, faut-il faire le code autant de fois qu'il y a de polices ? ou y a t il une technique qui permette plusieurs telechargement de police à la fois ?
En fait, par un combobox je veux permettre a mes visiteurs de pouvoir agir sur la police des textes qu'ils ecriront...
Encore merci
Salut bernard26000
Et bien oui tu peux très bien inclure plusieurs polices dans le swf loadé :
- avec Flex tu rajoute autant de [Embed...] que tu veux dans la classe
- avec Flash tu crée autant de symboles de polices dans la librairie
Ensuite le code dans le conteneur ne change presque pas, il faut juste exécuter le Font.registerFont() autant de fois pour chaque police.