Skip to main content

News

Topic: How can I Import a font from an Image file? (Read 3463 times) previous topic - next topic

How can I Import a font from an Image file?
I want to use font from MOTHER (Earthbound Zero) and I have an image that has all the letters I need, how can I arrange this so it can be imported and used as font in sphere?
Also I want the font to look sharp, no antialising-whatever.

  • DaVince
  • [*][*][*][*][*]
  • Administrator
  • Used Sphere for, like, half my life
Re: How can I Import a font from an Image file?
Reply #1
There's several ways:

1. Create an rfn file and individually copy/paste the characters in the appropriate spots. Make sure to make the black background transparent.
2. Create a dummy rfn and then write a script that will get the separate character pictures for you from the above picture and put them in that dummy rfn using Font.setCharacterImage(). It's recommended that you edit the above picture so those borders aren't in it (unless you want to add an offset to your script to handle that).

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #2
I'd go with DaVinces #2, In fact I'll do it right now to see if it work in Sphere-sfml.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #3
Okay, since the images characters were not aligned to the standard ASCII ordering, a mapping had to be made, which is used to figure out two things: where to cut, and where to put it.

Attached is a sample project that only grabs the regular-weight letters.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: How can I Import a font from an Image file?
Reply #4
What is the standard ASCII order?
I can manipulate the image and re-arrange the font that way.

:o I sort of understand whats going on but have no idea how the code works, where is the font saved
and how would I display it?... thanks though.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #5

What is the standard ASCII order?
I can manipulate the image and re-arrange the font that way.

:o I sort of understand whats going on but have no idea how the code works, where is the font saved
and how would I display it?... thanks though.


The standard ASCII order goes like this:
http://www.asciitable.com/

No, you don't have to put it into the standard order, that would take a lot of time cutting and pasting, etc. for no gain at all.

What it does is cut out sections of the image and put them into a font in the correct ASCII order. In order to do that I created a mapping that said: this letter goes here that letter goes there. Cut and move enough times and then you have the font finished. It saves the font to the file font.rfn in the /fonts folder. So you run it once - it's what's called a utility script - and then look for the font in the /fonts folder.

After that you can use it in your game like any other font:
Code: [Select]

function game()
{
    var font = LoadFont("font.rfn");
    while (!IsKeyPressed(KEY_ESCAPE)) {
        font.drawText(0, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        FlipScreen();
    }
}


How it works:

The reg-map is a glyph mapping of the light weight characters (the first 150 or so). It maps the letter as it appears in the image to an index in an array, this is used to know what letter went where in the image. This is not magic; this is not pattern recognition; this is just a hand-made thing that I had to use my eyes to figure out.
Code: (javascript) [Select]

var reg_map =
[
"!", "?", "_", "$", "\"", "'", "(", ")", ":", ";",

//...

"7", "8", "9"
];


The next bit was to create a single function that went through and stripped the image of it's glyphs. A glyph is a single character in a typeface. First I initialized the operation, by loading the fontname and imagename supplied. I then give x and y a starting location. We can't cut images out from exactly the top-left of the image, there has to be an offset. If you notice the first image is an 8x8 sprite that starts 24x24 into the image. So I set x and y to the initial offsets.

Code: (javascript) [Select]

var font = LoadFont(fontname);
var rip  = LoadSurface(imagename);
var x = ox, y = oy;


Next, I loop through the mapping so I can cut images out and put them into the blank font file. I do this by cloning a section of the image each pass. I call createImage() because the font takes images - not surface objects. After that I check to see what character is at the map at that position, if it's blank I do nothing, however if it exists in the ASCII table somewhere (I call charCodeAt() to get that part) then I put the image into the font at that standard ASCII position.

Code: (javascript) [Select]

for (var i = 0; i < map.length; ++i) {
var image = rip.cloneSection(x, y, c_width, c_height).createImage();

if (map[i] != "") {
var ch = map[i].charCodeAt(0); // find the character in the standard ASCII table
image.blit(0, 0); // this is was used for debug reasons; ignore it.
font.setCharacterImage(ch, image); // set the glyph to this image
}


Next I add to the x offset the width of the glyph which is 8 pixels. But they are 8 pixels apart so I had that as well. If you look at the image in an image editor and turn on a grid and set that grid to 8 or 16 pixels you'll see what I mean. Now I can add to x forever, so once I know it got all the way to the right edge of the image, I then increment the y axis by the same amount and start stripping the second line.

Code: (javascript) [Select]

x += c_width + x_pad; // add to x the withd of the character and it's offset to the next character
if (x == scan) // if we moved the x-coord to the end of the image, return to a new line
{
x = ox;  // reset x
y += c_height + y_pad; // and increment y, just like we did with x.
}
}


The process finishes when all items in the glyph mapping are finished. Add more to the mapping adds more to the font. But I had to be caregul there, it can't detect bold weighted characters over light weighted characters: it doesn't do any fancy image manipulation at all besides cut squares out of the sheet one at a time.

Finally I account for the space by creating a glyph like so:
Code: (javascript) [Select]

var surf = CreateSurface(c_width, c_height, CreateColor(0, 0, 0)); // create a blank glyph
font.setCharacterImage(" ".charCodeAt(0), surf.createImage()); // and put it in as the space character


And then it saves it to a file:
Code: [Select]

font.save(outfile);


The single line of code in the game function calls the stripping function, giving it all of the parameters needed to strip characters from the image. So in theory my code should work for any ripped font from any game as long as the characters are evenly stored (such as the mother ones you supplied).
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: How can I Import a font from an Image file?
Reply #6
Wow cool!
I'm going to study this and make a similar script from another image with evenly spaced font so I can soak in this experience (still think its magic *joke*). This is a very useful utility. Thanks again Radnen you always help and explain even the most complex programming  (^_^).
  • Last Edit: July 27, 2013, 04:04:33 pm by Xenso

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #7
You are free to create as many versions as you want!

My script was built to be used on many different images not just the one image. A good program is one that can be reused as much as possible. If you have to make a converter for each different image well, you are doing something wrong: it's a good idea to see where the common parts are and turn those into tweak-able parameters so that you can change them whenever you need to do somethining similar on a different object. ;)
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • DaVince
  • [*][*][*][*][*]
  • Administrator
  • Used Sphere for, like, half my life
Re: How can I Import a font from an Image file?
Reply #8
It's a useful script, Radnen. Should be included in some standard tools somewhere, really. :)

Question based on the code posted above: why is your map an array instead of a string? I mean, why did you decide on the above and not something like this?

Code: (javascript) [Select]
var reg_map = "!?_$\"'():;";

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #9
Because blank characters: "" would be impossible. ;)

I still need to modify it a bit. But yeah I intended for it to be a reused tool, I also have a font outliner/gradient tool written in Sphere.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • N E O
  • [*][*][*][*][*]
  • Administrator
  • Senior Administrator
Re: How can I Import a font from an Image file?
Reply #10
The original Sphere editor has a built-in image-to-RFN converter, but it's very Windows-only. I'd love to see it ported to more cross-platform code. ;)

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: How can I Import a font from an Image file?
Reply #11

The original Sphere editor has a built-in image-to-RFN converter, but it's very Windows-only. I'd love to see it ported to more cross-platform code. ;)


I'm sure my code would do it. In fact it does. It would even support 1-pixel borders.

Code: (javascript) [Select]

var map =
[
"" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" ,
"" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" ,
" ", "!", "\"", "" , "$", "" , "" , "'", "(", ")", "" , "" , ",", "-", ".", "/",
"" , "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "" , "" , "" , "?",
"" , "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "" , "" , "" , "" , "_",
"" , "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
];

function game()
{
// if no border remove the 1, 1 the other 1, 1, and set it to width 128 rather than 129.
Strip("blank.rfn", "compiled.png", 1, 1, 129, 8, 8, 1, 1, map, "font.rfn");
}


Anyways, It can't handled variable width fonts though. I'll have to look into that, but that's a different algorithm entirely. This one works as well as it does because it assumes each character is the same width throughout, and so is pretty fast. The above mapping can be used for any fixed width font that was generated to an image by Sphere. It stops at the lowercase though so you'll have to append letters to it if you want to reach the rest (and fill in the blanks with any letters that might exist).
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here