In an android app I'm using PdfDocument to save a report to a pdf file. On a customer's device I'm getting a strange result with the text of the report.
The following is image of header with the following text rendered in DroidSansMono:
Baus Demo Company
4727 4TH AVE SW STE 202
Seatle, WA 9816
Tel: 206-932-986
Fax: 206-932-986
I this same process renders well on most devices. I checked the pdf file and it has the correct font.
here is the full PDF file:
PDF File
Can anyone help me figure out why the text is rendered so?
The reason for this weird look is that this is exactly the formatting the PDF describes.
Horizontal scaling
The content stream of the page consists of three sections:
The top section, all text above the image of a signature, contains at the beginning the instruction
2000 Tz
Inside the section after some text a 1000 Tz follows, then again a 2000 Tz and yet again a 1000 Tz.
The Tz operator sets the horizontal scaling to the preceding number as a percentage value. Thus, these instruction cause all following text (until the end of the section where the graphics state is reset) to be horizontally stretched by a factor of either 10 or 20!
This explains why the glyphs are so wide but not why they overlap so much.
Glyph widths and positioning
The reason why they overlap so much is that each glyph is individually positioned at a distance appropriate for a layout without horizontal scaling.
First of all, the DroidSansMono font information in the PDF declare that virtually all glyphs in the font have a width of 0. Thus, whenever a glyph is drawn, the text insertion point does not wander along to the glyph's end but remains at its start.
Furthermore, each glyph is drawn using an individual operation and between two such single glyph drawing operations the text insertion point is advanced by a separate instruction. But the distance parameter of this instruction is appropriate for the glyphs without horizontal scaling!
This causes all the overlaps.
If this very PDF is rendered "well" (i.e. incorrectly ignoring the Tz operations) on most devices, the PDF renderer used on those devices clearly does a lousy job of PDF rendering.
Related
I don’t know the right way to think about “size” in web pages. I have some web pages which display correctly on various PC and Mac browsers, slightly incorrectly on Iphones, and very incorrectly on Chrome on Android (both Moto g power phone and Lenovo Tab 4 10 tablet). The problem is that point size in paragraphs is too small, under unexpected circumstances. If I can solve the Android problem, I might solve the Iphone problem. The general problem is that if paragraphs are too short (less than two display lines), the text is extremely small. For example,
<p>This is one very short paragraph</p>
<p>This is a second short paragraph</p>
<p>This is a third paragraph, with less than two lines but enough
text that it goes over a single line at the default point size,
ever so slightly</p>
</body></html>
displays as really tiny type, but
<p>This is one very short paragraph</p>
<p>This is a second short paragraph</p>
<p>This is a third paragraph, with less than two lines but enough
text that it goes over a single line at the default point size,
ever so slightly. Actually, there is enough text here that it
goes to over two display lines, and now the point size
changes to be readable</p>
</body></html>
displays as a readable size (comparable to PC-browser displays).
I experimented with setting explicit size in the paragraph style which sometimes works, and sometimes not. The following displayed correctly:
<p style="font-size:120%;">This is one very short paragraph</p>
<p style="font-size:120%;">This is a second short paragraph</p>
<p style="font-size:120%;">This is a third paragraph, with less
than two lines but enough text that it goes over
a single line at the default point size, ever so slightly</p>
</body></html>
Change the number to 105% and the page does not display correctly. There is a threshold at above 117% where I get a correct display, and below that the display is incorrect. It also matters what my sequence of tests is. 117% could work if the previous test was 120%, but not if it was 100%. When I discovered that the sequencing of tests changed the result, I stopped experimenting. I also tried using point size, and found that 14pt or smaller creates the “too small” problem.
<html><body>
<p style="font-size:14pt;">This is one very short paragraph</p>
<p style="font-size:14pt;">This is a second short paragraph</p>
<p style="font-size:14pt;">This is a third paragraph, with less than
two lines but enough text that it goes over a single line at
the default point size, ever so slightly</p>
</body></html>
But 15 pt or larger works. So the problem exists whether I specific an absolute scale like points, or percentage (of what?).
I am looking for general and best approach to specifying size: I think as a starter that I have to explicitly declare a size, All paragraph and table text is a single size, there are two headers with different sizes (about 115% and 140% of paragraph size). I’d like the display to be minimally 14pt at least for phones, but I also need a one-size-fits-all web page. What I most need is that text not vary wildly in size for unfathomable reasons. (Screenshot of first two snippets below)
in IOS Webview, the input type="time" generates a time display widget that is approx 70 pixels wide and when tapped brings up the IOS time picker.
However in Android the same code brings up a 130 pixel wide widget that also brings up a timepicker, albeit a very different style of one. My problem is the widget is far too big for my user interface design to cope with, without a huge amount of re-work.
Does anyone know if it is possible to reduce the length of the time display widget in Android using CSS, or by reducing the fidelity of the time that could be displayed. or is it always set to match the length of the type="date" version.
Alternatively might it be possible to set its style to display:"none" and activate it using javascript by clicking elsewhere?. Has anyone tried this on Android webview?
This seems like a basic question, but I couldn't find a similar one on SO. While reading the documentation, I was having trouble grasping the concepts. I want to understand what the difference is between top and ascent and also bottom and descent. And where exactly is the baseline? Do you have a diagram to help me visualize it?
Let's first review what the documentation says:
Top - The maximum distance above the baseline for the tallest glyph in the font at a given text size.
Ascent - The recommended distance above the baseline for singled spaced text.
Descent - The recommended distance below the baseline for singled spaced text.
Bottom - The maximum distance below the baseline for the lowest glyph in the font at a given text size.
Leading - The recommended additional space to add between lines of text.
Note that the Baseline is what the first four are measured from. It is line which forms the base that the text sits on, even though some characters (like g, y, j, etc.) might have parts that go below the line. It is comparable to the lines you write on in a lined notebook.
Here is a picture to help visualize these things:
Remember that when drawing on a canvas in Java and Android, going down is an increase in y and going up is a decrease in y. That means that FontMetrics' top and ascent are negative numbers since they are measured from the baseline (while descent and bottom are positive numbers). Thus, to get the distance from top to bottom you would need to do (bottom - top).
The leading is the distance between the bottom of one line and the top of the next line. In the picture above, it is the space between the orange of Line 1 and the purple of Line 2. As #MajorTom noted below, in typography the term is more properly defined as "the distance between the baselines of successive lines of type."* However, Android seems to use the term in the more historical sense. The word (pronounced "ledding") comes from the lead strip that the old typesetters used to put between lines of type. It was basically just a way to adjust the line spacing. In Android I've never actually seen the leading be anything other than 0 and I haven't seen it used for anything in the source code. (Correct me if you know where it is used to calculate anything.) You can change the line spacing in a TextView with setLineSpacing in code or android:lineSpacingExtra and android:lineSpacingMultiplier in xml. These methods, however, do not make use of or modify the leading.
Check out these links for more information:
Precise Android Text Drawing
Font Metrics in Java (and Android)
Layout documentation
Java: FontMetrics ascent incorrect?
FontMetrics not correct when run on android device. Simulator fine
Java Font Metrics (Java doesn't seem to use top and bottom)
Explore more
In order to explore Font Metrics more, I made a simple project.
Rather than listing all the code here. I added the project to GitHub. You can either clone the project, or copy the following files into a new project.
FontMetricsView.java (a custom view)
MainActivity.java
activity_main.xml
Do letters ever go above top or below bottom?
Not usually, but they could. Top and bottom, as I understand them, are set by the font (hence "FontMetrics"), so a font maker could make a glyph go higher than whatever they say the top is (or lower than the bottom). Also, with combining diacritical marks in Unicode it can very easily happen. Here is a rather extreme example (taken from here): M̵̳̙͔̟̱͕̓̀̄̉̅ͧ̋͊͌͑́͌ͪ̒̿̀̚a͔̟̝͔ͥ̈́̏ͮͯ̇͆̊̒ͦͦ͘͢͜y̵̴̢͕̝̩̱͈͕̼̣͕̟̌͗̾ͤ̎͌̄ͣͨ͊ͬb̡̯̰̪̜͙̟̝̠͚̜̥̙̤̃ͨ̋̒̒̊ͧͤ͐̓͋̌̾̇̔̈́̀́͡͠e̵ͯͪ̿̿̂̄ͫ̃҉͏͎̣̹̱̜͉̦̞̪̘̠̝̝͍̼̜̖̥̭͟ ̣̞͙͚̝̰̞̹̗̲̣͙͍͍̀̓͊̂̋ͣ̏̑̍̊͌ͩ͐̎̀ͣͣ̚͟ͅh̛͋̏̍̆ͤ͛͐ͨ̌̋ͤ̎̂ͨ̂̓̑̚̕͟͏̻̣͖̖͚͚͓̲̼̪ȁ̔̅̿͐̑͡͏̝͓̮͚̘̦̰͚͎͔͉͚̮̠̕͜ͅṱ̱̼̖̓̂ͭ̏̅͂ͥ͌ͯ͌͠sͪ̓ͪ̄̌̓ͧ͋͐ͬ̅̑҉̨̪̬͎͍̥̬?̡̮̳͙͓͔̹̘̹͓̘̻̦̣͎̫̐ͤ̐͛́͝ ̧̦̼̘͕̪̠̙͖̦̯̦̘͉͈͕͔̘̻̲͑ͨ̊̈́̐ͫ͐̌ͯ̀͘͝Ḩ̷̸̸̹͉̩̜̹̞ͯ̃̃ͧͬͨ̌̀̾̐̈̇ͧ͛̃͐̀ͦ͞A̴̦̗̬̠͙̭͉̟̺͇̭̰͔͕̯̅̃͋ͪ̈́̉̓̌ͯ̈́͆̋̀ͤ̇̂̿̈́̂͡͡Ṱ̲͎͉̣̳̺̱̜̦̬͕̣͉͇͊̌ͥ͐͒̈́̓́ͥ́́̋͂̅ͬ̆͗ͥ̕͢͡S̍ͧ͗̒͗̂̈ͬ͊̚̚͢͏̗̣̳ͅ!̶̨̡͇͚̙͚̭̱̣̲̳̤̞̫̗̣̦̮̖̞͒͆̿̄͑̃̎͡
Plugging that string into Android we get this:
The diacritical marks go above the top and below the bottom. It is interesting to note that the total width and height are correctly measured by the text bounds, though.
Anyway, for all practical purposes in your programming, you can just assume that the max and min for glyph letters are top and bottom. And usually they will stay within ascent and descent. If for whatever reason you need to know for sure if the letters go beyond top or bottom you can use TextPaint.getTextBounds.
Leading is NOT space between lines in typography. Apparently this is something Android code does not take into account. We've been struggling with this ourselves. The proper definition of leading (from Wikipedia):
In typography, leading /ˈlɛdɪŋ/ refers to the distance between the
baselines of successive lines of type. The term originated in the days
of hand-typesetting, when thin strips of lead were inserted into the
forms to increase the vertical distance between lines of type.
From what I can tell, Android does not have a way to specify this.
Special characters such as
📂 ★ ✉
Are being replaced with images in the Android OS. As you can see, this seems to affect native TextViews (see screenshot).
My problem is they are also affecting the HTML I am loading through my app via WebView. The main problem is stars of different colors are all showing up as the same gray star. And other than that, you can imagine the visual inconsistency problems that arise.
If you load this page on Chrome for Android, the characters don't load at all. But if you copy the question and paste it into a plain text program such as ColorNote, you will see what I'm experiencing.
Is there a way to get my own WebView or even my entire app to use the font-family, rather than an image?
A wild guess, since I've only heard about this happening on iOS now.
How can I disable the unicode black telephone from being rendered as a red phone on iOS Mail app?
I need help getting a normal looking unicode down arrow in a UILabel like this ⬇
Unicode has this nifty thing that's called "Variation selectors", which can be used, among others, to select a variant shape of a letter, or to select whether a glyph is to be rendered as a black-and-white standard glyph, or as a colourful picture.
This variants are characters \uFE00 to \uFE0F. In case of emoji, \uFE0E means "render the previous character as a black-and-white glyph", and \uFE0F means "try to draw the previous character as a colourful picture".
So in your case, add \uFE0E after the character.
I'm building an e-Book reader for android. The content of an ebook is often divided into html files (epub) with one or may chapters in them.
I'm planning to build an e-book reader who divides the content of those files into different "pages". The problem is to know how many much text "fits" on one page and to calculate the correct amount of pages since that depends on a number of different factors, such as: font-size, word size, paragraphs, images, page-breaks, headlines etc.
Idealy i would have my text justified and selectable, and since that's not possible with normal TextView or EditText i must use a non-scrollable WebView.
So to sum it up, how can i "measure" how much text that fits on one "page" on my WebView? Or is there a different better approach to solve this? I saw that the Paint class as support for measure text and breakText.
Thanks!
Note : This answer does not use the webview as your display surface.
You can use the Canvas to draw each page. The canvas gives you it's height & width using which you can draw each line on the canvas using drawText based on the width & height available.
Basically you can calculate how many letters can fit in a line , take that many words , taking care you don't split any words and keep drawing the text.
If you break up the tasks to use different workers for each paragraph you can also probably make it fast.
Maybe you can do it like this
Text is being added and rendered inside WebView
In WebView, you can use Javascript to inspect the current state of DOM tree and extract measurements like width and height of individual elements
Javascript communicates back the size of the page back to WebView creator thru some callback
When Javascript detects that the page size threshold is exceeded it sends a signal for a page break needed
Android HTML5 Kindle does page breaking with Javascript so it is definitely possible.
Take a look at the source of FitText or perhaps here. Both figure how much text can fit in a given space. You may be able to borrow ideas from them and adapt for your purposes.