I am loading a custom font (from ttf file) into my project, and using deriveFont(float f) to change the size. However, the size is not actually being set (stuck at 1). Here is my code:
public static void main(String[] args) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
Font mont =
Font.createFont(
Font.TRUETYPE_FONT,
new File(System.getProperty("user.dir") + "/data/Montserrat-MediumItalic.ttf"))
.deriveFont(20f);
ge.registerFont(mont);
Arrays.stream(ge.getAllFonts())
.filter(font -> font.getFontName().contains("Mont"))
.forEach(font -> System.out.println(font.getFontName() + ", Size: " + font.getSize()));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
}
output:
Montserrat Medium Italic, Size: 1
note: replacing font.getSize() with font.getSize2D prints 1.0.
New: Using decode:
I am now using this
Font test = Font.decode("Montserrat Medium Italic-ITALIC-20");
(fixed class not loading)
Update 2:
this line:
Font mont = Font.createFont(Font.ITALIC, new File(System.getProperty("user.dir") + "/data/Montserrat-MediumItalic.ttf"));
throws IllegalArgumentException: font format not recognized
However, the size is not actually being set (stuck at 1).
This seems unlikely to be the case. I asked for direct confirmation in a comment on the question ("What mont.getSize() return?" -- oops, what embarrassingly bad grammar), but so far you have not answered. I am reasonably confident that if you check, you will see that mont.getSize() evaluates to the size you requested.
An alternative explanation for your observed behavior is readily available. You are using GraphicsEnvironment.getAllFonts() to report on the registered fonts, but according to its documentation, this method
Returns an array containing a one-point size instance of all fonts
available in this GraphicsEnvironment.
(Emphasis added.)
Another answer and especially comments on it suggest that the Font objects returned by GraphicsEnvironment.getAllFonts() might differ in other ways, too, from corresponding Font instances passed to GraphicsEnvironment.registerFont(). Although such variations are not documented as far as I can see, they are consistent with the intended usage of Font objects obtained from a GE, as the getAllFonts() docs describe:
Typical usage would be to allow a user to select a particular font. Then, the application can size the font and set various font attributes by calling the deriveFont method on the chosen instance.
They go on to say that
If a font in this GraphicsEnvironment has multiple programmable variations, only one instance of that Font is returned in the array, and other variations must be derived by the application.
I'm not positive that "multiple programmable variations" means attributes that can be modified when you derive one Font object from another (for then what font wouldn't have programmable variations?), but it is clear that getAllFonts() is not a mechanism for reading back the exact Font objects previously presented to GraphicsEnvironment.registerFont(). Those objects might not even be retained as such.
On the other hand, you can perhaps be relieved that you are not responsible for registering all the different font variations you may want in advance.
I think I know what is the problem. When you call ge.registerFont(mont), it does exactly that, it registers the underlying font, without the modifications to the font object. The deriveFont() function only changes the state of the current font object, but cannot modify the actual font. When you register a font, it is registered with the size of 1. If you print the size of all the other fonts, you will find that they also have the default value of 1. I do not think that you can register a font with a custom default size, or override the default size of Font.getFont(). When you get a font by using Font.getFont(), it will always have the default size of 12 (from the specification).
If you need to have a the font specially formatted, I would suggest creating a static class variable:
Font MontMediumItalic_20;
Then load the font once, either in a resource loader, or the constructor, and apply all the modifications to it.
Alternatively, you can also use Font.decode()
Please let me know if you need any help.
Related
How do I set an IText7 fallback font? That is: A font which is used as a fallback font in cases where the primary font don't have a specific code point.
My original code just used PdfFontFactory.createFont(...) to get a PdfFont, and then I just called setFont on the Text element where I wanted to change font. This worked as in the text was shown with the expected font, but I could not find any way to specify a fallback font.
So I changed my code, so now I start by creating a new FontProvider and then call addFont(...) with all the fonts I need, including the fallback font.
And then I add this font provider to the document.
I then call setFontFamily on the Text objects where I want to change the font, and this works. Including fallback to the first added font, in cases where the primary font don't have the specified codepoint.
But is this the correct way to handle this issue?
This solution does have one new problem. It always embed the fonts in the pdf documents and I can't find a way to prevent this. None of the addFonts or setFontFamily methods have a flag to specify if the font should be embeded.
The FontProvider does have a method called getDefaultEmbeddingFlag() which always return true, so I tried to create a new Class which extended FontProvider and changed getDefaultEmbeddingFlag to just return false. But even when I use this class as FontProvider the font still get embeded.
So I guess my main question is: How do I enable fallback to a different font for unknown code points, while still having the ability not to embed fonts?.
I have some input PDF all with full set fonts, I want to "shrink" them all creating fonts subset. I know there is the way to unembed fonts and embed subset font, but the problem is that i don't have the source file of fonts. I just have fonts embedded in source PDF.
Someone can help me to troubleshoot this issue ?
ENV: java8, itext7.1.5
Here's a thread on a similar question (about embedding, not subsetting, despite the OP's question): How to subset fonts into an existing PDF file. The following statement is relevant:
If you want to subset it, you'd need to parse all the content streams
in the PDF to find out which glyphs are used. That's NOT a trivial
task.
I wouldn't recommend attempting this in iText, unless it's really necessary. It would likely end up buggy unless you have a very complete understanding of the PDF specs. It might be worth pursuing other avenues such as changing the way the PDFs are created, or use something like Distiller that can do this for you.
If you do want to do this in iText, I'm afraid you will likely have to use a PdfCanvasProcessor and some custom operator handlers. You would need to find all text fields, determine which font they use, build a new subset font with the applicable glyphs, and replace the fonts with new subset copies. This is how you would create a copy of the complete font to prepare for subsetting (assuming you don't have copies of the font files):
String encoding = PdfEncodings.WINANSI; // or another encoding if needed for more glyph support
PdfFont completeFont = ...; // get complete font from font dictionary
PdfFont subsetFont = PdfFontFactory.createFont(completeFont.getFontProgram(), encoding, true);
subsetFont.setSubset(true);
When you encounter a Font change operator (Tf), you would need to look up that font in the font dictionary and create a new (or lookup an already created) subset copy of that font to prepare for upcoming text fields. Don't forget to keep the font in a stack so you can pop back to the previous font (look for q and Q operators). And don't forget to check parent forms and page groups for the fonts if they don't exist in the current XObject or page resource dictionary.
When you encounter text (a Tj, TJ, ', or " operator), you would need to decode the text using the complete font, then re-encode it to the new subset font's encoding (unless you know for sure that all your source fonts are ASCII-compatible). Add that text's characters to the subset like this:
subsetFont.addSubsetRange(new int[]{character});
I'm working on a RESTful service in Java. Part of this is to take data that is stored in a database that contains a font name (e.g. Arial) and return JSON beans to a client that contains not only the font name to use, but the logical font that it belongs to (e.g. serif, monospace, etc...).
I've looked at using the java.awt.Font class to try and get this information, but when i call getName(), I always only ever get back the original font name (Arial). What I want is to get the logical font that this font belongs to (Sans-Serif).
Here is an example of what I've tried:
Font[] tfonts;
tfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
for (int i = 0; i < tfonts.length; i++) {
System.out.print(tfonts[i].getFontName() + " : ");
System.out.print(tfonts[i].getFamily() + " : ");
System.out.print(tfonts[i].getName());
System.out.println();
}
The output of this is basically:
Times New Roman : Times New Roman : Times New Roman
It is surprising that the root logical font is not found anywhere here. I was hoping to see Serif in here somewhere. I've even tried inspecting the output of the getAttributes() call, and don't see this information there.
The reason I want to do this, we have data objects that contain a field of display fonts that were created from fonts available on a user's PC. We are sending these objects to other platforms (namely iOS) where these fonts may not actually exist. What I'd like to do is send "Serif" or something in its place, and let the iOS clients pick a suitable Serif font. But I cannot seem to find a way to get back to the logical font for a given named font.
I appreciate any help anyone can provide.
I know that Java supports TrueType Fonts (.ttf) and that .ttc is extension of TrueType format, but i can't find information that Java also supports the TrueType collection (.ttc) to be explicitly set as font on JLabel for example.
I made an example, where I successfully load a .ttc file in my application with the following code:
InputStream is = getClass().getResourceAsStream("/resources/simsun.ttc");
Font font = Font.createFont(Font.TRUETYPE_FONT, is);
Font fontBase = font.deriveFont(15f);
field.setFont(fontBase);
The code is working well, there are no exceptions related to the creation, loading or setting of the .ttc file as a font in Swing components.
My question is: Can someone confirm this to be working well and that all glyphs from the fonts inside the .ttc are used in components, or there are any disadvantages related to this?
Also, is there any difference if the .ttc is loaded from jar on client machine or it has to be installed in system fonts?
I'm using Windows 7.
First of all, the difference between TTC and TTF is: TTC can (and usually) contain multiple fonts, but TTF only have font defined. The reason to put multiple font into one file is to save space by share glyphs (or sub glyphs). For example, in SimSun and NSimSun, most of glyphs are same, save them together can save lots of space.
Second, Java support TTC font format, but by using Font.createFont() you can only get the first font defined in the TTC file. Currently, there is no way to specify the font index. Take a look at sun.font.FontManager.createFont2D(), when they invoke new TrueTypeFont(), the fontIndex is alway zero. Shame!
For your question: if all you need is the first font in TTC file, then everything would be okay. All the glyphs defined for first font would be available. But, if you expect second or other font defined in that file, then you hit a block. You cannot even get the font name by using this API.
There is no difference between system loaded fonts and created font. However there is no good way to specify the font index, you may try to hack into FontManager and come up with some platform specific code.
I'm bundling ttf files in a jar file and intend to use them as physical fonts for rendering text.
All the sample codes i've seen over the internet are as follow:
InputStream is=Essai.class.getResourceAsStream(resourcePath);
Font f=Font.createFont(fontFormat, is);
I have two questions about this code:
First, a single font, say DejaVu, holds 4 different ttf files, 1 per style (regular, bold, italic and bold-italic); is-it enough to create a font from one single ttf (any one of the 4)?
Second, none of the codes i've seen closed the stream after creating the font, which kept me wondering was it intentional ? maybe the the created font (which will be registered in the local GraphicsEnvironment later) needs the stream to stay opened?
The javadoc of the createFont() method says: "This method does not close the InputStream."
So my second question is should i close the stream after creating the font, or keep it opened?
I don't believe loading one variant will load them all. But then, it does not matter. Java can make a Font variant with any combination of bold+italic. I'd only put the standard Font in the Jar in the first place.
Close the stream. Many examples cut corners for the sake of brevity (though that is generally a bad idea).