linux, C++, xft : how to use it? - c++

I try to use Xft, the tutorial, well let them calling that a tutorial... looks like it was written in a north korean camp... I also found this one. So let me try to do a step-by-step :
// g++ XftTest.cc -lX11 -lXft `pkg-config --cflags freetype2`
#include<unistd.h>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<X11/Xft/Xft.h>
int main()
{
Display *display;
XftFont *font;
XftDraw *xftdraw;
XRenderColor xrcolor;
XftColor xftcolor;
display = XOpenDisplay(0);
Window XP = XCreateSimpleWindow(display,DefaultRootWindow(display),0,0,360,90,0,0,0);
XMapWindow(display,XP);
font = NULL; /* added 6/16 */
//font = XftFontOpenName(display,0,"NorthKorea-50"); // how to check if this is good ?
font = XftFontOpenName(display,0,"") /* added 6/16 */
if (!font) return 1;
xftdraw = XftDrawCreate(display,XP,DefaultVisual(display,0),DefaultColormap(display,0));
xrcolor.red =65535;
xrcolor.green=0;
xrcolor.blue =0;
xrcolor.alpha=65535;
XftColorAllocValue(display,DefaultVisual(display,0),DefaultColormap(display,0),&xrcolor,&xftcolor);
XftDrawString8(xftdraw, &xftcolor, font, 20,70 , (XftChar8 *)"Joe Dalton", 10);
XFlush(display);
sleep(2);
XftDrawDestroy(xftdraw);
XftColorFree(display,DefaultVisual(display,0),DefaultColormap(display,0),&xftcolor);
return 0;
}
as you can see, in the XftFontOpenName :
XftFontOpenName(display,0,"NorthKorea-50")
if you write a bullshit, like I did, there is no error or something to tell me that I don't have a font called NorthKorea. That make sense since XftFontOpenName returns the nearest font from the string.
So, how can I check if my font match or not ? how can I use a font like arial? I tried XftFontOpenName(display,0,"arial-50"), I got nothing different.
On my system, I have these folders in my fonts folder :
$ls /usr/share/fonts/
100dpi 75dpi cyrillic encodings misc OTF TTF Type1 util
can I use any font in these folders by the same way ?
if you guys have some nice internet links, it would be a pleasure for me to take a look.
n.b. : there is no xft tag...
update 6/16
I'm still stuck with dat stuff...
I don't understand, if I replace
font = XftFontOpenName(display,0,"NorthKorea-50");
by
font = XftFontOpenName(display,0,"");
it still loading a font...
xlsfonts return a lot of stuff, like dat one :
-monotype-courier new-bold-r-normal--0-0-0-0-m-0-iso8859-10
but passing this as argument to XftFontOpenName changes nothing; I try to load a font with XftFontOpenXlfd too, it returns always NULL...

xft uses fontconfig for font discovery. xlsfonts is a way to query the old X core fonts system fontconfig replaced. xlsfonts results won't map in any reliable way way to the fontconfig state.
So:
forget about any shortcut where xft work sort-of like the X core font system documented in last centuries tech books. It is completely different. It is not X core fonts with antialiasing and truetype support. It is something that can use modern fonts and do antialiasing, but definitely not X core fonts in any form
Read the fontconfig documentation, the fontconfig configuration files on your system, and use fontconfig utilities (fc-query, fc-list, etc) to query the fontconfig state
as the people who maintain xorg (both x core fonts and fontconfig) already told you, do not try to use xft directly. xft is the product of the first attempt to write a new font stack. Its capabilities are not sufficient to manage modern text and modern fonts. The part dealing with modern font format complexities has been spun out in pango a long time ago (because it was proving complex enough it deserved a separate project). If you try to use xft alone, you'll hit the deficiencies in pre-pango code sooner or later, and no one will be interested in fixing your problems because the same code has already been subjected to a decade of fixes pango-side. Avoiding pango is not a shortcut. Avoiding pango is trying to rely of an half-finished, abandonned for years project.
forget about matching a specific font file. fontconfig will actively fight any attempt to work this way. In the post-core-fonts world, you give the font system a font pattern, and it will build a matching font for you. If the result is not the font file you expected that's because the file was evaluated and found lacking. If you want fontconfig to use this file you will have to fix the font file (add the missing glyphs, the missing font styles, etc), not write code to try to force it anyway. Fontconfig considers that it's more important to render a text your users can read, than to only render the parts your pet font can do. And yes that's now how you're used to think about it on other systems. fontconfig is different. Nothing short of a rewrite will make it behave like you expect. No one is interested in this rewrite because by and large fontconfig has been quite successful those past years.
fonts opentype text-rendering fontconfig linux

You should not pass an empty string to XftFontOpenName and expect to match a font. Xft provides support for core fonts and the structure nested within XftFont is a union of XFontStruct and XftFontStruct. X11 fills in the default font in the XFontStruct when creating new instances, so in the case of empty string you are likely getting the default core font.
In the simplest approach, one can hard code a font name like this:
const char *font_name = "Arial-20";
XftFont *font = XftFontOpenName (display, DefaultScreen(display), font_name);
Or you could use XftFontMatch and check the "results" before passing the pattern to XftFontOpenPattern. See http://keithp.com/~keithp/talks/xtc2001/paper/xft.html#sec-editing
Note that XCloseDisplay is missing.

Related

How to load multiple font of same familiy

I am writing an application using the Qt framework. In the display, I have to show multiple information, but using different types of font of the same family, Montserrat.
What I have done so far to load the fonts is:
int ultralightid = QFontDatabase::addApplicationFont(":/Montserrat_UltraLight.tff");
QString UltraFont= QFontDatabase::applicationFontFamilies(ultralightid ).at(0);
QFont font1(UltraFont,QFont::Normal);
font1.setPixelSize(50);
int lightid = QFontDatabase::addApplicationFont(":/Montserrat_Light.tff");
QString LightFont= QFontDatabase::applicationFontFamilies(lightid).at(0);
QFont font2(LightFont,QFont::Normal);
font2.setPixelSize(150);
label1->setFont(font1);
label2->setFont(font2);
label1->setText("bla bla");
label2->setText("bla bla");
The font sizes are correct, but the font itself it is not. From what I have noticed (trying with Hairline_Montserrat,Light_Montserrat,UltraLight_Montserrat), it is as if the fonts have a sort of priority. If I declare them all, all the fonts are the Light one, if I comment that font type, all of them are Hairline one, otherwise (last priority) the labels use the ultralight font.
I have tried adding other font type (from other families) and in that case my code works correctly.
If I use
qDebug()<<QFontDatabase::applicationFontFamilies(ultralightid);
qDebug()<<QFontDatabase::applicationFontFamilies(lightid);
both of them print the family "Montserrat".
I use the qrc file and the AUTORCC flag in the CMAKE (it should be similar using qmake) and all the file are uploaded correctly.
Do you know if there is another way to add fonts of the same family? Or is there something I am doing wrong?
Here are the fonts:
https://www.onlinewebfonts.com/download/9d31c906a6cc6064bbe7d33d51058317 light
https://it.allfont.net/download/montserrat-light/ ultralight
This is an old question but I was just struggling with exactly the same problem when trying to load normal, bold, ... versions of a font family in Qt.
I solved the problem (although in a somewhat hacky way) by simply giving each of the ttf files a different family name. I used Typograf, simply open the font, right click to open properties and then click rename. There are probably many other tools that do this too.
You don't need to manage font files from one family separatelly.
I suggest this solution:
Create a folder with all ttf's of the same family.
Load all files from the folder via id = QFontDatabase.addApplicationFont(path)
Collect all font families from these files via QFontDatabase.applicationFontFamilies(id)
Check if only one and desired family is loaded, and the family name is exactly the same as requested, or warn the user about these errors.
Create font object font = QFont(family)
Then for example, font.setItalic(True). If Italic version of family is loaded, it will be used, otherwise it will be created from Regular by QT.

How to customize vtkTextActor display font(VTK 6.1)

As we know, VTK text supports 3 kinds of fonts, they are VTK_ARIAL, VTK_COURIER and VTK_TIMES. But in this case, I'd like to customize the text font.
Now, all things I did are:
vtkTextActor* textActor = vtkTextActor::New();
//...
vtkUnicodeString u = vtkUnicodeString::from_utf16((const vtkTypeUInt16*)txt);
textActor->SetInput(u.utf8_str());
//...
vtkTextProperty* prop = textActor->GetTextProperty();
prop->SetFontFamily(VTK_FONT_FILE);
prop->BoldOff();
prop->ItalicOff();
prop->ShadowOff();
prop->SetLineSpacing(1.2);
//...
prop->SetFontSize(iFontSize);
prop->SetFontFile(font_file_full_path);
There are lots of fonts(true type fonts) installed on my system, above codes only can work for some fonts with specified font size. Such as, it supports
'Calibric' font with file size 8, 14,16..., but if you set iFontSize to 12, vtk cannot display the string.
So my questions is that does vtk 6.1 not support all kinds of true type fonts installed on my system? If that's the case, is there any function I can use to check if one font/fontsize is supported or not?
Thanks for you help in advance.

ChooseFont dialog: munges font name fails to reload it

I've found some slightly odd, and more importantly, inconsistent behavior from Win32 ChooseFont() API.
LOGFONT lf = { 0 };
strcopy(lf.lfFaceName, m_face_name);
const int ppi = GetDeviceCaps(pView, LOGPIXELSY);
lf.lfHeight = -MulDiv(m_font_height, ppi, 72);
CFontDialog fd(&lf);
if (fd.DoModal() != IDOK)
return;
m_face_name = fd.GetFaceName();
m_font_height = lf.lfHeight;
Assuming that the first time though, face name is "Segoe UI", this works.
But if the user changes the dialog to be "Segoe UI", "Light", "9", (face, style, height), and we go through the above a second time, then the font choose common dialog fails to select "Segoe UI" as the face name. Instead, I get the Font: field as blank.
This is not a problem if the user selects a style of "Regular", "Italic", "Bold", "Bold Italic", as those are stored in the style bits, and don't munge the name. I discard them for the second run, because I'm ignoring them (I would disable Font Style: if there were a way to easily do so - I don't wish to subclass CFontDialog for this - that's a whole 'nother level of time & effort that this moment doesn't allow for).
I've tried creating a font based on the previous specifics from the dialog, and then tried pulling the LOGFONT back out of that. No dice.
Similarly, I've tried querying the dialog for the FontStyle() - but that returns blank - so nothing to strip from the font name here...
This just seems like a bug with MS's dialog - it tells me one thing, but then cannot use it's own output to correctly initialize itself the second time through (granted, I'm only persisting some, not all, of the LOGFONT in this situation).
Does anyone know WTH is up with this? Or an approach I might use to (short of hard coding looking for " Light" on the end of a font name - YUCK!)?
Developments in font design has significantly outstripped the legacy api's ability to keep up. OpenType happened, for one. There are additional font styles beyond what LOGFONT can support. For Segoe UI, properties that control boldness can be Light and Semibold. For other fonts, font stretch is another property, common ones are Condensed and Expanded. With the font being able to implement a dedicated font file to make these styles look good and not depend on synthesizing the style from an existing font as it was done in the olden days. Review the WPF FontStretch and FontWeight enumeration types for possible values.
These are properties that LOGFONT can't express. There's a compatibility hack to deal with this, type face names get mapped. So "Segoe UI" with a style of "Light" becomes "Segoe UI Light". And the Windows font mapper will pick the right true-type font file from such a name. What however doesn't work is initialize LOGFONT.lfFaceName with "Segoe UI Light". Not actually sure why, it was probably avoided to not have to deal with the ambiguity. Or just plain flubbed. A possible workaround is to recognize these appended style names in the font face name, but that's not perfect either.
GDI is running out of gas. Much like User32.
First, when you initialize your LOGFONT in your proc, you can't just set it to 0
ala "= { 0 };"
Use something like
memset(&lf, 0, sizeof(lf));
Otherwise your lf in your proc contains random crap. Secondly, what's the big deal about not saving all the settings of the LOGFONT structure? It you're using MFC, it's not because it would be too much overhead. If fixing the initialization of lf doesn't work, just save the entire LOGFONT.

Is there a Mac OSX version of windows GetFontData function?

We have an application that allows our users to generate print-ready PDF documents using variable data (names, titles, phone numbers, etc) that their customer's enter via an online e-commerce website. To facilitate the variable data we have to embed a font's entire character map. On windows we have been using the windows API function GetFontData(...) like so:
#ifdef Q_WS_WIN
//this is windows specific code
HDC DC = CreateCompatibleDC(NULL);
HFONT hFont = font.handle();
HFONT oFont=(HFONT)SelectObject(DC,hFont);
DWORD fontLength = ::GetFontData(DC, 0, 0, 0, 0);
if(fontLength != GDI_ERROR)
{
fontData.GrowAllocation(fontLength);
if(::GetFontData(DC, 0, 0, fontData.GetBuffer(), fontLength) == GDI_ERROR)
{
fontData.Clear();
}
else
{
fontData.SetLength(fontLength);
returnVal = true;
}
}
SelectObject(DC,oFont);
DeleteDC(DC);
//End of windows specific code
#elif defined(Q_WS_MAC)
#endif
This technique works very successfully on our windows specific version; however, we are porting the application to Qt to target the Mac OSX platform.
My first question: Is there a Qt way of accessing the raw font data from a QFont, QFontDatabase, etc. that we could use to embed in the pdf? We have been unable to find a way. Notice the #ifdef wrapper in the above code. Note that the variable fontData is a self contained memory buffer that manages its own memory, please disregard.
My second question: If there is no Qt way of accessing the font data in an OS agnostic way, what is the OSX equivalent to the windows GetFontData?
Thanks
I've only skimmed documentation for GetFontData, and I don't know much about Qt (though it does sound like a Qt solution would be preferable), but you might want to look at the ObjC class for fonts, NSFont.
The latest (until Apple hires new font people and gets infected with not-invented-here disease again) text and font API is Core Text. I never used it since chasing Apple's mood is harmful to my personal and organization's financial health, I stopped using any Apple-only API. :)
Kidding aside, it looks like CTFont does provide access to all tables in a font. I don't see anything that prepares a font for embedding but this probably gives you the best chance.

How to detect missing font characters

Is there a way to detect that all characters are displayed properly with the current font? In some environments and fonts certain characters are replaced with a square symbol.
I'd like to automatically verify that all characters used in the GUI are supported by the current font.
I found a possible solution using the QFontMetrics class. Here is a an example function to query whether all characters are available in the current text of a QLabel:
bool charactersMissing(const QLabel& label) {
QFontMetrics metrics(label.font());
for (int i = 0; i < label.text().size(); ++i) {
if (!metrics.inFont(label.text().at(i))) {
return true;
}
}
return false;
}
Of course displaying to the user which character is missing would be good, but of course that has to be done with a different font :)
According to this discussion, I don't think the sample code of QFontMetrics will work well.
https://bugreports.qt-project.org/browse/QTBUG-1732
The QFontMetrics inFont() function depend on QFont class, and it seems you have to set the StyleStrategy to QFont::NoFontMerging. But actually, the NoFontMerging flag doesn't work in that way you think, so the inFont function still return true if other fonts in your system have this glyph.
BTW, I make a verification tool in python finally.
https://github.com/diro/pyGlyphChecker
A possible solution...
Depending upon your application the following might be a possible solution
(or completetly not applicable) :
Popup a dialog-box with a sample paragraph containing all the characters that you intend to use.
Render the paragraph using the FONT u have in mind.
Display a message to the user to
-- Select OK (if he/she can read the text i.e. only if no "squares" visible)
-- Select a different FONT (if any "squares" are visible)
NOTE: In case you are wondering, this is not a very uncommon behaviour for apps. MS-WORD does this when it detects non-standard encoding in a doc file.
GoodLUCK!!