Strikethrough in cell using itext in Android/Java - java

I have two numbers one above the other, but the first one must have an Strikethrough, I'm using a table and cell to put both numbers in the table, is there a way to make what I need?

Create a font with the style STRIKETHRU.
Font f = new Font(Font.FontFamily.HELVETICA, 12, Font.STRIKETHRU);

I am adding an extra answer for the sake of completeness.
Please take a look at the SimpleTable6 example:
In the first row, we strike through a number using a STRIKETHRU font as explained by Paulo:
Font font = new Font(FontFamily.HELVETICA, 12f, Font.STRIKETHRU);
table.addCell(new Phrase("0123456789", font));
In this case, iText has made a couple of decisions for you: where do I put the line? How thick is the line?
If you want to make these decisions yourself, you can use the setUnderline() method:
chunk1.setUnderline(1.5f, -1);
table.addCell(new Phrase(chunk1));
Chunk chunk2 = new Chunk("0123456789");
chunk2.setUnderline(1.5f, 3.5f);
table.addCell(new Phrase(chunk2));
If you pass a negative value for the y-offset parameter, the Chunk will be underlined (see first column). You can also use this method to strike through text by passing a positive y-offset.
As you can see, we also defined the thickness of the line (1.5f). There is another setUnderline() method that also allows you to pass the following parameters:
color - the color of the line or null to follow the text color
thickness - the absolute thickness of the line
thicknessMul - the thickness multiplication factor with the font size
yPosition - the absolute y position relative to the baseline
yPositionMul - the position multiplication factor with the font size
cap - the end line cap. Allowed values are PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_CAP_ROUND and PdfContentByte.LINE_CAP_PROJECTING_SQUARE
See http://api.itextpdf.com/itext/com/itextpdf/text/Chunk.html

Related

iText 7 - Image in Cell of Table fill full height

I add images in my cells of a table, but it doesn't fit the whole height.
The height is not fixed and can change between 2 rows.
How can my images fit the full height of my cells ?
Here is my problem :
Here is the code of creation of my table :
int nbColumns = 7 + planning.size() *4;
Table table = new Table(nbColumns);
table.setWidthPercent(100);
table.addCell(createCell(""));
table.addCell(createCell("Col1"));
table.addCell(createCell("Col2"));
DateFormat hourFormat = new SimpleDateFormat("HH", Locale.FRENCH);
for(Date hourDate : planning){
table.addCell(new Cell(1,4).setTextAlignment(TextAlignment.CENTER).add(hourFormat.format(hourDate)).setFont(regular).setFontSize(10));
}
table.addCell(createCell("Long"));
table.addCell(createCell("A"));
table.addCell(createCell("B"));
table.addCell(createCell(""));
Here is how I add my images for each cell :
String IMG = // my img path
table.addCell(createImageCell(IMG));
public static Cell createImageCell(String path) throws MalformedURLException {
Image img = new Image(ImageDataFactory.create(path));
Cell cell = new Cell().add(img.setMargins(0,0,0,0).setAutoScaleHeight(true).setAutoScale(true)).setPadding(0);
cell.setBorder(null);
return cell;
}
Posting this as an answer for the sake of visibility.
With regards to autoscaling:
setAutoScaleHeight() is currently bugged in iText7 on the develop branch (so the bug will be present in 7.0.5 and prior versions). It currently sets the AUTO_SCALE_WIDTH(probably due to a copy-paste oversight), unless the AUTO_SCALE_WIDTHproperty is already set, then it will put them both on false and set the AUTO_SCALE to true.
Fixing the typo does not result in expected behaviour, since we're now aware of the issue, a ticket for it has been added to our backlog.
Bi-directional autoscaling (via the AUTO_SCALE-property) works correctly, but will scale uniformly and thus only scale to width in these case where the cell is greater in height than width.
As for a temporary solutions or trick to bypass it, I don't have a generic one :( for now, apart from waiting for the fix.
I did a quick test with relative height declarations (which should be included in 7.0.5), but that scaled the image uniformly again. Some trial&error and Image.scaleAbsolute() can get a desired result but that's hardly automate-able. You could in theory hook into the layout-process by writing your own custom CellRenderer, extracting the height of the largest Cell in to row to use in conjuction with scaleAbsolute(), but you're kinda writing the auto-scaling logic yourself at that point.
Some remarks on the OP's posted code as well, in the interest of spreading good practice:
int nbColumns = 7 + planning.size() *4;
Table table = new Table(nbColumns);
The constructor Table(int) is deprecated (since 7.0.2) and can lead to unexpected behaviour in later versions (this was done when improving the table-layouting mechanisms). It's better to pass a UnitValue[], preferably created using UnitValue.createPercentArray(float[]) or UnitValue.createPercentArray(float[])
img.setMargins(0,0,0,0).setAutoScaleHeight(true).setAutoScale(true))
setAutoScale after setAutoScaleHeight makes the latter redundant.

Calculate correct width of a text

I need to read a plan exported by AutoCAD to PDF and place some markers with text on it with PDFBox.
Everything works fine, except the calculation of the width of the text, which is written next to the markers.
I skimmed through the whole PDF specification and read in detail the parts, which deal with the graphic and the text, but to no avail. As far as I understand, the glyph coordinate space is set up in a 1/1000 of the user coordinate space. Hence the width need to be scale up by 1000, but it's still a fraction of the real width.
This is what I am doing to position the text:
float textWidth = font.getStringWidth(marker.id) * 0.043f;
contentStream.beginText();
contentStream.setTextScaling(1, 1, 0, 0);
contentStream.moveTextPositionByAmount(
marker.endX + marker.getXTextOffset(textWidth, fontPadding),
marker.endY + marker.getYTextOffset(fontSize, fontPadding));
contentStream.drawString(marker.id);
contentStream.endText();
The * 0.043f works as an approximation for one document, but fails for the next.
Do I need to reset any other transformation matrix except the text matrix?
EDIT: A full idea example project is on github with tests and example pdfs: https://github.com/ascheucher/pdf-stamp-prototype
Thanks for your help!
Unfortunately the question and comments merely include (by running the sample project) the actual result for two source documents and the description
The annotating text should be center aligned on the top and bottom marker, aligned to the left on the right marker and aligned to the right on the left marker. The alignment is not working for me, as the font.getSTringWidth( .. ) returns only a fraction of what it seems to be. And the discrepance seems to be different in both PDFs.
but not a concrete sample discrepancy to repair.
There are several issues in the code, though, which may lead to such observations (and other ones, too!). Fixing them should be done first; this may already resolve the issues observed by the OP.
Which box to take
The code of the OP derives several values from the media box:
PDRectangle pageSize = page.findMediaBox();
float pageWidth = pageSize.getWidth();
float pageHeight = pageSize.getHeight();
float lineWidth = Math.max(pageWidth, pageHeight) / 1000;
float markerRadius = lineWidth * 10;
float fontSize = Math.min(pageWidth, pageHeight) / 20;
float fontPadding = Math.max(pageWidth, pageHeight) / 100;
These seem to be chosen to be optically pleasing in relation to the page size. But the media box is not, in general, the final displayed or printed page size, the crop box is. Thus, it should be
PDRectangle pageSize = page.findCropBox();
(Actually the trim box, the intended dimensions of the finished page after trimming, might even be more apropos; the trim box defaults to the crop box. For details read here.)
This is not relevant for the given sample documents as they do not contain explicit crop box definitions, so the crop box defaults to the media box. It might be relevant for other documents, though, e.g. those the OP could not include.
Which PDPageContentStream constructor to use
The code of the OP adds a content stream to the page at hand using this constructor:
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
This constructor appends (first true) and compresses (second true) but unfortunately it continues in the graphics state left behind by the pre-existing content.
Details of the graphics state of importance for the observations at hand:
Transformation matrix - it may have been changed to scale (or rotate, skew, move ...) any new content added
Character spacing - it may have been changed to put any new characters added nearer to or farther from each other
Word spacing - it may have been changed to put any new words added nearer to or farther from each other
Horizontal scaling - it may have been changed to scale any new characters added
Text rise - it may have been changed to displace any new characters added vertically
Thus, a constructor should be chosen which also resets the graphics state:
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true, true);
The third true tells PDFBox to reset the graphics state, i.e. to surround the former content with a save-state/restore-state operator pair.
This is relevant for the given sample documents, at least the transformation matrix is changed.
Setting and using the CalRGB color space
The OP's code sets the stroking and non-stroking color spaces to a calibrated color space:
contentStream.setStrokingColorSpace(new PDCalRGB());
contentStream.setNonStrokingColorSpace(new PDCalRGB());
Unfortunately new PDCalRGB() does not create a valid CalRGB color space object, its required WhitePoint value is missing. Thus, before selecting a calibrated color space, initialize it properly.
Thereafter the OP's code sets the colors using
contentStream.setStrokingColor(marker.color.r, marker.color.g, marker.color.b);
contentStream.setNonStrokingColor(marker.color.r, marker.color.g, marker.color.b);
These (int, int, int) overloads unfortunately use the RG and rg operators implicitly selecting the DeviceRGB color space. To not overwrite the current color space, use the (float[]) overloads with normalized (0..1) values instead.
While this is not relevant for the observed issue, it causes error messages by PDF viewers.
Calculating the width of a drawn string
The OP's code calculates the width of a drawn string using
float textWidth = font.getStringWidth(marker.id) * 0.043f;
and the OP is surprised
The * 0.043f works as an approximation for one document, but fails for the next.
There are two factors building this "magic" number:
As the OP has remarked the glyph coordinate space is set up in a 1/1000 of the user coordinate space and that number is in glyph space, thus a factor of 0.001.
As the OP has ignored he wants the width for the string using the font size he selected. But the font object has no knowledge of the current font size and returns the width for a font size of 1. As the OP selects the font size dynamically as Math.min(pageWidth, pageHeight) / 20, this factor varies. In case of the two given sample documents about 42 but probably totally different in other documents.
Positioning text
The OP's code positions the text like this starting from identity text matrices:
contentStream.moveTextPositionByAmount(
marker.endX + marker.getXTextOffset(textWidth, fontPadding),
marker.endY + marker.getYTextOffset(fontSize, fontPadding));
using methods getXTextOffset and getYTextOffset:
public float getXTextOffset(float textWidth, float fontPadding) {
if (getLocation() == Location.TOP)
return (textWidth / 2 + fontPadding) * -1;
else if (getLocation() == Location.BOTTOM)
return (textWidth / 2 + fontPadding) * -1;
else if (getLocation() == Location.RIGHT)
return 0 + fontPadding;
else
return (textWidth + fontPadding) * -1;
}
public float getYTextOffset(float fontSize, float fontPadding) {
if (getLocation() == Location.TOP)
return 0 + fontPadding;
else if (getLocation() == Location.BOTTOM)
return (fontSize + fontPadding) * -1f;
else
return fontSize / 2 * -1;
}
In case of getXTextOffset I doubt that adding fontPadding for Location.TOP and Location.BOTTOM makes sense, especially in the light of the OP's desire
The annotating text should be center aligned on the top and bottom marker
For the text to be centered it should not be shifted off-center.
The case of getYTextOffset is more difficult. The OP's code is built upon two misunderstandings: It assumes
that the text position selected by moveTextPositionByAmount is the lower left, and
that the font size is the character height.
Actually the text position is positioned on the base line, the glyph origin of the next drawn glyph will be positioned there, e.g.
Thus, the y positioned either has to be corrected to take the descent into account (for centering on the whole glyph height) or only use the ascent (for centering on the above-baseline glyph height).
And a font size does not denote the actual character height but is arranged so that the nominal height of tightly spaced lines of text is 1 unit for font size 1. "Tightly spaced" implies that some small amount of additional inter-line space is contained in the font size.
In essence for centering vertically one has to decide what to center on, whole height or above-baseline height, first letter only, whole label, or all font glyphs. PDFBox does not readily supply the necessary information for all cases but methods like PDFont.getFontBoundingBox() should help.

java print job cutting off the edge of the page

An application uses a jEditorPane to display html pages, which also has the ability to print said html page. We construct the MediaPrintableArea for the printerJob attributeSet like so:
float mediaWidth = mediaSize.getX(Size2DSyntax.MM);
float mediaHeight = mediaSize.getY(Size2DSyntax.MM);
float imageableX = 18;
float imageableY = 25;
float imageableWidth = (mediaWidth - (2 * imageableX));
float imageableHeight = (mediaHeight - (2 * imageableY));
MediaPrintableArea imageableArea = new MediaPrintableArea(imageableX, imageableY, imageableWidth, imageableHeight, Size2DSyntax.MM);
So we control the printable area of the page. However, when the moons align and a single line is just the right length, the end of the last character in the line is being cut off.
EX: if a line ends with the word "to", there will only be the left-most half of the 'o' visible on the printed page. I would expect if this were to run off the edge of the printable are, "to" would wrap to the next line, but its not.
Is there some other method of defining the printable area besides using the MediaPrintableArea? Is there anything that can be causing the words to not wrap or how java calculates the placement of the words?
We've also tested several other printers and printed from browsers where we can print beyond there our java print job is cutting off, so I don't think hardware problems should be considered.
You're probably rendering the JEditorPane starting from (0, 0) instead of from PageFormat.getImageableX(), PageFormat.getImageableY(). See http://java.sun.com/developer/onlineTraining/Programming/JDCBook/advprint.html for more information.

How to change line thickness in iText?

I'm drawing images to pdf using Java framework iText. I need to draw lines of specified width. There is a method setLineWidth(float width) in class PdfContentByte that should change it. However no matter what value I pass as its parameter the lines drawn are always extra thin.
There is following line in javadoc of setLineWidth:
The line width specifies the thickness of the line used to stroke a path and is measured in user space units.
I don't know what is "space unit". Everything else in iText seems to be measured in point(around 1/72 inch). I cant find any reference to what are those "space units" and how to change them.
code:
to.setLineWidth(thickness);
to.moveTo(x, y);
to.lineTo(x + 100, y + 100);
Variable to contains instance of PdfContentByte.
Solved. There was no stroke method call after lineTo call. That's why it used another line width set just before stoke method was called.
Correct code look like this:
to.setLineWidth(thickness);
to.moveTo(x, y);
to.lineTo(x + 100, y + 100);
to.stroke();

Apache POI Color cell with formula

I want create a excel with Apache POI in java and I must insert in a cell a formula: A3=B3+C3.
Is possible to insert another formula in A3 that color the cell if his value is> 0?
I use Apache POI 2.5.1
You will need a conditional formatting.
From this document:
// Define a Conditional Formatting rule, which triggers formatting
// when cell's value is greater or equal than 100.0 and
// applies patternFormatting defined below.
HSSFConditionalFormattingRule rule = sheet.createConditionalFormattingRule(
ComparisonOperator.GE,
"100.0", // 1st formula
null // 2nd formula is not used for comparison operator GE
);
// Create pattern with red background
HSSFPatternFormatting patternFmt = rule.cretePatternFormatting();
patternFormatting.setFillBackgroundColor(HSSFColor.RED.index);
// Define a region containing first column
Region [] regions =
{
new Region(1,(short)1,-1,(short)1)
};
// Apply Conditional Formatting rule defined above to the regions
sheet.addConditionalFormatting(regions, rule);
which creates a cell with a red background for values >= 100. Which is almost what you want :-)

Categories

Resources