How to save a font to the program?
Hello! How do you save a font to the program so any computer can see it? (Not just the ones with the font installed.) This is my current code: (In form1_load)
vb Code:
Dim MyFont As PrivateFontCollection = New PrivateFontCollection
MyFont.AddFontFile("visitor.ttf")
Me.Font = New Font(MyFont.Families(0), 12)
It sends an error when another computer runs the program. (Visitor.ttf is in the resources!)
So, what I need to jnow is, is there another way or another place to save the font instead of downloading it to another computer? Thanks.
Re: How to save a font to the program?
As the name suggests, AddFontFile adds a font file. You have to have a file to add if you want to use AddFontFile. A resource is not a file, which is the whole point. A resource is compiled into the binary code of your EXE or DLL. You would have to extract the resource and save it as a file first in order to use it like that.
I've never actually embedded a font as a resource. What do you get back from My.Resources if you do? It may well be a Font object so you don't need to do anything more to use it.
Re: How to save a font to the program?
It looks like you get back a byte array, so something like this is what JMC is suggesting
Code:
' get file from resources & write to file system
Dim path = System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData, "visitor.ttf")
If Not System.IO.File.Exists(path) Then
IO.File.WriteAllBytes(path, My.Resources.visitor)
End If
' apply font
Dim MyFont = New System.Drawing.Text.PrivateFontCollection
MyFont.AddFontFile(path)
Me.Font = New Font(MyFont.Families(0), 12)
Re: How to save a font to the program?
I appreciate the help, but the labels are still the default font. I don't get an error message.
Edit:
Aha... I see.
vb Code:
Dim MyFont As PrivateFontCollection = New PrivateFontCollection
MyFont.AddFontFile("visitor.ttf")
Me.Font = New Font(MyFont.Families(0), 12)
Only checks the same folder that the program is in for that specific font. So If you wanted to send your program to someone else then you'd have to send them the .ttf file too. :/
So you cannot save fonts to the resources?
Re: How to save a font to the program?
Quote:
Originally Posted by
NinjaNic
I appreciate the help, but the labels are still the default font. I don't get an error message.
You haven't shown us anything to do with Labels so far. As far as we know, there is no such code and that's the issue. Show us the exact code you're using now to create the Font object and change the Label's Font.
Re: How to save a font to the program?
Me.Font =
is supposed to change all the labels's fonts to what it is set to. But anyway, here's the full code (to one of the forms.)
(There are only 2 labels in this form.)
Attachment 116965
vb Code:
Imports System.Drawing.Text
Public Class FormHelp
Private Sub FormHelp_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Escape Then
Me.Close()
End If
End Sub
Private Sub FormHelp_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim MyFont As PrivateFontCollection = New PrivateFontCollection
MyFont.AddFontFile("visitor.ttf")
Me.Font = New Font(MyFont.Families(0), 12)
Me.Text = Me.ProductName & " - " & Me.ProductVersion
Me.KeyPreview = True
End Sub
Private Sub FormHelp_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
FormStart.Show()
End Sub
End Class
Re: How to save a font to the program?
You've posted a screen shot of some code that includes a compilation error and then you've posted some different code. Are we supposed to guess which one you're actually using?
Re: How to save a font to the program?
It's the same code, but in the picture I have
MyFont.AddfontFile(My.Resources.Visitor)
and in the code I have
MyFont.AddfontFile("Visitor.ttf")
I'm just showing what happens when I put
MyFont.AddfontFile(My.Resources.Visitor)
Re: How to save a font to the program?
If you have added the font to the project resources (Project Menu -> ProjName Properties; Resource Tab -> Add Existing File), then you could do something like this:
Code:
Private Function FontByteArray(ByVal fontData() As Byte, Optional ByVal sizeInPoints As Single = 12.0F, Optional ByVal style As FontStyle = FontStyle.Regular) As Font
Dim ret As Font
Dim ptrFontData As IntPtr
Try
ptrFontData = System.Runtime.InteropServices.Marshal.AllocHGlobal(fontData.Length)
System.Runtime.InteropServices.Marshal.Copy(fontData, 0, ptrFontData, fontData.Length)
Using pfc As New System.Drawing.Text.PrivateFontCollection
pfc.AddMemoryFont(ptrFontData, fontData.Length)
ret = New Font(pfc.Families.Last, sizeInPoints, style, GraphicsUnit.Point)
End Using
Finally
If ptrFontData <> IntPtr.Zero Then System.Runtime.InteropServices.Marshal.FreeHGlobal(ptrFontData)
End Try
Return ret
End Function
Assuming the name of the resource is "myFont" then:
Code:
Me.Font = FontByteArray(My.Resources.myFont)
Re: How to save a font to the program?
That code is hard to understand! I'm still pretty basic in Visual Basic ...(chirp chirp)... and I don't know what or how to use unmanaged memory. Anyway I tried the code but I still get the default font. Thank you all for the help though, but it seems like my attempt was in vain. If you used that code and it worked, it is probably because you have the font pre-installed on your pc. Seems like creating a file path is better for this one. Thanks again.
Re: How to save a font to the program?
Quote:
Originally Posted by
NinjaNic
...If you used that code and it worked, it is probably because you have the font pre-installed on your pc. Seems like creating a file path is better for this one. Thanks again.
You are correct. I missed that in my testing. For the MemoryFont to work, the control must be rendered in GDI+. Loading the font from a file as Wild_Bill showed should work though.
Re: How to save a font to the program?
Ok, after a bit of research, I found that it is possible to install a font on a per process level using the AddFontMemResourceEx API function. Coupling that with the previous attempt now allows you to load a font from your project resources.
Code:
''' <summary>
''' adds the font resource from a memory image to the system.
''' </summary>
''' <param name="FontData"></param>
''' <param name="lengthFontData"></param>
''' <param name="MustBeZero"></param>
''' <param name="numFontsAdded"></param>
''' <returns>If the function succeeds, the return value specifies the handle to the font added. This handle uniquely identifies the fonts that were installed on the system. If the function fails, the return value is zero. No extended error information is available.</returns>
''' <remarks>A font that is added by AddFontMemResourceEx is always private to the process that made the call and is not enumerable. To remove the fonts that were installed, call RemoveFontMemResourceEx. However, when the process goes away, the system will unload the fonts even if the process did not call RemoveFontMemResource.</remarks>
<Runtime.InteropServices.DllImport("gdi32.dll", ExactSpelling:=True)> _
Private Shared Function AddFontMemResourceEx(ByVal FontData() As Byte, ByVal lengthFontData As Int32, ByVal MustBeZero As IntPtr, ByRef numFontsAdded As UInt32) As IntPtr
End Function
Private Function FontFromByteArray(ByVal fontData() As Byte, Optional ByVal sizeInPoints As Single = 12.0F, Optional ByVal style As FontStyle = FontStyle.Regular) As Font
Dim ret As Font
Dim ptrFontData As IntPtr
Try
AddFontMemResourceEx(fontData, fontData.Length, IntPtr.Zero, 1UI)
ptrFontData = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length)
System.Runtime.InteropServices.Marshal.Copy(fontData, 0, ptrFontData, fontData.Length)
Using pfc As New System.Drawing.Text.PrivateFontCollection
pfc.AddMemoryFont(ptrFontData, fontData.Length)
ret = New Font(pfc.Families.Last, sizeInPoints, style, GraphicsUnit.Point)
End Using
Finally
If ptrFontData <> IntPtr.Zero Then System.Runtime.InteropServices.Marshal.FreeCoTaskMem(ptrFontData)
End Try
Return ret
End Function
Re: How to save a font to the program?
Hi NinjaNic,
I'm looking for help with embedded fonts and have found this thread, it's a bit late in the day since your last post was Jul 30th, 2014, 05:11 AM.
But... I'm surprised none of the guys helping you pointed out that Me.Font will only affect the font of the actual form, i.e. anything you place as the title of the form. It wouldn't affect the font of any label or textbox or whatever...
I wonder if when you were working on this project you were looking in the wrong place for font changes ?
In order to change the font of any object (a label, say) you have to specifically change the font of that object, as you did (tried to do) with the Title of your form.
Poppa.
Re: How to save a font to the program?
Quote:
Originally Posted by
TnTinMN
Ok, after a bit of research, I found that it is possible to install a font on a per process level using the AddFontMemResourceEx API function. Coupling that with the previous attempt now allows you to load a font from your project resources.
Hi TnTinMN,
It's a bit late to be asking this now, since your post was made July 30th 2014, however, I'm resurrecting that project and can't figure out just how to couple "that with the previous attempt".
The 'previous attempt' works, but only if the relevant font is already in the C:/Windows/Font directory.
I don't understand where to place: -
Code:
''' <summary>''' adds the font resource from a memory image to the system.
''' </summary>
''' <param name="FontData"></param>
''' <param name="lengthFontData"></param>
''' <param name="MustBeZero"></param>
''' <param name="numFontsAdded"></param>
''' <returns>If the function succeeds, the return value specifies the handle to the font added. This handle uniquely identifies the fonts that were installed on the system. If the function fails, the return value is zero. No extended error information is available.</returns>
''' <remarks>A font that is added by AddFontMemResourceEx is always private to the process that made the call and is not enumerable. To remove the fonts that were installed, call RemoveFontMemResourceEx. However, when the process goes away, the system will unload the fonts even if the process did not call RemoveFontMemResource.</remarks>
<Runtime.InteropServices.DllImport("gdi32.dll", ExactSpelling:=True)> _
Private Shared Function AddFontMemResourceEx(ByVal FontData() As Byte, ByVal lengthFontData As Int32, ByVal MustBeZero As IntPtr, ByRef numFontsAdded As UInt32) As IntPtr
End Function
The first bit looks like remarking out the first 9 lines, but I'm certain that's not the case.
I don't believe it's for a module because the word 'module' doesn't appear anywhere.
I've tried placing it before Public Class Form1 but it doesn't like that, neither does it like to be placed straight after it... Nor anywhere else as far as I can discover.
Poppa.
Re: How to save a font to the program?
From what I've learned, this is the function that saves and uses a .ttf from the program's resources. I tested it and it works. It creates a folder in your C:\ drive, however. (In this example, the font is named "nulshock.")
vb Code:
Private Function SaveFont(FontSize As Integer) As Font
Dim FilePath As String = "C:\Temporary"
Dim FileName As String = "\nulshock.ttf"
Dim MyFont As New Text.PrivateFontCollection
Try
MyFont.AddFontFile(FilePath & FileName)
Catch ex As Exception
IO.Directory.CreateDirectory(FilePath)
Dim b() As Byte = My.Resources.nulshock.ToArray
IO.File.WriteAllBytes(FilePath & FileName, b)
MyFont.AddFontFile(FilePath & FileName)
End Try
Return New Font(MyFont.Families(0), FontSize)
End Function
To delete the folder, simply use this. But for me, it's giving me an error stating that I do not have access.
vb Code:
Private Sub CloseFont()
Dim FilePath As String = "C:\Temporary"
Dim FileName As String = "\nulshock.ttf"
IO.File.Delete(FilePath & FileName)
IO.Directory.Delete(FilePath)
End Sub
And lastly, this is how you would use the first function:
vb Code:
Label1.Font = SaveFont(20)
Label1.Text = "nulshock"
Re: How to save a font to the program?
Quote:
Originally Posted by
Poppa Mintin
Hi TnTinMN,
It's a bit late to be asking this now, since your post was made July 30th 2014, however, I'm resurrecting that project and can't figure out just how to couple "that with the previous attempt".
Just copy all the code from post #12 and add it to either a Class (your form class for instance) or you can place it in a Module if you like. If you place it in a Module, removed the Shared qualifier on AddFontMemResourceEx
Quote:
Originally Posted by
Poppa Mintin
The first bit looks like remarking out the first 9 lines, but I'm certain that's not the case.
I don't believe it's for a module because the word 'module' doesn't appear anywhere.
Those first nine lines are know as XML documentation. It is the source for the Intellisence help that pops up when you type AddFontMemResourceEx. You can delete it if you want.
Just remember that any font that you use this way will need to be explicitly assigned in your code. You can not assign these fonts through the designer.
Re: How to save a font to the program?
Hi TnTinMN,
Thanks for the rapid reply, I was trying to 'Couple' Post 12 with the previous code, didn't realise you'd already done it.
Once I'd spotted that you'd also changed the function's name it all worked well. I even left the XML stuff in. I know nothing about XML as you can tell. :o
Poppa.