I (think) have every values for Text-Rendering in a PDF.
* Position (Text Matrix)
* FontDescriptor with Widths Array
* FontBBox
* StemV/StemH
* FontName
* Descent
* Ascent
* CapHeight
* XHeight
* ItalicAngle
My problem is I don't know what to do with these values. I went through the PDF Spec 1.7 a couple of times and cannot find a formular to calculate the real pixel sizes of every glyph in PDF. Can you give me a hint?
Thank you.
What are you trying to do? Rendering PDF is a lot of work and you also need to factor in leading, Text raise, kerning, CTM and several other factors.
Position: (optional, you can avoid it)
Text Matrix: (optional, you can avoid it)
Widths Array: (use empty array [], PDF can read it directly from CFF (FontFile3 stream))
FontBBox: font file->'CFF ' table->Top DICT INDEX->DICT-> 4 operands for 'FontBBox' operator
StemV: (optional, you can avoid it)
StemH: (optional, you can avoid it)
FontName: font file->'name' table->records
or: font file->'CFF ' table->Top DICT INDEX->string by index 0 for 'fonts names' operator
Descent: font file->'hhea' table->'Descender' parameter
Ascent: font file->'hhea' table->'Ascender' parameter
CapHeight: font file->'OS/2' table->'sCapHeight' parameter
XHeight: font file->'OS/2' table->'sxHeight' parameter
ItalicAngle: font file->'OS/2' table->'sxHeight' parameter
Actually, you can calculate Widths array. For each glyph:
Decoding array(PDF) -> Glyph name (PDF) -> Glyph index (CFF table of font file) -> table 'hmtx' -> Glyph 'hMetrics'[Glyph index] = array ('advanceWidth', 'leftSideBearing')
I spent a WEEK, to understand it...
If you want just highlight a text, it's not necessary calculate the text. You can add as much as you want content objects to the page (rectangle, image, line, semi-transparent stuff) and re-calculate the PDF structure. It is really simple. Ask your mouse about the selection coordinates))
These values are designed to properly typeset type, not draw glyphs, so you can't get the exact pixel size of each glyph from these attributes. The only way to get the exact pixel dimensions of a glyph is to draw the glyph into an image and analyze that image.
The FontBBox (font bounding box) is the smallest box that will hold each glyph. The Widths Array holds information on how far apart each character should be drawn, not the actual glyph image size. Some fonts will draw some glyphs outsize that width.
When you highlight text in a typical text editor, the highlight will be the full height of the font, and the width of each individual character. This highlight is made by getting the FontBBox height, and each character's width from the Widths Array, and transforming those values to match the current font's attributes (size, etc.). This information is sufficient to make your app draw type like typical applications.
Related
There's a RectComponent, and a TextComponent inside. The text will change length sometimes.
So I need "text adaptation".
The fontsize :
The size of glyphs (in logical pixels) to use when painting the text.
I cannot find the conversion method between fontSize(logical pixels) and component size.
Is there some formula between "component size" and "font size"?
There is currently no way to automatically fit the text in the size of the RectangleComponent.
You can however use TextComponent.textRenderer.measureWidth and calculate whether the font size has to be smaller or larger than it currently is.
Remember that if you don't use a mono-spaced font, a string with the same amount of characters as another string might become different widths.
You can use FittedBox, check this answer out:
How to dynamically resize text in Flutter?
So, basically, FittedBox makes sure the content always stays within an area.
When I call setFixedHeight() on a PdfPCell, and add more text than fits in the given height, iText seems to print the prefix of the string which fits.
Can I control this clipping algorithm? For example:
Print a suffix of the string rather than a prefix.
Mark a substring of the string as not to be removed. This is with footnote references. If I add text saying "Hello World [1]", the [1] is a reference to a footnote and should not be removed. It's okay to remove the other characters of the string, like "World".
When there are multiple words in the string, iText seems to eliminate a word that doesn't fit, while I would like it partially printed. That is, if the string is "Hello World", and the cell has room only for "Hello Wo...", I would like that to be printed, rather than just "Hello", as iText prints.
Rather than printing characters in their entirety, print only part of them. Imagine printing the text to a PNG and chopping off the top and/or bottom part of the PNG to fit it in the space available. For example, notice that the top line and the bottom line are partially clipped here:
Are any of these possible? Does iText give me any control over how text is clipped? Thanks.
This is with reference to iText 2.1.6.
I have written a proof of concept, ClipCenterCellContent, where we try to fit the text "D2 is a cell with more content than we can fit into the cell." in a cell that is too small.
Just like in your other question ( iText -- How do I get the rendered dimensions of text? ), we add the content using a cell event, but we now add it twice: once in simulation mode (to find out how much space is needed vertically) and once for real (using an offset).
This adds the content in simulation mode (we use the width of the cell and an arbitrary height):
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText ct = new ColumnText(canvas);
ct.setSimpleColumn(new Rectangle(0, 0, position.getWidth(), -1000));
ct.addElement(content);
ct.go(true);
float spaceneeded = 0 - ct.getYLine();
System.out.println(String.format("The content requires %s pt whereas the height is %s pt.", spaceneeded, position.getHeight()));
We now know the needed height and we can add the content for real using an offset:
float offset = (position.getHeight() - spaceneeded) / 2;
System.out.println(String.format("The difference is %s pt; we'll need an offset of %s pt.", -2f * offset, offset));
PdfTemplate tmp = canvas.createTemplate(position.getWidth(), position.getHeight());
ct = new ColumnText(tmp);
ct.setSimpleColumn(0, offset, position.getWidth(), offset + spaceneeded);
ct.addElement(content);
ct.go();
canvas.addTemplate(tmp, position.getLeft(), position.getBottom());
In this case, I used a PdfTemplate to clip the content.
I also have answers to your other questions, but I don't have the time to answer them right now.
For straight Text box clipping, I adapted the C# code given here
http://itextsharp.10939.n7.nabble.com/Limiting-Text-Width-using-PdfContentByte-td2481.html
to the Java code below. The clipping area ends up outside this rectangle, so you can still draw a rectangle on the same exact coordinates.
cb.saveState();
cb.rectangle(left,top,width,height);
cb.clip();
cb.newPath();
// perform clipped output here
cb.restoreState();
I used a try/finally to ensure restoreState() was called.
When I generate a CCLabelBMFont object, the font seems to include some leading whitespace on the top and bottom of the characters, and this empty space is included in the font object that I create. Sometimes, I need to position the object precisely by the top and bottom, and this offset ruins my spacing. I want to do is trim the font so that its bounds and content size is only the space in which there are no pixels with an alpha greater than 0.
Using Glyph Designer you can export FNT/PNG files. Although the parameter is not exposed in GlyphDesigner GUI, you can modify (decrease) the lineHeight parameter directly in the FNT file. You can also change the yOffset parameter for every character included in your font.
It makes it a little harder to maintain as those manual changes will be overwritten each time you re-publish with GlyphDesigner, but at least you have a way to adress your problem.
Hope that helps.
You can use a tool like Glyph Designer to set the padding and spacing parameters for your BMFont.
Glyph Designer: http://glyphdesigner.71squared.com
I use iReport to create reports, and I would like to know if there is a way to set the width of "optically grouped fields". They should be set to the minimal size that still displays longest text. I have Static Text on left side and Text Field right of them. This Text Fields are set to the width 150 and alignment to right, but I'd like to set smaller size to wipe out white spaces.
Consider some thing like this
Name: Paul
Surname: Smither
And want automatically to
Name: Paul
Surname: Smither
etc. can be smaller then preset size but no bigger.
Is there a way?? even some component
You cannot change the element width dynamically without using Java frameworks.
The quote from JasperReports Ultimate Guide:
ELEMENT SIZE
The width and height attributes are mandatory and represent the size
of the report element measured in pixels. Other element stretching
settings may instruct the reporting engine to ignore the specified
element height. Even in this case, the attributes remain mandatory
since even when the height is calculated dynamically, the element will
not be smaller than the originally specified height.
You can read this article for better understanding the mechanism of changing the element size.
If it's genuinely just a couple of fields that come from the same row in the dataset, then you could hack something together.
Use a monospace font
Define your maximum field length with a String set to N spaces. For example:
$P{MaxLengthString} default value is 10 spaces: " "
Change your field text from $F{FirstName} to this:
$P{MaxLengthString}.substring(
$P{MaxLengthString}.length() + $F{FirstName}.length() - java.lang.Math.max($F{FirstName}.length(), $F{LastName}.length())
) + $F{FirstName}
That is... er... a bit more complex. And it only works with monospace fonts. And I can't believe I really suggested this. Don't do it. (But it ought to work.)
I'm using FreeType2 for font rendering, and I need to get a global bounding box for all fonts, so I can align them in a nice grid. I call FT_Set_Char_Size followed by extracting the global bounds using
int pixels_x = ::FT_MulFix((face->bbox.xMax - face->bbox.xMin), face->size->metrics.x_scale );
int pixels_y = ::FT_MulFix((face->bbox.yMax - face->bbOx.yMin), face->size->metrics.y_scale );
return Size (pixels_x / 64, pixels_y / 64);
which works, but it's quite a bit too large. I also tried to compute using doubles (as described in the FreeType2 tutorial), but the results are practically the same. Even using just face->bbox.xMax results in bounding boxes which are too wide. Am I doing the right thing, or is there simply some huge glyph in my font (Arial.ttf in this case?) Any way to check which glyph is supposedly that big?
Why not calculate the min/max from the characters that you are using in the string that you want to align? Just loop through the characters and store the maximum and minimum from the characters that you are using. You can store these values after you rendered them so you don't need to look it up every time you render the glyphs.
I have a similar problem using freetype to render a bunch of text elements that will appear in a grid. Not all of the text elements are the same size, and I need to prerender them before I know where they would be laid out. The different sizes were the biggest problem when the heights changed, such as for letters with descending portions (like "j" or "Q").
I ended up using the height that is on the face (kind of like you did with the bbox). But like you mentioned, that value was much to big. It's supposed to be the baseline to baseline distance, but it appeared to be about twice that distance. So, I took the easy way out and divided the reported height by 2 and used that as a general height value. Most likely, the height is too big because there are some characters in the font that go way high or way low.
I suppose a better way might be to loop through all the characters expected to be used, get their glyph metrics and store the largest height found. But that doesn't seem all that robust either.
Your code is right.
It's not too large.
Because there are so many special symbols that is vary large than ascii charater. . view special big symbol
it's easy to traverse all unicode charcode, to find those large symbol.
if you only need ascii, my hack method is
FT_MulFix(face_->units_per_EM, face_->size->metrics.x_scale ) >> 6
FT_MulFix(face_->units_per_EM, face_->size->metrics.y_scale ) >> 6