I am creating labels (as in Avery labels) using iText 5 tables. Positioning of label elements requires some very tight tolerances in order to fit everything on the label. My problem is that I have various zones on the label as PdfPCells. I need to fit text into these zones with 0 wasted space. But I always seem to have extra space at the top of the cell. This is best illustrated by using .setVerticalAlignment(Element.ALIGN_TOP); which does not bring the text to the top of my cell.
I'd show image but apparently I'm not allowed.
How do I get rid of this space?
package actions.test;
import java.io.FileOutputStream;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class PdfCellTest
{
public static void main(String[] args) throws Exception {
System.out.println("Cell Test");
BaseFont bf = BaseFont.createFont
(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.EMBEDDED);
Font companyFont =new Font(bf);
companyFont.setSize(10.5f);
companyFont.setColor(BaseColor.BLUE);
companyFont.setStyle(Font.BOLD);
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("c:\\temp\\celltest.pdf"));
document.open();
PdfPTable main = new PdfPTable(1);
main.setWidthPercentage(30);
Phrase companyPhrase = new Phrase("My Company Name, LLC",companyFont);
PdfPCell companyCell = new PdfPCell(companyPhrase);
companyCell.setHorizontalAlignment(Element.ALIGN_CENTER);
companyCell.setVerticalAlignment(Element.ALIGN_TOP);
companyCell.setBorder(Rectangle.BOX);
companyCell.setBorderColor(BaseColor.RED);
companyCell.setPadding(0);
companyCell.setFixedHeight(10.5f);
companyCell.setBackgroundColor(BaseColor.WHITE);
main.addCell(companyCell);
document.add(main);
document.close();
}
}
You are very close to the solution. All the properties you're setting are OK, now try adding:
companyCell.setUseAscender(true);
companyCell.setUseDescender(true);
What do these methods do? They take into account metrics that are stored in the font that is being used. You talk about the top padding, but you'll notice that the "descender" will also have a nice effect on the bottom padding.
The top "padding" isn't really a padding. It's the "leading". You are using the default font, which is Helvetica 12pt. The default leading is 1.5 times the font size. That's 18pt. You are working in text mode, which means that you can define the leading at the level of the cell (as opposed to composite mode where you define the leading at the level of the elements). For instance: you can remove 4pt from the top "padding" like this:
companyCell.setLeading(14);
Important: this will also reduce the spacing between the different lines. If that i not an option, you may want to switch to composite mode.
Related
I'm using iTextSharp 5.5.13 and when i try to generate the PDF with Hebrew it comes out empty.
this is my code: I'm i doing something wrong?
public byte[] GenerateIvhunPdf(FinalIvhunSolution ivhun)
{
byte[] pdfBytes;
using (var mem = new MemoryStream())
{
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.GetInstance(document, mem);
writer.PageEvent = new MyHeaderNFooter();
document.Open();
var font = new
Font(BaseFont.CreateFont("C:\\Downloads\\fonts\\Rubik-Light.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED), 14);
Paragraph p = new Paragraph("פסקת פתיחה")
{
Alignment = Element.ALIGN_RIGHT
};
PdfPTable table = new PdfPTable(2)
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL
};
PdfPCell cell = new PdfPCell(new Phrase("מזהה", font));
cell.BackgroundColor = BaseColor.BLACK;
table.AddCell(cell);
document.Add(p);
document.Add(table);
document.Close();
pdfBytes = mem.ToArray();
}
return pdfBytes;
}
The PDF comes out blank
I changed a few details of your code, and now I get this:
My changes:
Embedding the font
As I don't have Rubik installed on my system, I have to embed the font into the PDF to have a chance to see anything. Thus, I replaced BaseFont.NOT_EMBEDDED by BaseFont.EMBEDDED when creating the var font:
var font = new Font(BaseFont.CreateFont("Rubik-Light.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 14);
Making the Paragraph kind of work
You create the Paragraph p without specifying a font. Thus, a default font with default encoding is used. The default encoding is WinAnsiEncoding which is Latin1-like, so no Hebrew characters can be represented. I added your Rubik font instance to the Paragraph p creation:
Paragraph p = new Paragraph("פסקת פתיחה", font)
{
Alignment = Element.ALIGN_RIGHT
};
Et voilà, the writing appears.
iText developers often have communicated that in iText 5.x and earlier right-to-left scripts are only supported properly in certain contexts, e.g. in tables, but not in others like paragraphs immediately added to the document. As your Paragraph p is added immediately to the Document document, its letters appear in the wrong order in the output.
Making the PdfPTable work
You defined the PdfPTable table to have two columns (new PdfPTable(2)) but then you added only one cell. Thus, table contains not even a single complete row. iText, therefore, draws nothing when it is added to the document.
I changed the definition of table to have a single column only:
PdfPTable table = new PdfPTable(1)
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL
};
Furthermore, I commented out the line setting the cell background to black because usually it is difficult to read black on black:
PdfPCell cell = new PdfPCell(new Phrase("מזהה", font));
//cell.BackgroundColor = BaseColor.BLACK;
table.AddCell(cell);
And again the writing appears.
Properly downloading the font
Another possible obstacle is that when downloading the font from the URL you gave — https://fonts.google.com/selection?selection.family=Rubik — one can see in the customization tab of the selection drawer that by default only Latin characters are included in the download, in particular not Hebrew ones:
I tested with a font file I downloaded with all language options enabled:
I'd not normally ask for help here, but I'm stumped - this bug is the strangest thing I've seen in a long time.
https://gfycat.com/FluidFrigidEastsiberianlaika
I've got a simple UI object called GhostProgressBar that extends ScalaFX.StackPane and gives it two children - a ProgressBar and a Label. I noticed after adding it to some other UI screens that my framerate had plummeted, to a point where the UI was painfully unusuable.
The code for this is super simple:
import scalafx.geometry.Pos
import scalafx.scene.control.{Label, ProgressBar}
import scalafx.scene.layout.StackPane
class GhostProgressBar extends StackPane {
alignment = Pos.Center
val bar = new ProgressBar() {
prefWidth = Integer.MAX_VALUE
}
val text = new Label() {
id = "ProgressBarText"
text = "PERFORMANCE TESTING"
}
children = List(bar, text)
}
In the GIF I'm using it inside a VBox that's the center element of a regular BorderPane - nothing strange or atypical.
From the behaviour I've observed, I think it's an issue with text being drawn over the bar of the ProgressBar. Just now I've done some more debugging, and my suspicions that it was related to the styling of the text were confirmed.
This is the styling that's on the text in the GIF.
#ProgressBarText {
-fx-text-fill: #dddddd;
-fx-font-weight: bold;
}
#ProgressBarText .text {
-fx-stroke: #333333;
-fx-stroke-width: 1px;
-fx-stroke-type: outside;
}
When I remove that styling, the framerate doesn't drop when the bar hits the text.
What I can't figure out is why this is happening? Anyone got any ideas? I have no idea if it's a Scala thing, or a ScalaFX thing, whether or not it's reproducible with the same stuff in a JavaFX context.
Help would be appreciated.
EDIT: I was asked for versions, here we go:
Scala version: 2.12.7
ScalaFX version: 8.0.102-R11
JDK version: 1.8.0_181
JavaFX version: unknown, I'm not familiar with ScalaFX's internals and I'm not using JavaFX directly.
EDIT 2: I was asked to try the same screen elements, but using JavaFX elements instead of ScalaFX ones. Here's the code I used, the outcome was the same - whenever the outlined text was over the progress bar's bar, the framerate dropped.
import javafx.geometry.Pos
import javafx.scene.control.{Label, ProgressBar}
import javafx.scene.layout.StackPane
class JavaFXGhostProgressBar extends StackPane {
this.setAlignment(Pos.CENTER)
val bar = new ProgressBar()
bar.setMaxWidth(Double.MaxValue)
val text = new Label()
text.textProperty().setValue("PERFORMANCE TESTING")
text.idProperty().setValue("OutlineProgressBarText")
this.getChildren.addAll(bar, text)
}
I couldn't find out what version of JavaFX I used here; IntelliJ was weirdly inconsiderate in not telling me. I couldn't find it in my external libraries list, either.
I am attempting to use TextMarginFinder to prove that odd and even pages back up correctly when printing. I have based my code on:
http://itextpdf.com/examples/iia.php?id=280
The issue I have is that on odd pages I am looking for the box to be aligned to the left showing a 1CM back margin for example, and on an even page I would expect the page box to be aligned to the right also showing a 1CM back margin. Even in the example above this is not the case, but when printed the text does back up perfectly because the Trim Box conforms.
In summary I believe on certain PDF files the TextMarginFinder is incorrectly locating the text width, usually on Even pages. This is evident by the width being greater than the actual text. This is usually the case if there are slug marks outside of the Media Box area.
In the PDF the OP pointed to (margins.pdf from the iText samples themselves) indeed the box is not flush with the text:
If you look into the PDF Content, though, you'll see that many of the lines have a trailing space character, e.g. the first line:
(s I have worn out since I started my ) Tj
These trailing space characters are part of the text and, therefore, the box does not flush with the visible text but it does with the text including such space characters.
If you want to ignore such space characters, you can try doing so by filtering such trailing spaces (or for the sake of simplicity all spaces) before they get fed into the TextMarginFinder. To do this I'd explode the TextRenderInfo instances character-wise and then filter those which trim to empty strings.
A helper class to explode the render info objects:
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
public class TextRenderInfoSplitter implements RenderListener
{
public TextRenderInfoSplitter(RenderListener strategy) {
this.strategy = strategy;
}
public void renderText(TextRenderInfo renderInfo) {
for (TextRenderInfo info : renderInfo.getCharacterRenderInfos()) {
strategy.renderText(info);
}
}
public void beginTextBlock() {
strategy.beginTextBlock();
}
public void endTextBlock() {
strategy.endTextBlock();
}
public void renderImage(ImageRenderInfo renderInfo) {
strategy.renderImage(renderInfo);
}
final RenderListener strategy;
}
Using this helper you can update the iText sample like this:
RenderFilter spaceFilter = new RenderFilter() {
public boolean allowText(TextRenderInfo renderInfo) {
return renderInfo != null && renderInfo.getText().trim().length() > 0;
}
};
PdfReader reader = new PdfReader(src);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
TextMarginFinder finder = new TextMarginFinder();
FilteredRenderListener filtered = new FilteredRenderListener(finder, spaceFilter);
parser.processContent(i, new TextRenderInfoSplitter(filtered));
PdfContentByte cb = stamper.getOverContent(i);
cb.rectangle(finder.getLlx(), finder.getLly(), finder.getWidth(), finder.getHeight());
cb.stroke();
}
stamper.close();
reader.close();
The result:
In case of slug area text etc you might want to filter more, e.g. anything outside the crop box.
Beware, though, there might be fonts in which the space character is not invisible, e.g. a font of boxed characters. Taking the spaces out of the equation in that case would be wrong.
I have a TabLayoutPanel where I am putting custom widgets in for the tabs to be able to display some images next to the text. I originally worked with TabPanel and using custom HTML for the tab text, but custom tab widgets allows me to modify the image on the fly as needed.
My tab widget is essentially a HorizontalPanel, a number of small images, and a line of text. The problem I'm having is that the tab doesn't want to stick to the bottom of the tab bar like normal. The tab is getting positioned at the top of the space reserved for the tab bar, and there's a gap between it and the bottom of the tab bar. I uploaded an image of the problem to http://imgur.com/fkSHd.jpg.
Is there some style that I need to apply to custom widget tabs to make them appear correctly?
In my brief experience, the newer standards mode panels (they all end in "LayoutPanel") don't get along with the older ones (the ones that just end in "Panel"). So you might consider trying a DockLayoutPanel instead of the HorizontalPanel, and it may be more cooperative.
See https://developers.google.com/web-toolkit/doc/latest/DevGuideUiPanels, particularly the section called "What won't work in Standards Mode?":
HorizontalPanel is a bit trickier. In some cases, you can simply
replace it with a DockLayoutPanel, but that requires that you specify
its childrens' widths explicitly. The most common alternative is to
use FlowPanel, and to use the float: left; CSS property on its
children. And of course, you can continue to use HorizontalPanel
itself, as long as you take the caveats above into account.
After a bit more research, I found the answer here: https://groups.google.com/d/msg/google-web-toolkit/mq7BuDaTNgk/wLqPm5MQeicJ. I had to use InlineLabel or InlineHTML widgets instead of normal Label or HTML widgets. I've tested this solution and it does exactly what I want. I pasted the code of the class below for completeness. Note two things here:
The "float" attribute cannot be set on the last element (the InlineLabel) or the incorrect drawing condition occurs again.
The code could be cleaned up a bit further by having the class extend directly from FlowPanel instead of making it a composite containing a FlowPanel.
package com.whatever;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Float;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineLabel;
public class StatusTab extends Composite
{
public interface StatusImages extends ClientBundle
{
public static StatusImages instance = GWT.create(StatusImages.class);
#Source("images/status-green.png")
ImageResource green();
#Source("images/status-red.png")
ImageResource red();
}
private final ImageResource greenImage;
private final ImageResource redImage;
private final FlowPanel flowPanel;
public LinkStatusTab(String text, int numStatuses) {
greenImage = StatusImages.instance.green();
redImage = StatusImages.instance.red();
flowPanel = new FlowPanel();
initWidget(flowPanel);
for (int i = 0; i < numStatuses; i++)
{
Image statusImg = new Image(redImage);
statusImg.getElement().getStyle().setMarginRight(3, Unit.PX);
statusImg.getElement().getStyle().setFloat(Float.LEFT);
flowPanel.add(statusImg);
}
flowPanel.add(new InlineLabel(text));
}
/**
* Sets the image displayed for a specific status entry.
*/
public void setStatus(int which, boolean status)
{
Image image = (Image)flowPanel.getWidget(which);
if (status)
image.setResource(greenImage);
else
image.setResource(redImage);
}
}
I have an SWT window wherein there is Group widget in which i placed couple of other widgets,i set the title of group & its working fine. The group title color is blue always(in my case i am not sure) and that doesn't sync up with other children inside group.So i wonder if there is a way to change the group title text color and font if there is a way ?
It's quite easy to change font of group, check this snippet (used snippet from java2s.com)
//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner#interspatial.com)
//Robert Harris (rbrt_harris#yahoo.com)
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
* This class demonstrates groups
*/
public class GroupExample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
// Create the first group
Group group1 = new Group(shell, SWT.SHADOW_IN);
group1.setText("Who's your favorite?");
group1.setLayout(new RowLayout(SWT.VERTICAL));
group1.setFont(new Font(display, "Consolas", 10, SWT.BOLD));
new Button(group1, SWT.RADIO).setText("John");
new Button(group1, SWT.RADIO).setText("Paul");
new Button(group1, SWT.RADIO).setText("George");
new Button(group1, SWT.RADIO).setText("Ringo");
// Create the second group
Group group2 = new Group(shell, SWT.NO_RADIO_GROUP);
group2.setText("Who's your favorite?");
group2.setLayout(new RowLayout(SWT.VERTICAL));
group2.setForeground(new Color(display, new RGB(255, 0, 0)));
new Button(group2, SWT.RADIO).setText("Barry");
new Button(group2, SWT.RADIO).setText("Robin");
new Button(group2, SWT.RADIO).setText("Maurice");
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
It provides this behavior on W7
But as you can see, change of color by setForeground(Color c) doesn't change a thing, when I search for additional info I found bug report on SWT bugzilla The color of the title of the group control cannot be changed. It's windows platform dependent bug.
But you can try a Group without text + a Label widget, this maybe a solution if you just want a better GUI.