Font Editor (preview #5)
I'm working on this font editor. It's mostly for LCD screens and LED panels.
But, I've added some options to import the font from "VGA_HiRes_Text.spin".
You can then export it and paste it back in. Run the stock "VGA_HiRes_Text_Demo" to see your font on a VGA screen.
Fonts are saved as ".rfd" files.
This program is self-contained, so just extract it anywhere and run it:
RaysFontEditor_24Aug12.zip 'Updated version 0.5
But, I've added some options to import the font from "VGA_HiRes_Text.spin".
You can then export it and paste it back in. Run the stock "VGA_HiRes_Text_Demo" to see your font on a VGA screen.
Fonts are saved as ".rfd" files.
This program is self-contained, so just extract it anywhere and run it:
RaysFontEditor_24Aug12.zip 'Updated version 0.5
Comments
I've looked at a number of font solutions. I've ended up using a free program to create a bitmap of all the fonts, then a custom vb.net program to turn that into a file that can be loaded rapidly off an sd card. It is a solution that works for any font and means you can use any font editor out there to build a new .fon file, then convert it when it is done.
Hmm - that is a bit confusing to explain. At the end of the day, it is about a 30second process to create a font file.
However I've never been entirely happy with it being in vb.net as that is not a program that can be run on linux/mac etc. Maybe we can share some code here?
This is written in MFC, so there's no way it will work on Linux (well, at least not without VirtualBox).
If you tell me about your .fon format, I can try to include that for you though.
I have been using this free program to convert true type fonts into bitmaps http://www.angelcode.com/products/bmfont/
That generates two things, a bitmap picture, and a text file that tells you where each character is in the picture. That in itself could be decoded by a spin program. However, I process that a bit more and combine them into one file which has a jump table at the beginning and also changes the foreground and background color to whatever you want. That means that you can get the pixel data for a character quickly - take the ascii value which points to the jump location in the header and the width and height and number of pixels, jump to that location, and then read off the pixels. This preprocessing makes the retrieval fast. This is the spin code to print a character:
PUB TextChar(FileN,ascii,x,y) | jump,size,width,height,ramaddress,xoffset,yoffset,xadvance ' read out a character from a .ifn file stored in ram ' pass Fonttable = global ' moves to next line if off the end ramaddress := RamLocation[FileN] jump := ReadRamLong(ramaddress,(ascii << 2) + 256) ' jump location = ascii *4 plus fonttable + 256 SpinRamToHub(@buffer2,ramaddress+jump>>1,20) ' read in the width height as a block = quicker than readramlong size := long[@buffer2][0] ' size in pixels of this character xadvance := long[@buffer2][5] ' amount to move to next character 'if size > 0 and ascii <> 32 ' no need to print anything if size is zero or read more font data width := long[@buffer2][1] ' width height := long[@buffer2][2] ' height xoffset := long[@buffer2][3] ' xoffset to move yoffset := long[@buffer2][4] ' yoffset to move if (x+width -1 + xoffset) > screenwidth crlf ' do a new line if it won't fit x := curx y := cury if ascii < 32 xadvance := 0 ' add nothing if a non displaying character if ascii == 13 ' carriage return cr x := curx if ascii ==10 ' line feed (new line) lf y := cury if ascii > 32 ' space not displayed Draw(x+xoffset,y+yoffset,x+width-1+xoffset,y+height-1+yoffset) ' draw on screen RamToDisplay(ramaddress+((jump+32)>>1),size) ' move bytes from ram out to the display return x + xadvance
If this is helpful I can give you the vb.net code to produce these font files.
As for editing fonts, hmm, that is a separate issue. Truetype or bitmap fonts?
Sorry about the delay. The angelcode program takes a .ttf font file and produces two files - a text file and a png graphic. I save the text files with a .fnt extension.
The png file is white on black and you can use the grayscale to convert from any foreground and any background.
I'll post the full vb.net program below, but this is the routine to load up the .png and .fnt files and draw the png on a picturebox
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim Filepath, Sourcefile, DestinationFile, pngfile As String Filepath = TextBox2.Text ' directory OpenFileDialog1.Multiselect = False OpenFileDialog1.InitialDirectory = Filepath OpenFileDialog1.FileName = "*.fnt" ' select .fnt file. OpenFileDialog1.ShowDialog() ' open the openfile dialog Sourcefile = OpenFileDialog1.FileName ' get the filename Sourcefile = Strings.Mid(Sourcefile, Strings.Len(Filepath) + 2) ' strip off directory pngfile = Strings.Left(Sourcefile, Strings.Len(Sourcefile) - 4) + "_0.png" Dim img As Image Dim fs As New FileStream(Filepath + "\" + pngfile, IO.FileMode.Open) ' open the picture img = Image.FromStream(fs) ' load in the file fs.Close() ' close the picture PictureBox3.Image = img ' display the picture RichTextBox1.LoadFile(Filepath + "\" + Sourcefile, RichTextBoxStreamType.PlainText) TextBox3.Text = Sourcefile TextBox4.Text = Strings.Left(Sourcefile, Strings.Len(Sourcefile) - 4) + ".ifn" End Sub
Then you can use a color selection box to change the colors (eg white on black to black on white).
This is the code that does the conversion
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click Dim FontArray(262144) As Byte ' won't need all of this! Dim Ascii, x, y, i, j, Width, Height, Xoffset, Yoffset, Xadvance, Fontvalue As Long Dim RedDiff, GreenDiff, BlueDiff, Backred, BackGreen, BackBlue, ForeRed, ForeGreen, ForeBlue As Single Dim ILIred, ILIgreen, ILIblue As Single Dim ILIredbyte, ILIgreenbyte, ILIbluebyte As Long Dim ILIlong As Long Dim ILIhigh, ILIlow As Byte Dim Mycolor As Color Dim MyBitmap As New System.Drawing.Bitmap(PictureBox3.Image) 'image from picture box Dim LineOfText As String Dim Counter, StartCharacter As Long Dim Header As String Dim FontHeight As Byte Dim start1, start2, finish1, finish2, loopstep1, loopstep2 As Long Backred = PictureBox5.BackColor.R BackGreen = PictureBox5.BackColor.G BackBlue = PictureBox5.BackColor.B ForeRed = PictureBox4.BackColor.R ForeGreen = PictureBox4.BackColor.G ForeBlue = PictureBox4.BackColor.B RedDiff = Backred - ForeRed GreenDiff = BackGreen - ForeGreen BlueDiff = BackBlue - ForeBlue Counter = 256 + 1024 ' first 256 bytes are data about the font - size, bold, back and foreground colors etc and the next 1024 are the jump tables StartCharacter = Counter Header = "Portrait " Header += "Forecolor" + Strings.Chr(ForeRed) + Strings.Chr(ForeGreen) + Strings.Chr(ForeBlue) Header += "Backcolor" + Strings.Chr(Backred) + Strings.Chr(BackGreen) + Strings.Chr(BackBlue) For Each Line As String In RichTextBox1.Lines ' much faster than for i=0 to richtextbox1.lines.length LineOfText = Line If Strings.Left(LineOfText, 4) = "info" Then Header += LineOfText ' add this line to header string End If If Strings.Left(LineOfText, 6) = "common" Then FontHeight = Strings.Val(Strings.Mid(LineOfText, 19, 2)) End If If Strings.Left(LineOfText, 7) = "char id" Then 'char id=32 x=96 y=21 width=1 height=1 xoffset=0 yoffset=23 xadvance=7 page=0 chnl=15 Ascii = Strings.Val(Strings.Mid(LineOfText, 9, 3)) ' sub 17 x = Strings.Val(Strings.Mid(LineOfText, 16, 3)) y = Strings.Val(Strings.Mid(LineOfText, 24, 3)) Width = Strings.Val(Strings.Mid(LineOfText, 36, 3)) Height = Strings.Val(Strings.Mid(LineOfText, 49, 3)) Xoffset = Strings.Val(Strings.Mid(LineOfText, 63, 3)) Yoffset = Strings.Val(Strings.Mid(LineOfText, 77, 3)) Xadvance = Strings.Val(Strings.Mid(LineOfText, 92, 3)) StartCharacter = Counter ' start of the data about this character LongtoArray(FontArray, (Ascii * 4 + 256), StartCharacter) ' 4 byte jump table LongtoArray(FontArray, StartCharacter, Width * Height) ' size of the character LongtoArray(FontArray, StartCharacter + 4, Width) ' width LongtoArray(FontArray, StartCharacter + 8, Height) ' height LongtoArray(FontArray, StartCharacter + 12, Xoffset) ' xoffset LongtoArray(FontArray, StartCharacter + 16, Yoffset) ' yoffset LongtoArray(FontArray, StartCharacter + 20, Xadvance) 'xadvance Counter += 32 ' start of the pixels - add 32 start1 = y ' outside loop start2 = x ' inside loop finish1 = y + Height - 1 finish2 = x + Width - 1 loopstep1 = 1 ' add 1 to each step loopstep2 = 1 For j = start1 To finish1 Step loopstep1 For i = start2 To finish2 Step loopstep2 'If RadioButton1.Checked = True Then Mycolor = MyBitmap.GetPixel(i, j) ' get the color 'Else 'Mycolor = MyBitmap.GetPixel(j, i) ' swap i and j if in landscape mode 'End If Fontvalue = Mycolor.R ' grayscale so RGB should be the same ILIred = Backred - (RedDiff * Fontvalue) / 255 ILIgreen = BackGreen - (GreenDiff * Fontvalue) / 255 ILIblue = BackBlue - (BlueDiff * Fontvalue) / 255 If ILIred > 255 Then ILIred = 255 ' limit testing If ILIred < 0 Then ILIred = 0 If ILIgreen > 255 Then ILIgreen = 255 If ILIgreen < 0 Then ILIgreen = 0 If ILIblue > 255 Then ILIblue = 255 If ILIblue < 0 Then ILIblue = 0 ILIredbyte = CByte(ILIred) ILIgreenbyte = CByte(ILIgreen) ILIbluebyte = CByte(ILIblue) ILIredbyte = ILIredbyte >> 3 ' round down 3 places ILIgreenbyte = ILIgreenbyte >> 2 ' round down two places ILIbluebyte = ILIbluebyte >> 3 ' round down 3 places ILIlong = (ILIredbyte << 11) + (ILIgreenbyte << 5) + ILIbluebyte ILIhigh = HighByte(ILIlong) ' get high and low bytes ILIlow = LowByte(ILIlong) FontArray(Counter) = ILIlow ' store the pixels FontArray(Counter + 1) = ILIhigh Counter += 2 Next Next Counter += 4 ' so last pixel included ** this doesn't work, not sure why, file looks ok in hexedit ** Counter = Counter And &HFFFFFFFC ' mask off lower 2 bits, same as rounding to the nearest long so data is long aligned End If Next ' store the size of the array at the beginning of the array ' because it is much easier to read in blocks of 256 bytes, round up Counter = Counter + 256 ' round up by one block Counter = Counter And &HFFFFFF00 ' mask off lower 256 - same as rounding up LongtoArray(FontArray, 0, Counter) ' add counter to array at location 0 (file length) ' put in the header string For i = 1 To Strings.Len(Header) FontArray(i + 3) = Strings.Asc(Strings.Mid(Header, i, 1)) Next ' Store a byte for the height in a fixed location - easier to decode For i = 1 To 6 FontArray(i + 244) = Strings.Asc(Strings.Mid("Height", i, 1)) ' so can see the start of the jump table Next FontArray(251) = FontHeight ' store some text For i = 1 To 4 FontArray(i + 251) = Strings.Asc(Strings.Mid("Jump", i, 1)) ' so can see the start of the jump table Next Dim DestinationFile As String DestinationFile = TextBox2.Text + "\" + TextBox4.Text Dim OutputILI As New FileStream(DestinationFile, FileMode.Create, FileAccess.Write) OutputILI.Write(FontArray, 0, Counter) ' save bytes OutputILI.Close() MsgBox("Finished") End Sub
Attached are the vb.net program (in ILI9325.zip) and three font files, the .png, .fnt and the output .ifn file. The .ifn one is the one that spin code in the previous post can decode.
The font is stored as one word per pixel suitable for touchscreens ie RRRRRGGG_GGGBBBBB
The catch here is that when you store fonts as raw pixels most fonts end up 30-60k in size, and if you want to read characters quickly then you need external ram rather than reading each one off the sd card. I think you have some external ram working, is that correct?
Reading your last post, I think you want 16 bpp, but that winds up bigger than what you can hold in the Propeller...
My font editor works in 24 bpp, so it can generate the 16 bpp you want.
But, personally, I think 1 bpp is the best way to go for LCD screens, at least initially.
Small size fonts really don't get anti-aliased anyway, so you don't really gain anything in 16 bpp, except for the ClearType effect.
I do actually have some code to send out the propeller font using the more traditional method and I use that for bootup messages, in particular messages related to starting up the SD card because if the SD card is not working you can't display a font off the SD card. The catch is that it is slower.
PUB Propfont_out(ascii) | address,pixels Draw(curx,cury,curx+15,cury+31) ' location to start drawing address := $8000 + (ascii >> 1) << 7 ' get rom address repeat 32 ' 32 rows per character, split in two parts pixels := long[address] ' get rom font data pixels := pixels >> (ascii & 1) ' shift for odd characters repeat 16 ' 16 columns if pixels & 1 Pixel(%00000111_11100000) ' foreground color RRRRRGGG_GGGBBBBB else Pixel(%00000000_00000000) ' background color pixels := pixels >> 2 ' alternate pixels interleaved so shift 2 address += 4 curx +=16 if curx >239 ' new line Propfontcrlf
One thing that could be possible is to take that code and turn it into pasm and then it should be a lot faster and fonts will be a lot smaller.
The angelcode font program has a checkbox for outputting aliased or non aliased fonts so we could think about non aliased fonts with 32 pixels per long and which will be 1/16th of the size compared with aliased bitmap ones. An advantage is that you could change the foreground and background colors on the fly. A disadvantage will be that the code for variable width fonts will be more complex.
Your thoughts?
http://www.mikroe.com/eng/products/view/683/glcd-font-creator/
which works with a .LCD file, in ascii format, one example, snipped for size.
Looks to store 24bpp, but as just one of two values for a Monochrome Font.
This would be a good file format to support ?
53='5', and I think this stores left-column first (ie Top-Left, DecY ,DecX order) 0=ON ?
<?xml version="1.0" encoding="iso-8859-1"?> <FONT> <FONTNAME>TerminalB9</FONTNAME> <FONTSIZE WIDTH="6" HEIGHT="12" PROPORTIONAL="0" FONTKIND="0"/> <RANGE FROM="32" TO="127"/> <CHARS> <CHAR CODE="32" PIXELS="16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215"/> .. removed chars.. <CHAR CODE="53" PIXELS="16777215,0,0,0,0,0,16777215,16777215,0,16777215,16777215,16777215,16777215,0,0,0,0,0,16777215,16777215,0,0,16777215,16777215,16777215,0,16777215,16777215,16777215,0,16777215,16777215,16777215,0,16777215,16777215,16777215,0,16777215,16777215,16777215,0,0,0,0,0,16777215,16777215,16777215,0,16777215,16777215,16777215,16777215,0,0,0,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215"/> </CHARS> </FONT>
I think I have decided that the ROM font works well on this 5" Newhaven LCD, so it may be moot there.
Still, for large text, and for reading, the cleartype effect helps a lot. I think I can do it with 4 bpp though...
jmg, that program looks a lot like what I'm trying to do... Maybe I wouldn't have done this if I'd found that one... Still, I think mine is unique in capturing the Parallax font with it's code page (I'm hoping to make an on-Prop spin editor, so I'll want that...) and also outputting to VG_HiRes_Text . That format looks fine.
http://terminus-font.sourceforge.net/
The sizes present are 6x12, 8x14, 8x16, 10x18, 10x20, 11x22, 12x24, 14x28 and 16x32.
The styles are normal and bold (except for 6x12), plus EGA/VGA-bold for 8x14 and 8x16.
I see your Font Editor imports in Pixels, or Point, whilst the glcd-font-creator I linked above, imports in Point only, and so getting the wanted Pixel XY is more of a lottery.
glcd-font-creator does have a Export Range feature, but it annoyingly lacks a Raster-Order choice (and defaults to a dY scan).
The ideal is to
* Export each Char with the Char as a comment, (allows users to cut/paste/merge)
* Give users the choice of Mirror X, Mirror Y and dX or dY raster scan exports
Most assemblers I've used support DB and DW tables, but I cannot see that mentioned in the Prop Assembler reference, it would be a useful option.
Maybe we can think about a format for fonts for the propeller?
Good idea, see the example in #10.
That is ASCII, so is easy to parse, is text editor friendly, and it has the support of a free viewer.
hehe, I think that is targeting Fixed-width LCDs, but there is nothing preventing allowing an optional field of
WIDTH="6" HEIGHT="12"
on a per-character basis (usually only one would vary, in the plot direction, if you expected both to vary, then the issue of handling offsets occurs.You would need to scan the file and build a separate index table if you wanted to remove the dead-space, and the Free Viewer would likely break.....
On some instances, simpler indexing might be more important than smallest size (eg Font in QuadSPI ), but for RAM hosted fonts, smallest overall footprint would be the target.
I do like the idea of an ascii readable font. For speed of processing, would you make the text for something like "width" always a fixed number of characters? That might make the conversion quicker, eg if you had leading zeros then the position of the text describing the width is always in a fixed location so you can do a simple "ascii to value" conversion.
I built a jump table at the front of the font as it makes it quicker to send out the pixels. Still, it takes about one and a half seconds to dump out all the display in this photo. I have a vague feeling that if you gave up aliasing and just went for white and black, plus a pasm driver, plus smaller font files, this could be dumped to the display quicker.
I'm not completely following the question, but assuming too much about the format can be dangerous, as it may be Auto-created.
Taking the example above, of
WIDTH="6"
Usually you would 'key' off 'WIDTH=', or perhaps even 'WIDTH="', and then trim using the next ", which should leave a number string, which could be in any base.
The time needed to work on ASCII files is not important, as you usually finally create a Table, which is then assembled/compiled.
eg the glcd-font-creator above is somewhat sluggish in load/trim/export, but 10 seconds is not a big problem.
Byte alignment (none, 1, 2, 4)
Scan direction (8 different ways)
Bits per pixel (1,4,8,24)
This is for fixed-width. For variable width, I was thinking about having all characters still taking the same # of bytes to define plus 1 byte to say the width. That way, you can quickly index the characters... But, this takes up more space than necessary, so I'm still mulling it over...
If you are looking for suggestions for your font editor, these are the 'peeves' I found with glcd-font-creator
* It lacks raster order export choices, (seems to always TopLeft, dY then dX) - needs Mirror X, Mirror Y, Scan X.Y and Y.X choices.
* It can insert/delete rows, but ONLY on the edges, so (eg) making a taller variant is more work than it should be.
Insert row/column choices of Black/White/Clone Present row would almost eliminate pixel-clicking.
* It lacks a screen-preview mode, your's is way ahead there. Allows a screen capture font thumbnail record.
Pluses :
It has a simple ASCII file, so a user can always add external code to fix some of this.
Sounds great. When you say 'binary' do you mean ASM type source ?
There, I would add each Char value as a comment, and allow DB 12H,34H,... and DW 1234H,5678H, ... syntax.
I've struck some assemblers that choke above some line-length, so an ASM line length option would fix that.
ie if practical I prefer one line per char, but larger fonts, and Colour, will give long lines.
Perhaps an option ? As you say, Fixed is simpler and Serial flash is dirt cheap, but someone may want to target RAM use, and RAM is precious indeed on a Prop.
The most compact would be a separate byte-sized width table, and you simply run through that, adding the widths to find your packed Char index. Code to run-sum should be << the alternative N.Words index array.
Or maybe all 3 : Simple/Compact/Fast, but that may be over-doing a font editor... ?
One that you can include in Prop Tool like this:
DAT 'bitmap font data font long file "ProgoCo.dat"
I do like that XML output format, BTW. I also like the idea of defining a range of characters to output.
In some cases, you might only want to define the "normal" characters...
So that is an ASM source file ? - like you export now as :
long $00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000 long $ffffffff,$00000000,$ffffffff,$00000000,$00000000,$00000000,$00000000,$00000000 etc
So I would suggest also doing what we do here, which is Asm DB, with ASM comments like :
; ReverseX=Y ; ReverseY=N; Width=8; Height=16 ;xx12345678 ASCII No / Index : 1 ;1 ###### ;2 # # ;3 # # # # ;4 # # ;5 # #### # ;6 # ## # ;7 # # ;8 ###### DB 07EH,081H,099H,0BDH,081H,0A5H,081H,07EH
The AsciiArt is what you expect to see, the DB may be bit-flipped( with perhaps DW option, but then an endian choice may be needed...)
This would allow using almost any assembler to create large hex files for Font ROMs
Yes, and in other cases, you may wish to merge fonts from multiple archives/sources...
WIDTH=6
HEIGHT=12
then if you have a bigger font
WIDTH=15
HEIGHT=12
the position of "H" changes and then you have to search for a string which takes more time. I was thinking you write
WIDTH=06
HEIGHT=12
and then H is always in the same place in the file.
Another idea - instead of writing in longs, what about writing in binary. Assume all fonts will be less than 32 wide (probably true). Ok it wastes a bit of memory for small fonts but it very much simplifies both editing and processing. eg an A
WIDTH=05 HEIGHT=06 long %00100000_00000000_00000000_00000000 long %01010000_00000000_00000000_00000000 long %10001000_00000000_00000000_00000000 long %11111000_00000000_00000000_00000000 long %10001000_00000000_00000000_00000000 long %10001000_00000000_00000000_00000000
binary output means that for, e.g., this 8x16 x 1bpp font, the first 16 bytes in the file represent the 1st character...
but why work in hard-to--check binary, given you import into a compiler, or assembler, anyway, to create the full run-time ?
( or assemble multiple files to a HEX file for loading a Font-rom).
I'm not following the issue here ?
On a PC, who cares how many microseconds a string search adds ?
On the target, you would not work with full ASCII-parser record files, you would use equates, or DB/long arrays, and even there
the source-file size is a total 'don't care' these days, so I create for clarity.
And for more efficiency regarding file size, maybe have two file types - one for "bytes" and one for "longs", ie ones that are 1-8 pixels wide and ones that are more than 8 pixels wide? Then you could display both in a way that you can edit easily as you can see the pixels.
ah - miscommunication there, I was thinking you wanted an ascii file on the target.
Many possibilities here. I wonder if one solution is to produce an ascii file that is actually code you can paste into the DAT section of code?
he he - how about a program you run on the PC that produces a spin/pasm program that contains not only the font data in a DAT section but also the code needed to process it? Then if the format of the file changes the code changes too. Crazy stuff. Quite doable of course.
I see three levels of choice :
Simplest : No tables, all chars are identical sizes and no 'gaps'. Suits serial FLASH fonts.
Compact : For variable width fonts, you need a width, but an Index table is not mandatory, you can quick-sum the width bytes.
Fastest: : Uses a Index table, and could pack Width into the Table-change, which needs a EOF entry.
This is larger, as the font index will be at least 16 bits, and could be 24 or 32 bits per character.
An index table has one other advantage, in that it allows sparse fonts - you can skip unused values, but still use an accepted/portable ASCII value index to the ones you do have. - eg A meter might support 0..9, and A,V,Hz (etc)
I'm going to have a go at writing a "True Type Font to Spin converter" when I get home. I've got this idea that the driver and the data get created at the same time. Later, if one lost the program to create the code, you could still edit a font as the code is human readable. And you could even automatically generate comments - eg your Simplest one is going to be fixed height and width so all the data is just one character after another. But if you had a variable width font, you could put in the dat section the width of the letter as a hex byte, but more importantly, you could put a comment in next to that to say what it is. So again, later you could edit this despite not having access to the code that made the program. Ditto you could edit the Spin - translate it to pasm if you wanted.
DAT FontBitmap ' character 32 Byte 8 ' xadvance Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 ' character 33 ! Byte 8 ' xadvance Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00001000 Byte %00001000 Byte %00001000 Byte %00001000 Byte %00001000 Byte %00000000 Byte %00000000 Byte %00001000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 ' character 34 " Byte 8 ' xadvance Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00110110 Byte %00110110 Byte %00100100 Byte %00100100 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 Byte %00000000 ' character 35 # Byte 8 ' xadvance Byte %00000000 Byte %00000000 Byte %00000000 Byte %00010010 Byte %00010010 Byte %00100100 Byte %01111110 Byte %00100100 Byte %00100100 Byte %01111110 Byte %00100100 Byte %01001000 Byte %01001000 Byte %00000000 Byte %00000000 Byte %00000000
produced by this
Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click Dim SpinProgram(10000) As String Dim Ascii, x, y, i, j, Width, Height, Xoffset, Yoffset, Xadvance, Fontvalue, Base As Long Dim Mycolor As Color Dim MyBitmap As New System.Drawing.Bitmap(PictureBox3.Image) 'image from picture box Dim LineOfText As String Dim FontHeight As Byte Dim LineCounter As Long Dim start1, start2, finish1, finish2, loopstep1, loopstep2 As Long Dim FontString, Destinationfile As String LineCounter = 30 ' DAT section SpinProgram(LineCounter) = "DAT" LineCounter += 1 SpinProgram(LineCounter) = " FontBitmap" LineCounter += 1 For Each Line As String In RichTextBox1.Lines ' much faster than for i=0 to richtextbox1.lines.length LineOfText = Line If Strings.Left(LineOfText, 6) = "common" Then FontHeight = Strings.Val(Strings.Mid(LineOfText, 19, 2)) Base = Strings.Val(Strings.Mid(LineOfText, 27, 2)) ' base is a better measure of height End If If Strings.Left(LineOfText, 7) = "char id" Then 'char id=32 x=96 y=21 width=1 height=1 xoffset=0 yoffset=23 xadvance=7 page=0 chnl=15 Ascii = Strings.Val(Strings.Mid(LineOfText, 9, 3)) ' sub 17 x = Strings.Val(Strings.Mid(LineOfText, 16, 3)) y = Strings.Val(Strings.Mid(LineOfText, 24, 3)) Width = Strings.Val(Strings.Mid(LineOfText, 36, 3)) Height = Strings.Val(Strings.Mid(LineOfText, 49, 3)) Xoffset = Strings.Val(Strings.Mid(LineOfText, 63, 3)) Yoffset = Strings.Val(Strings.Mid(LineOfText, 77, 3)) Xadvance = Strings.Val(Strings.Mid(LineOfText, 92, 3)) start1 = y ' outside loop start2 = x ' inside loop finish1 = y + Height - 1 finish2 = x + Width - 1 loopstep1 = 1 ' add 1 to each step loopstep2 = 1 SpinProgram(LineCounter) = "' character " + Strings.Str(Ascii) + " " + Strings.Chr(Ascii) LineCounter += 1 SpinProgram(LineCounter) = "Byte " + Strings.Str(Xadvance) + " ' xadvance" LineCounter += 1 ' add in blank lines at top For i = 1 To Yoffset SpinProgram(LineCounter) = "Byte %00000000" LineCounter += 1 Next For j = start1 To finish1 Step loopstep1 FontString = "" ' now add in the font data For i = 1 To Xoffset FontString += "0" ' add leading spaces Next For i = start2 To finish2 Step loopstep2 Mycolor = MyBitmap.GetPixel(i, j) ' get the color Fontvalue = Mycolor.R ' grayscale so RGB should be the same If Fontvalue > 128 Then FontString += "1" Else FontString += "0" End If Next FontString = Strings.Left(FontString + "00000000", 8) ' pad so always 8 wide FontString = "Byte %" + FontString SpinProgram(LineCounter) = FontString LineCounter += 1 Next ' add in lines at the bottom For i = 1 To FontHeight - (Height + Yoffset) SpinProgram(LineCounter) = "Byte %00000000" LineCounter += 1 Next End If Next Destinationfile = TextBox2.Text + "\" + TextBox5.Text FileOpen(1, Destinationfile, OpenMode.Output) For i = 0 To LineCounter Print(1, SpinProgram(i) + vbCrLf) ' send to disk Next FileClose(1)