Our users are giving us Emoji and a lot of other weird characters and the built-in Helvetica can't handle it. Neither can Google's Noto fonts by themselves - I need to figure out how to declare the Noto Font Family in HexaPDF and I can't figure out how to do that with the given documentation. OpenSans was an improvement, but I still want more glyph coverage than that.
Update:
I used this method to set the font:
def self.pdf_summary_font
##pdf_summary_font ||= File.open(Rails.root.join('public',
'OpenSansEmoji.ttf'), 'r')
end
canvas = page.canvas(type: :overlay)
canvas.font(self.class.pdf_summary_font, size: 10)
However, no Noto font ever worked with this - I would get errors like "Missing glyph - 'A'"
The best I could do was to use OpenSansEmoji, and replace missing glyphs with the following block:
begin
style = HexaPDF::Layout::Style.new(font: canvas.font, fill_color: color, stroke_color: color, align: :left, valign: :center)
fragment = HexaPDF::Layout::TextFragment.create(str, style)
layouter = HexaPDF::Layout::TextLayouter.new(style)
layouter.fit([fragment], w, h).draw(canvas, x1, y2)
rescue HexaPDF::Error => e
if e.message.include?('Glyph for')
glyph = e.message.match(/\{(.*?)\}/).captures.first
str = str.grapheme_clusters.map do |char|
if char.dump.include?(glyph)
"\u{FFFD}"
else
char
end
end.join
retry
end
Have a look at https://hexapdf.gettalong.org/documentation/reference/api/HexaPDF/index.html and the configuration option "font_map". This allows you to declare any TrueType file and use it.
You could also use the path to the font file directly with the Canvas#font method.
If you need to cover a wide array of characters you need to use a single font that covers all of them, one of the fonts included in this ZIP file should probably work (Google says 582 languages, 237 regions included).
Related
I'm trying to output text to the main window with unicode character like that
def initialize
super 800, 800
self.caption = 'Chess'
#font = Gosu::Font.new(self, Gosu.default_font_name, 100)
end
def draw
text = "Chess \u2658".encode('utf-8')
#font.draw(text, 100, 100, 10, 1, 1, Gosu::Color::BLACK)
end
but the window displays only the 'Сhess' string without unicode symbol '♘' as supposed.
What I have tried so far:
to change font name itself, 'Gosu.default_font_name' to 'Serif', 'Arial', 'Hack' - same result only 'Chess' string changes font but not displaying glyph
use symbol '♘' instead of unicode code
use .draw_markup, .draw_text, Gosu::Image.from_text.
use different unicode code, for example with cyrillic letter '\u0416' it worked as supposed.
use different encoding arguments.
use different colors.
I looked for similar problems on the Gosu forum, but I could not find anything.
You need to use a font that includes those Unicode characters or Gosu's internal font rendering code will return a 0 width image for drawing that character.
A font like: https://fontlibrary.org/en/font/chess
require "gosu"
class Window < Gosu::Window
def initialize(*args)
super
#font = Gosu::Font.new(28, name: "Chess.odf")
end
def draw
#font.draw_text("♘\u2658", 10, 10, 10)
end
end
Window.new(100, 100, false).show
I have three fonts i want to use in my software with pango:
Font1: latin, Cryllic characters
Font2: Korean characters
Font3: Japanese characters
Pango render the text correctly but i want select a font
There any way to indicate this preference pango font?
I use: linux and pango 1.29
The simplest way is to use PangoMarkup to set the fonts you want:
// See documentation for Pango markup for details
char *pszMarkup = "<span face=\"{font family name goes here}\">"
"{text requiring font goes here}"
"</span>"; // Split for clarity
char *pszText; // Pointer for text without markup tags
PangoAttrList *pAttr; // Attribute list - will be populated with tag info
pango_parse_markup (pszMarkup, -1, 0, &attr_list, &pszText, NULL, NULL);
You now have a buffer of regular text and an attribute list. If you want to set these up by hand (without going through the parser), you will need one PangoAttribute per instance of the font and set PangoAttribute.start_index and PangoAttribute.end_index by hand.
However you get them, you now give them to a PangoLayout:
// pWidget is the windowed widget in which the text is displayed:
PangoContext *pCtxt = gtk_widget_get_pango_context (pWidget);
PangoLayout *pLayout = pango_layout_new (pCtxt);
pango_layout_set_attributes(pLayout, pAttr);
pango_layout_set_text (pLayout, pszText, -1);
That's it. Use pango_cairo_show_layout (cr, pLayout) to display the results. The setup only needs changing when the content changes - it maintains the values across draw signals.
I'm using rmagick to annotate images programatically with text. The text will need to support a range of languages including Chinese, Korean, English among others. The font requirements I'm dealing with are very specific, and the font chosen for English supports a wide variety of western languages, but it doesn't support Chinese or Korean. I'll have other fonts for those languages.
The approach I have in mind is to map character ranges to particular fonts and programmatically tell rmagick what font to use based on that. Am I missing anything obvious, or is this a good approach to take?
Here is how I ended up solving this:
def font_for(verb)
return "#{Rails.root}/app/uploaders/fonts/Gotham-Bold.ttf" if verb =~ /\p{Latin}/
return "#{Rails.root}/app/uploaders/fonts/ArialUnicode.ttf"
end
That method will take some text and return the path to an appropriate font face. Regex's character property matching comes in handy here! Then i can use the font_for method inside my rmagick script for annotating an image.
def create_image_with_text
canvas = Magick::ImageList.new
canvas.new_image(640, 480) {self.background_color = "white"}
text = Magick::Draw.new
text.font = font_for "english"
text.pointsize = 23
text.gravity = ::Magick::NorthGravity
text.annotate(canvas, 0,0,0,28, "ENGLISH") { self.fill = '#343434' }
text.font = font_for self.verb
text.pointsize = 65
text.gravity = ::Magick::CenterGravity
text.annotate(canvas, 0,0,0,18, self.verb.upcase) { self.fill = '#343434' }
tempfile = Tempfile.new(['new_center_stripe', '.jpg'])
canvas.write tempfile.path
self.image.store!(tempfile)
end
It is worth noting that this simplistic approach wouldn't handle input with mixed languages.
I'm trying to use Rubygame to determine each of a string's character widths as a percentage of the string's total width...
require "rubygems"
require "rubygame"
include Rubygame
TTF.setup
$font = TTF.new "/Library/Fonts/Times New Roman.ttf", 40
total = 0
"Hello TrueType text! My name is Davide".each_char do |c|
size = $font.size_text c
#puts "Char: #{c} - #{size[0]}/#{total}"
total = total + size[0]
end
puts "Size: #{$font.size_text('Hello TrueType text! My name is Davide')[0]}"
puts "Total: #{total}"
puts "Difference: #{total - $font.size_text('Hello TrueType text! My name is Davide')[0]}"
The program's output for the string above is...
Size: 642
Total: 650
Difference: 8
...And varies depending on the length and content of the string.
The result is close, but... Does anyone know why there's a difference of 8 between the sum of the character widths and the string's width?
Any help would be greatly appreciated...
Cheers...
Davide
PS I'm also open to suggestions about other/better ways of doing this.
The result is close, but... Does anyone know why there's a difference of 8 between the sum of the character widths and the string's width?
Yes: because a good TrueType font, like any good font, will be kerned by the layout engine. http://en.wikipedia.org/wiki/Kerning
When doing layout with variable width fonts - which you want - always use the full string width. Per-character numbers are meaningless. (...and, really, the "right" way to do this is to use something that does layout for you. Pango is a project that does that; go count the lines of code, and consider if you really want to write that yourself.)
I'm trying to diagnose a problem in UKSyntaxColoredTextDocument 0.4 http://www.zathras.de/angelweb/blog-uksctd-oh-four.htm where text that actually lives in a different font than the one you have specified disappears as you type. (You can download and try out this cool utility to see this problem for yourself...)
Here's the background: This is some syntax coloring code that recolors as you type. It works great, but if you enter some characters that are not a part of the font set for that text view (e.g. Monaco, Helvetica) ... for instance, a symbol character or something in Japanese, which actually uses fonts like ZapfDingbatsITC or HiraKakuProN-W3 to display it, then those characters are not displayed as you type.
Let's say you have some text like this: fdsafd[☀]sfds‡[☀☀☀][日本語]...
If you paste that into the text field, and switch among syntax coloring from the popup, this invokes oldRecolorRange:, with this line:
[[textView textStorage] replaceCharactersInRange: range withAttributedString: vString];
Here, things behave as I would expect. The ASCII text, the symbols, and the Japanese text are all visible. The value of [textView textStorage] starts out, and ends up, something like this: (This is output of gdb; it's not showing the unicode characters, don't worry about that.)
df{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}?{
NSFont = "ZapfDingbatsITC 20.00 pt. P [] (0x001ae720) fobj=0x001bb370, spc=5.56";
}fdsafd[{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}?{
NSFont = "HiraKakuProN-W3 20.00 pt. P [] (0x001b59e0) fobj=0x001bb600, spc=6.66";
}]sfds[{
...
... even after setting the new value to be
dffdsafd[?]sfds[???][???] Nihddfdfffdfdd{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}
In other words, the "foreign" fonts needed to display this string are preserved automatically somehow, even though the fonts are not specified in the replacement string.
However, when you type in one character at a time, a different call of replaceCharactersInRange:withAttributedString: in the method recolorRange: results in an attributed string that is only in the base font -- no foreign-character fonts have been added for us, so the characters out of the range of the main font are not visible at all!
dffdsafd[?]sfds[???][???] Nihddfdfffdfddx{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}
Any idea why this method would be working one way in one circumstance and not in another? Is there some kind of switch that I can pass to give the NSTextStorage/NSAttributedString a hint that we want the text to display foreign characters?
Try [[textView textStorage] fixFontAttributeInRange:range]; after the [[textView textStorage] replaceCharactersInRange: range withAttributedString: vString] in recolorRange:
I think the problem is editing the text storage again in response to processEditing, which is already the tail end of an edit. -[NSTextStorage processEditing] uses fixFontAttributeInRange:, but since you're trying to edit again, something is going wrong and the fix behavior is being dropped.
When you do it for the whole document, there is a normal beginEditing/endEditing/processEditing sequence which causes fixFontAttributeInRange: to be called happily.