Is it possible to use a non-embedded fallback font when using an embedded font with AS3 TextField? - actionscript-3

I have an embedded font in my AIR/AS3 app that lacks support for most international characters. Using TextField and StyleSheet with the font-family property, I assumed I would simply need to do this:
font-family: Interstate-Regular, _sans;
This works if TextField.embedFonts = false; but then Interstate-Regular isn't embedded for users that don't have it on their system. With TextField.embedFonts = true; the text doesn't even show up. Is there a way to embed Interstate-Regular and still use _sans as a fallback system font without embedding it as well?

Flash Text Engine has this "fallback" feature, but it is slower than regular TextField, and more difficult to use it.
Link to the Adobe Manual

You could implement a switch in a custom FontManagement class , if a language is not supported by your main font , revert to a non embedded font. To achieve this , you could use this FontManagement class as a centralized point where to format your TextFields. This could be achieved by creating a public static function which would return a TextField with the relevant format.
//where you need to format a TextField
var params:Object = {color:0xffffff , size:12, supported:false , etc...};
var tf:Texfield = FontManagement.formatTextField(tf , params );
public class FontManagement
{
//A basic example
public static function formatTextField( tf:TextField , params:Object ):TextField
{
//since this is a static function , the Boolean is passed as an argument
//but there are other ways to set it, depending on where in your app
//the language is identified
if( params.supported )
tf.embedFonts = true;
else
tf.embedFonts = false;
//here the rest of your formatting code
return tf;
}
}

Related

How to use a font embedded in a SWC

I exported a SWC from Flash CS3 with a font embedded.
Now I want use it in some TextFields, but I don't know how to use the font.
Done! Here's my solution:
[Embed(source="res/guardanapo.otf", fontName="guardanapo", fontFamily="guardanapo", unicodeRange="U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E", advancedAntiAliasing="false", embedAsCFF="false")]
public static const fonte:Class;
I wanted to embed the font from SWC, but now it isn't necessary anymore. But answer if you know how to do that, maybe someone is serching for it now.
Give this a try. myLoader is the loader that you loaded your swf/swc with the font in its library. myTextField is a pre-existing text field. I set embedFonts to true, but you may not need it.
var MyFont:Class = myLoader.contentLoaderInfo.applicationDomain.getDefinition("FontClassName");
var embeddedFont:Font = new MyFont();
var textFormat:TextFormat = new TextFormat();
textFormat.font = embeddedFont.fontName;
textFormat.size = 24;
myTextField.setTextFormat(textFormat);
myTextField.embedFonts = true;
Maybe you can include a font-fetching class in the swf with the font(s) you want to use. There could be static methods that apply a font to a field, or return the font name given the font's class name. This could help keep the rest of your application cleaner.

FLVPlaybackCaptioning + Custom position

Using FLVPlayback Captioning component I would like to move the subtitle text at certain parts in y-position. Is this possible in AS3?
All of my own custom arguments are ignored when subtitles are parsed and wrapping the specific part with some sort of character won't do it either as I cannot change the text during runtime.
The reason is that in my videostreams there is boxes with text content that I don't want the subtitle on top of, and rather above for reading purposes.
I was thinking of either doing an own manual subtitle function or custom flash cuepoints that I can access but want to know if anyone has done this before.
Something like this will do it. I found out that autoLayout was over overridden by the subtitle xml so I forced it to false every "change".
public function Init() : void
{
// captions
_captions = new FLVPlaybackCaptioning();
_captions.autoLayout = false;
_captions.flvPlayback = _video;
_captions.addEventListener(CaptionChangeEvent.CAPTION_CHANGE, onCaptionChange);
_captions.source = "mySubs.xml";
addChild(_captions);
}
private function onCaptionChange(pEvent : CaptionChangeEvent) : void
{
if(!_captions.captionTarget)
return;
_captions.autoLayout = false; // force autoLayout
_captions.captionTarget.y = 666; // position of choice
}

embedding a font in a swf using as3

I have a project using flash (and AIR for android and eventuall iOS) for translating some phrases. Although most fonts are fine there are some that I have to load after the user has chosen the languages. Over a year ago I generated a couple of swf files (Bengali and Urdu) and put them on my web server. The flash application then loads them when required and everything is OK...
However as I am nearing implementing the project I thought I should generate the swf files for the other languages that are in the pipeline and for some reason I can't manage it! Needless to say I have misplaced (tidied) the original AS3 source for the two fonts I have done.
package
{
import flash.display.Sprite;
import flash.events.Event;
public class ArabicF extends Sprite
{
[Embed(source = "trado.ttf",
fontName = "ArabicX",
fontFamily = "ArabicY",
fontWeight = "normal",
fontStyle = "normal",
mimeType = "application/x-font",
advancedAntiAliasing="true",
embedAsCFF="true")]
public static const ArabicZ:Class;
}
}
This has expanded from a much simpler form as I added things to get it to work and I must have tried all permutations of true and false. I load the swf ok but then can't extract the class. With the two fonts I embedded before the swf class and the parameter all have the same name and they work fine (i.e.
Urdu.swf
then later:
var FontClass:Class = evt.target.applicationDomain.getDefinition("Urdu") as Class;
and then
Font.registerFont(FontClass.Urdu);
in the calling .as application with the above Arabic.swf I try
trace("1 Arabic "+evt.target.applicationDomain.hasDefinition("ArabicF"));
trace("2 Arabic "+evt.target.applicationDomain.hasDefinition("Arabic"));
trace("3 ArabicX "+evt.target.applicationDomain.hasDefinition("ArabicX"));
trace("4 ArabicY "+evt.target.applicationDomain.hasDefinition("ArabicY"));
trace("5 ArabicZ "+evt.target.applicationDomain.hasDefinition("ArabicZ"));
but all return false
PS also tried generating the Arabic.swf using fontswf.bat which again seems to make a very similar swf file which is loaded but I can't extract the class from it
PPS I'm using flashdevelop and the font swf are set up as AS3 standard project compiler options.
I don't use Flash Develop, but perhaps I can offer some perspective from my implementation.
If I wanted to embed Arial, the embedding swf would "Export for ActionScript" the embedded font. In its document class, use registerFont() as below:
Font.registerFont(Arial);
Like every other swf, you'd use a Loader to import it into your runtime, and at that point, the font will be available to your global table. You can query the complete list of registered fonts using enumerateFonts().
var fontList:Array = Font.enumerateFonts();
for (var i:int = 0; i < fontList.length; i++) {
trace(fontList[i].fontName);
}
Assuming we've got a TextField called "txt", you can then implement that font with setTextFormat() like so:
var format:TextFormat = new TextFormat();
format.font = "Arial";
txt.embedFonts = true;
txt.antiAliasType = AntiAliasType.ADVANCED;
txt.setTextFormat(format);
txt.defaultTextFormat = format;
A disclaimer from Adobe on the use of these last two settings:
"When you apply a TextFormat object to a text field using the
TextField.defaultTextFormat property or the TextField.setTextFormat()
method, only its defined properties are applied. Use the
TextField.defaultTextFormat property to apply formatting BEFORE you
add text to the TextField, and the setTextFormat() method to add
formatting AFTER you add text to the TextField."
As I said before, my workflow doesn't utilize Flash Develop, but rather Flash IDE to embed the fonts into the swfs. Your results may vary, but be aware you must set embedFonts to true, or it won't respond to your embedded font. I've lost hair on that issue before.
Hope that helps. Cheers,
OK In case someone else runs into similar problems this is stage one of the answer (really the answer to my original question) still have to sort out how to get the font to be used in the flash.font.engine apparatus!
The critical parts are:
Point #1. the embedded font swf must have a name that doesn't clash with ANY name registered in the calling script. Bizzare and (as far as I could search) undocumented. i.e. I have a list of languages uploaded via xml services to an xml object and that includes for instance 'English' however the font loading doesn't work until I make the loadable font file into 'EnglishF.swf' The obvious choice of just 'English.swf' fails. So my embedded font source is now called EnglishF.swf and reads:
package
{
import flash.display.Sprite;
import flash.text.Font;
import flash.system.Security;
Security.allowDomain("*");
/**
* ...
* #author patrick
*/
public class EnglishF extends Sprite
{
[Embed(source = "Kingthings Exeter.ttf",
fontName = "EnglishF",
fontFamily = "EnglishF",
fontWeight = "normal",
fontStyle = "normal",
mimeType = "application/x-font",
advancedAntiAliasing="true",
embedAsCFF="true")]
public static var myFont:Class;
}
}
and the using script goes:
private function fontLoaded(evt:Event):void {
var FontClass:Class
if (evt.target.applicationDomain.hasDefinition(font1Name)) FontClass = evt.target.applicationDomain.getDefinition(font1Name) as Class;
else if (evt.target.applicationDomain.hasDefinition(font2Name)) FontClass = evt.target.applicationDomain.getDefinition(font2Name) as Class;
try {
Font.registerFont(FontClass.myFont);
trace("successfully loaded " + FontClass);
} catch (err:Error) {
trace("couldn't register font "+FontClass.myFont+" =>"+err);
}
}
The line in the embedded script about security is because of point #2: the registerFont doesn't work across domains. In fact the Security.allowDomain() didn't work and to debug this I have had to copy/paste the swf files on the PC and change the loader.load(URLRequest()) accordingly
There is still an issue that although the font is registered and claims to be compatible with the flash.text.engine TextElement requirements it still fails to be used as in:
_tl = new Array();
var block:TextBlock = new TextBlock();
var font:FontDescription = new FontDescription(fontName);
var formt:ElementFormat = new ElementFormat(font, fontSize);
//following gives 'true EnglishF'
trace(FontDescription.isFontCompatible(fontName,"normal","normal"), formt.fontDescription.fontName);
formt.color = colr;
var span:TextElement = new TextElement(text, formt);
block.content = span;
_tl[0] = null;
_tl[0] = block.createTextLine(null, width);
var tl:TextLine;
// after here justification and addition lines
I will post something if and when I sort out why this doesn't work (Unless some kind person does it for me!)

AS3: Embedding characters

I having some trouble with TextFields and caracter embedding. As I have understood, the way to embed character in Flash, is to have a TextField in a movieclip that is exported to actionscript via some classname. Then have the TextField embed the characters.
But when i try to use that TextField in my project, I cannot auto resize the field any longer!? Is there a better way to embed charactes? or am I missing some unknow attribute? (and yes i have tried TextField.autoSize = "left" (or "center" or "right")).
The TextField is configured like this in Flash CS4:
Properties:
http://screencast.com/t/0VB6KnNO6G
Library implementation:
http://screencast.com/t/w3yQLqit0veI
And I embed the MovieClip containing the TextField like this:
protected var tabname:MovieClip = new Text(); // The property on the object
Adding the text and setting its Settings:
var txt:TextField = tabname.txt;
if( !contains(tabname) )
{
addChild(tabname);
var format:TextFormat = new TextFormat();
format.bold = true;
format.font = "Arial";
format.size = 12;
format.align = "left";
var dropShadow = new DropShadowFilter(0);
dropShadow.color = 0xFFFFFF;
dropShadow.strength = 2;
dropShadow.blurX = dropShadow.blurY = 5;
dropShadow.alpha = .7;
txt.type = TextFieldType.DYNAMIC;
txt.multiline = tabname.wordWrap = false;
txt.autoSize = TextFieldAutoSize.LEFT;
txt.defaultTextFormat = format;
txt.filters = [dropShadow];
txt.mouseEnabled = false;
txt.x = 10;
}
txt.text = value;
txt.y = Math.ceil((tabmask.height - txt.height) /2);
To embed fonts, don't rely on wrapping them in MovieClips in the library. They should be embedded correctly as Fonts. I have included some basic steps below for embedding fonts, then an example for your particular situation:
1 - Make the textfield Dynamic and click the Embed.. button
2 - Name the font with something meaningful (like the fonts name) and tick the character sets you will be using (usually I select caps, lowercase, numbers and punctuation). Also note the Style is 'Bold', you will need to embed a font set for each style. So if you want to use Bold and Regular, you need to embed 2 fonts.
3 - If you plan on adding textfields dynamically through ActionScript, goto the ActionScript tab and add a class for it (again, use a meaningful name)
4 - Finally click ok, and away you go. I have setup an example, using these steps, and the auto size method, you can see the results below
In Flash, you can click the [Embed...] button below the TextField's character properties. In the window that you get then, you can specify which characters you want embedded in your textfield.
There's a lot more to say about font embedding but this is the simple story. Flash CS5 added TLF TextFields but I don't think you were referring to those, right?
The autoSize property really has nothing to do with font embedding but I guess your TextField is not Dynamic when you cannot auto resize it?
Are you using CS5 or CS4 or earlier by the way?

How can you dynamically put different patterns on images in a webpage .

i have
A bunch of fabric patterns (simple jpg files)
An image for every letter of the alphabet(blank white background)
I essentially want to have a page similar to this:
http://www.craftcuts.com/hand-painted-wooden-letters-single-patterns.html
but instead of having it as a static page, i would like a user to be able to:
Type in a name
Choose a pattern (one of the jpg files)
and then have it display that name in that pattern.
Obviously i could create separate jpgs for every combination of letters (right now i have a jpg for every letter with white back color) and patterns but i wanted to find out if there was a more elegant way of coding this up to have it dynamically put one image onto the letter in the other.
EDIT: In my initial post, i assumed that this would have to be a front end thing (javascript), but if it makes it any easier (as a few people asked what is the backend), my back end is an asp.net-mvc so if there is some solution to build this up on the serverside and ship down to the client, i am more than happy using that as well.
You can apply background images to images using CSS, then use a load of transparent .png images for the letters.
I mocked it up:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
img.leaves
{
background:url("leaves.png");
}
img.lights
{
background:url("lights.png");
}
</style>
<script type="text/javascript">
function makeText()
{
var text = document.getElementById('text').value.toUpperCase();
var pattern = document.getElementById('pattern').value;
for(var i=0; i<text.length; i++)
{
var img = document.createElement('img');
img.src=text[i]+'.png';
img.className=pattern;
document.getElementById('textArea').appendChild(img);
}
return false;
}
</script>
</head>
<body>
<form onsubmit="return makeText();">
<p><label for="text">Enter your text</label> <input type="text" name="text" id="text" size="20"></p>
<p><label for="pattern">Choose a pattern</label> <select id="pattern"><option value="leaves">Leaves</option><option value="lights">Lights</option></select></p>
<p><input type="submit" value="Make!"></p>
</form>
<div id="textArea"></div>
</body>
</html>
and you can also see it in action.
alt text http://www.subdimension.co.uk/files/1/SO/A.png < this is one of the letter cutouts (difficult to see!)
alt text http://www.subdimension.co.uk/files/1/SO/leaves.png and one of the background patterns.
I got bored at G, so you can only write words that contain the letters a-g, it's also a little lazy in that it only does upper case and there are only 2 patterns but hopefully it should be enough to give you an idea
You could use the ImageMagick libraries to make any combination of superimpositions your and your users' hearts desire. This way, you're not limited to just something simple that can be achieved with CSS.
ImageMagick examples
The easiest way to do so via Javascript is probably to have an image mask of each letter and apply it on top of a pattern. By image mask I mean a simple image completely black (or white, or whatever you prefer) with a "cut out" transparent part in the shape of the letter. You can simply overlay that over the pattern file to get the wanted effect.
<div style="background: url(pattern.jpg)">
<img src="letter_a.png" />
</div>
You can dynamically change the img src and div background url to switch patterns and letters. You can also dynamically create new divs based on user input.
Note that this won't work easily in IE6 due to the transparent PNG.
Alternatively, you could generate the image dynamically on the server using something like gd, which would be a little more involved, but ultimately more flexible.
For users to be able to type in their own name you'll need a text field. You'll also need a button that fires a Javascript function that checks the value of the text field and renders the letter images.
You can use the following code to create the letters. You will need a textfield with the id 'textfield' and a div to render the results in with the id 'output', which ofcourse you can change. I recommend using a select element to store the pattern options (#patternChooser in this example)
function renderName()
{
// Get the name to be rendered and the chosen pattern
var text = document.getElementById('textfield').value;
var pattern = document.getElementById('patternChooser').value;
// Iterate over the name and create an element for each letter
for(i = 0; i < text.length; i++)
{
var letter = document.createElement('div');
letter.style.backgroundImage = 'url(' + pattern + '_' + text[i] + ')';
document.getElementById('output').appendChild(letter);
}
}
You can use the following CSS to apply some positioning to the letters (adjust the with and height to that of your images):
#output div
{
margin-left: 10px;
width: 50px;
height: 100px;
float: left;
}
You will need to name your images like this: flowerpattern_a.png, brickpattern_j.png, etc.
If you want the letters to appear real time you can use Javascript's onkeyup() to fire a function that checks the last character of the text field's value and creates an element for it.
Sprites
You can also use a sprite to increase performance. Put all the images for the letters into one image. You set this image as a background for every letter.
Quick read on CSS sprites: http://css-tricks.com/css-sprites/
You can add background-image: url(sprite.png); to the CSS snippet above.
Instead of just setting a backgroundImage with Javascript, you will need to set the background position of the letter (letter.style.background-position = '100px 200px')
Font embedding
If you got fonts to use: there are many font embedding options like Typeface and Cufon. The one I find most pleasant to work with is the use of font-face. It is fast and the text will behave like any other text.
If you got your .TTF Truetype font, you'll need to convert the font to .EOT for use with Internet Explorer. You could also add SVG fonts for full browser coverage. It's actually very easy: You just add the following snippet to the top of your stylesheet like this:
#font-face {
font-family: 'GothicCustom';
src: url("LeagueGothic.eot");
src: local('League Gothic'),
url("LeagueGothic.svg#lg") format('svg'),
url("LeagueGothic.otf") format('opentype');
}
The advantage of this technique is that it's easy to use and you got full controll over the rendered text, like any other text on your website. You can set the font-size, letter-spacing etc. Here's a good read about font-face font embedding.
You can use Microsoft WEFT or TTF2EOT to create .EOT fonts.
For example, your code could look like this.
Javascript
function renderName()
{
// Get the name to be rendered and the chosen pattern
var text = document.getElementById('textfield').value;
var pattern = document.getElementById('patternChooser').value;
// Render the text with a class
for(i = 0; i < text.length; i++)
{
var output = document.getElementById('output');
output.style.fontFamily = pattern;
output.innerHTML = text;
}
}
HTML
<form>
<input id="textfield" type="text" />
<select id="patternChooser">
<option>Flowers</option>
<option>Brick</option>
<option>Decorative</option>
</select>
<input type="button" onclick="renderName()" />
</form>
<div id="output"></div>
CSS
#font-face {
font-family: 'Decorative';
src: url("decorative.eot");
src: local('Decorative'),
url("Decorative.svg#lg") format('svg'),
url("Decorative.otf") format('opentype');
}
Now the only thing that is left is converting the fonts and import them in your stylesheet.
Ofcourse you can choose to go with any other font-embedding method. Here's an article about font-embedding options but a quick Google will show you the options as well.
If you are allowed to use something in the back-end, here is a java solution. You will just need the font (name.ttf) with which you type the letters, but I assume you have it:
(this is inside a servlet doGet method)
String text = "A letter, or any text here";
File texture = new File(patternTexturePath);
File fontFile = new File(filePath);
Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(font);
BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2 = buffer.createGraphics();
g2.clearRect(0, 0, width, height);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
FontRenderContext fc = g2.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(text, fc);
AttributedString attrStr = new AttributedString(text);
Rectangle r = new Rectangle(0, 0, width, height);
attrStr.addAttribute(TextAttribute.FOREGROUND, new TexturePaint(ImageIO.read(texture), r));
attrStr.addAttribute(TextAttribute.FONT, font);
g2.drawString(attrStr.getIterator(), 0, (int) -bounds.getY());
response.setContentType("image/png");
ImageIO.write(buffer, "png", response.getOutputStream());
response.getOutputStream().close();
Even on the server this is not a trivial issue, as it is not possible to do a direct Fill() using a color mask, which is esentially what you need.
I would sooner loop over the existing pixels, do a lookup and write the pattern pixel to the resulting image if the letter image is non-white:
Graphics g = Graphics.FromImage(letterImg);
Brush brush = new System.Drawing.TextureBrush(patternImg);
for (int x=0;i<letterImg.Width;i++)
for (int y=0;y<letterImg.Height;y++)
{
Color mask = img.GetPixel(x,y);
//Color pattern = patternImg.GetPixel(x % patternImg.Width, y % patternImg.Height);
if (mask != Color.White)
{
g.FillRectagle(brush,x,y,1,1);
}
}
And then find a naming scheme to cache these on the disk after creation so you only need to render each pattern<->letter combination once.
GDI+ works fine under ASP.NET. (WPF used to, but then was broken with a service pack. Not sure if it's working again now).
Building images server-side is pretty easy - the trick is linking them to client-side requests. I made use of a stack representation - my article here:
http://www.hackification.com/2008/10/29/stack-based-processing-part-2/
After confirming with OO (the poster) I wanted to throw Flash in the mix.
Flash has the advantage that it has really nice anti-aliasing and awesome typography support (especially since CS4). You could choose to have the entire interface in Flash where you type the patterned letters directly or just have the swf render the result according to parameters specifying the name and the pattern.
Personally I would make the whole thing in Flash, supplying the interface with the optional patterns with for instance JSON. But the most basic steps you could take are
create a form with input for the name and a select box for the patterns
display the flash file with parameters patterntype.swf?name=flash&pattern=disco.png
The basic concept is having the Text set as the mask for the pattern.
I did a quick test in flash to test the performance of tiling the pattern (and if it would actually work)
package {
import flash.display.MovieClip;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
public class PatternType extends MovieClip {
/* library element, use the textfield to change the font */
public var nameDisplay:NameDisplay;
private var loader:Loader;
/* parameters, you can pass these as request parameters, or make a javascript call to get/set them */
private var pattern:String = "pattern.png";
private var nameString:String = "Heidi Klum";
private var container:MovieClip;
public function PatternType() {
container = new MovieClip();
addChild(container);
nameDisplay = new NameDisplay();
nameDisplay.txt.text = nameString;
nameDisplay.cacheAsBitmap = true; //mask wont work without this.
container.addChild(nameDisplay)
container.mask = nameDisplay;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handlePatternLoaded);
loader.load(new URLRequest(pattern));
}
private function handlePatternLoaded(e:Event) {
trace("complete");
var bmp:Bitmap = e.target.content as Bitmap;
var rows:int = Math.ceil(stage.stageHeight / bmp.height);
var cols:int = Math.ceil(stage.stageWidth / bmp.width);
//tile the texture
for(var i:int = 0; i < cols; i++) {
for(var j:Number = 0; j < rows; j++) {
var b:Bitmap = new Bitmap(bmp.bitmapData.clone());
b.x = i * bmp.width;
b.y = j * bmp.height;
container.addChild(b);
}
}
}
}
}
When everything is to the users wishes, you can create a new Bitmap object from the result and send the data to the server which can write the data directly to a bitmap file (jpeg is also possible).
A few things that could sell Flash a bit more:
you can rotate the text
use exotic fonts
use different patterns per letter
scale the text
use custom made image filters
move in 3d space (x,y,z translation rotation, perspective)
Save the result as an image
Read the link below here you will find the dynamic loader details alonmg with example
http://thecodecentral.com/2008/02/21/a-useful-javascript-image-loader