I'm generating a PDF using iText and wanted to include an iText Form and TextFields so that users can fill in the PDF Form electronically, rather than printing it out.
I've followed the Examples here: http://itextpdf.com/examples/iia.php?id=161
and here: http://itextpdf.com/examples/iia.php?id=162
So far, I have a TextField on my Landscape PDF, and I can click and enter text.
I have two issues:
TextField alignment. To click on the text field, I have to position my mouse to the right of the cell that I added the TextField too. How can I align the TextField with the cell?
Entered Text Rotation. Once I've entered text, it's displayed rotated and 90 degrees to the rest of the page. How can I set the rotation of this displayed text?
The rotation of the entered text is the thing that bugs me th most. I've tried setting the rotation on the cell and the TextField but that seems to have no effect.
Any suggestions?
Thanks
Here is my code:
int rotation = document.getPageSize().getRotation();
PdfFormField pdfForm = PdfFormField.createEmpty(docWriter);
coverSheetPdfForm.setFieldName("Form");
coverSheetPdfForm.setRotate(rotation);
...
cell = new PdfPCell(borderedTable("Cell Title:", tblHeadingFont, "", borderColor));
cell.setColspan(1);
cell.setPadding(5f);
cell.setBorderWidth(0f);
cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
cell.setMinimumHeight(100f);
TextField textField = new TextField(docWriter, new Rectangle(50, 50,rotation), "cell_text_field");
textField.setFontSize(12);
textField.setRotation(rotation);
textField.setVisibility(TextField.VISIBLE);
textField.setBorderColor(borderColor);
textField.setBorderWidth(BORDER_WIDTH);
cell.setCellEvent(new ChildFieldEvent(pdfForm, textField.getTextField(), 1, rotation));
.....
docWriter.addAnnotation(pdfForm);
and the ChildFieldEvent code that I've borrowed from the example page, and added a extra parameter for rotation:
/**
* Creates a ChildFieldEvent.
* #param parent the parent field
* #param kid the child field
* #param padding a padding
* #param rotation
*/
public ChildFieldEvent(PdfFormField parent, PdfFormField kid, float padding, int rotation) {
this.parent = parent;
this.kid = kid;
this.padding = padding;
this.rotation = rotation;
}
/**
* Add the child field to the parent, and sets the coordinates of the child field.
* #param cell
* #param rect
* #param cb
* #see com.lowagie.text.pdf.PdfPCellEvent#cellLayout(com.lowagie.text.pdf.PdfPCell,
* com.lowagie.text.Rectangle, com.lowagie.text.pdf.PdfContentByte[])
*/
#Override
public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] cb) {
try {
parent.addKid(kid);
kid.setWidget(new Rectangle(rect.getLeft(padding), rect.getBottom(padding),
rect.getRight(padding), rect.getTop(padding),rotation),
PdfAnnotation.HIGHLIGHT_INVERT);
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
I've done some more testing and it looks like the Ubuntu PDF fiewer (Document Viewer) is not rendering the PDF correctly as viewing the same file in Windows Adobe PDF Viewer, the form looks fine.
I'll do more testing and report back.
Related
I'm trying to print an Image and a text next to each other into a PdfPCell. The image is bigger than the font size, so the row height is increased. iText renders the Text at the bottom of the baseline (First example).
But I want the text to be vertically aligned in the middle of the cell (Second example).
What can I do to change this? I know I can change the alignment of the cell, but that doesn't change anything.
PdfPCell getImageAndText(byte[] image, String text, int originalDimension){
final Image pdfImg = Image.getInstance(image);
//Scale to 16pt.
pdfImg.scalePercent(16 * 100f / originalDimension);
Phrase image = new Phrase(new Chunk(pdfImg, 0, 0));
//Create Cell with image
final PdfPCell cell = new PdfPCell(image);
//Add text to cell
cell.addElement(new Phrase(text, getFont()));
return cell;
}
I am using iText 2.1.7
I can set hyperlink for cell in Apache POI, but I don't know how to put the hyperlink into an image (I'm using XSSF)
Here is the function of putting cell hyperlink :
/**
* Helper function for putting hyperlink into specified cell
* #param label
* #param value
* #param col
* #param row
* #param sheet
*/
private static void putImageHyperlink(Cell cell, CellStyle hyperlinkStyle, String value, Workbook wb) {
try {
CreationHelper createHelper = wb.getCreationHelper();
Hyperlink link = createHelper.createHyperlink(Hyperlink.LINK_URL);
link.setAddress(value);
cell.setHyperlink(link);
cell.setCellStyle(hyperlinkStyle);
// Put hyperlink value
cell.setCellValue(value);
} catch (Exception e) {
log.severe("Can't create hyperlink : " + Utils.exceptionToString(e));
}
}
And here is the function for putting image into specified cell :
/**
* Put image into sheet at position [row,col]
* #param sheet
* #param col
* #param row
* #param imgData
* #throws Exception
*/
private static void putImage(Workbook wb, Sheet sheet, int col, int row, byte[] imgData) throws Exception {
try {
Drawing drawing = sheet.createDrawingPatriarch();
int pictureIdx = wb.addPicture(imgData, Workbook.PICTURE_TYPE_PICT);
CreationHelper helper = wb.getCreationHelper();
ClientAnchor anchor4 = helper.createClientAnchor();
//set top-left corner of the picture,
//subsequent call of Picture#resize() will operate relative to it
anchor4.setCol1(col);
anchor4.setRow1(row);
anchor4.setCol2(col+1);
anchor4.setRow2(row+1);
drawing.createPicture(anchor4, pictureIdx);
} catch (Exception ex) {
log.severe("Exception : " + Utils.exceptionToString(ex));
}
}
=> How to put hyperlink into picture created by command drawing.createPicture(anchor4, pictureIdx); ?
Thanks in advance!
When looking at how Excel stores this it seems to be stored differently for Images in the xl\drawings\_rels\drawing1.xml.rels and xl\drawings\drawing1.xml part of the XLSX file:
<Relationship Id="rId1" Target="http://poi.apache.org" TargetMode="External" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"/>
<xdr:cNvPr descr="Picture" id="2" name="Picture 1">
<a:hlinkClick xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId1"/>
</xdr:cNvPr>
POI does not support adding such hyperlinks via it's API yet, but you can use the underlying lowlevel-API as follows to first create the relationship for the hyperlink and then set the relation to the hyperlink in the Picture-object:
PackageRelationship rel = ((XSSFDrawing)patriarch).getPackagePart().addRelationship(
new URI("http://poi.apache.org"),
TargetMode.EXTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink");
((XSSFDrawing)patriarch).addRelation(rel.getId(),new POIXMLDocumentPart());
CTPictureNonVisual nvPicPr = ((XSSFPicture)picture).getCTPicture().getNvPicPr();
CTHyperlink hLinkClick = nvPicPr.getCNvPr().addNewHlinkClick();
hLinkClick.setId(rel.getId());
As it says on the tin.. I cannot get a label's text to wrap. Essentially I am building like a comments panel, user enters a comment and its displayed with timestamp etc.
I want the labels to both display with ContentMode.PREFORMATTED but also wrap.
The layouts of which contain the label are fixed width (100%) as is the label obviously by default, from what I have readin the book of vaadin what I am doing should work?
here is my code snippet:
VerticalLayout container = new VerticalLayout();
rootLayout.addComponent(container);
VerticalLayout comment = new VerticalLayout();
container.addComponent(comment);
Label createdByLbl = new Label(entity.getManagedMetadata().getAttrValue("createdBy") + " said:");
createdByLbl.setId("conversation.comment.username." + repositoryUID);
createdByLbl.setStyleName("conversation-comment-username");
Label createdDateLbl = new Label(entity.getManagedMetadata().getAttrValue("createdDate"));
createdDateLbl.setId("conversation.comment.createddate." + repositoryUID);
createdDateLbl.setSizeUndefined();
String text = entity.getDataNode().getAttrValue("text");
Label textLbl = new Label(text, ContentMode.PREFORMATTED);
textLbl.setId("conversation.comment.text." + repositoryUID);
comment.addComponent(createdByLbl);
comment.addComponent(textLbl);
comment.addComponent(createdDateLbl);
comment.setExpandRatio(createdByLbl, 0.2f);
comment.setExpandRatio(textLbl, 0.7f);
comment.setExpandRatio(createdDateLbl, 0.1f);
Note the container is also wrapped by CssLayout (rootLayout), which is full sized.
I want the textLbl as seen above to display as formatted should the user enter text on separate lines themselves and wrap if they have entered a long paragraph comment.
Here is a picturing showing my dilemma.
Any help would be appreciated.
Thanks,
Try with css.
For example:
textLbl.addStyleName("wrapLine");
Css:
.wrapLine{
word-wrap: break-word; /* IE */
white-space: -moz-pre-wrap; /* Firefox */
}
Some background info: I'm creating a system to register lost, found and returned luggage. The amount of those 3 variable need to be in a LineChart to get a nice overview from how much luggage is lost etc. over an amount of time.
Now the problem:
When I create a LineChart and add it to a ChartPanel the LineChart represent a dataset. I've heard that when you edit/update your dataset, the chart is also automatically updated. Well I have an update button next to the chart which has to update the chart when clicked. Independent of the chart in an already existing JPanel/ChartPanel I also create a new frame which represent a ChartFrame.
When I click the update button a new frame pops-up and with the most recent data from the updated dataset. When I click it again, obviously another frame is created, but the already existing frame is also update while the chart in the JPanel isn't though they use the same dataset which is static and comes from a LineChart model.
Well here some code:
LineChartModel
//At the top of the document the dataset is initialize static
public static DefaultCategoryDataset dataset = null;
/*****************Other code omitted***********************/
/**
*
* Updates an already existing dataset
*
* #param dataset
* #return dataset
*/
public CategoryDataset updateDataset(DefaultCategoryDataset dataset) {
this.dataset = dataset;
// row keys...
final String rowLost = "Lost";
final String rowFound = "Found";
final String rowReturned = "Returned";
//Don't pay attention to this. It's setting the value for the dataset from different arrays which I know of the are filled correctly
int i = 0;
while (i < 12) {
dataset.setValue(lost[i], rowLost, type[i]);
System.out.println("There were " + lost[i]
+ " lost luggages in month: " + type[i]);
i++;
}
for (int j = 0; j < 12; j++) {
dataset.setValue(found[j], rowFound, type[j]);
System.out.println("There were " + found[j]
+ " found luggages in month: " + type[j]);
}
for (int j = 0; j < 12; j++) {
dataset.setValue(returned[j], rowReturned, type[j]);
System.out.println("There were " + returned[j]
+ " returned luggages in month: " + type[j]);
}
return dataset;
}
The LineChart Class with his constructor
LineChartModel model = new LineChartModel();
public ChartPanel chartPanel;
/**
* Creates a new demo.
*
* #param title the frame title.
*/
public LineChart(final String title, LineChartModel m) {
m = model;
m.selectRange();
m.createDataset();
final JFreeChart chart = createChart(m.dataset);
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500, 270));
}
ChartController
First the params of the constructor
public ChartController(final ManCharts v, final LineChartModel m) {
view = v;
model = m;
And here the actionlistener of the button.
//Select a range by sumbitting the variables
v.date.btnSubmit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//selectRange select all the data between 2 dates but isn't important for this problem
m.selectRange(/*v.date.dateChooserFrom, v.date.dateChooserTo*/);
//updateDataset updates the dataset from the LineChartModel which is static
m.updateDataset(m.dataset);
//The data in the chart should already be updated but here I'm trying to replace the current chart by a new one
v.chart.chartPanel = new ChartPanel(v.chart.createChart(m.dataset));
//This is the new chart which does automatically update when the button is pressed
JFreeChart chart = ChartFactory.createLineChart("Something chart", "Date", "Value", m.dataset);
ChartFrame frame = new ChartFrame("New line chart", chart);
frame.setVisible(true);
}
});
I really hope someone can help and that this problem is not too complicated without having the full code.
If you need more code or something. Just say so.
Thanks in advance!
EDIT!
I think it has to do something with how I create the chart. The chart in my JPanel which is created at the start of my application is created with an edited method (this is part of my LineChart class and stands below my constructor):
/**
* Creates a sample chart.
*
* #param dataset a dataset.
*
* #return The chart.
*/
public JFreeChart createChart(final CategoryDataset dataset) {
// create the chart...
final JFreeChart chart = ChartFactory.createLineChart(
"Luggage", // chart title
"Time", // domain axis label
"Value", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);
chart.setBackgroundPaint(Color.decode("#d6d9df"));
final CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setRangeGridlinePaint(Color.white);
// customise the range axis...
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setAutoRangeIncludesZero(true);
// customise the renderer...
final LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
//renderer.setDrawShapes(true);
renderer.setSeriesStroke(
0, new BasicStroke(
2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
1.0f, new float[] {10.0f, 6.0f}, 0.0f
)
);
renderer.setSeriesStroke(
1, new BasicStroke(
2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
1.0f, new float[] {6.0f, 6.0f}, 0.0f
)
);
renderer.setSeriesStroke(
2, new BasicStroke(
2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
1.0f, new float[] {2.0f, 6.0f}, 0.0f
)
);
// OPTIONAL CUSTOMISATION COMPLETED.
return chart;
}
SOLVED
It had to do with another dataset that was created when clicking the submit button. So I've fixed the recreation and it's working now. Not really a chart problem, but just a problem in my model. Thanks for the help anyway!
ChartPanel implements an event listener that prompts it to repaint() itself when needed; JPanel does not. See the implementation of ChartChangeListener in chartChanged(), for example. When debugging, look for one instance of ChartPanel that shadows another or an errant use of JPanel.
Addednum Does the frame also need to be an ApplicationFrame or could it work in a JFrame?
Either is acceptable, as shown in this JFrame example or this ApplicationFrame example; both update dynamically. Note that Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
Here is my code. But its not working.
private static void insertWatermarkText(Document doc, String watermarkText) throws Exception
{
// Create a watermark shape. This will be a WordArt shape.
// You are free to try other shape types as watermarks.
Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
// Set up the text of the watermark.
watermark.getTextPath().setText(watermarkText);
watermark.getTextPath().setFontFamily("Arial");
watermark.setWidth(500);
watermark.setHeight(100);
// Text will be directed from the bottom-left to the top-right corner.
watermark.setRotation(-40);
// Remove the following two lines if you need a solid black text.
watermark.getFill().setColor(Color.GRAY); // Try LightGray to get more Word-style watermark
watermark.setStrokeColor(Color.GRAY); // Try LightGray to get more Word-style watermark
// Place the watermark in the page center.
watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
watermark.setWrapType(WrapType.NONE);
watermark.setVerticalAlignment(VerticalAlignment.CENTER);
watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
// Create a new paragraph and append the watermark to this paragraph.
Paragraph watermarkPara = new Paragraph(doc);
watermarkPara.appendChild(watermark);
// Insert the watermark into all headers of each document section.
for (Section sect : doc.getSections())
{
// There could be up to three different headers in each section, since we want
// the watermark to appear on all pages, insert into all headers.
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
}
}
I have resolved my issue. Actually it was conflict of jar file.
Here I got the new jar files. Now my code is working.
Here is the updated code :
/**
* Inserts a watermark into a document.
*
* #param doc The input document file.
* #param watermarkText Text of the watermark.
*/
private static void insertWatermarkText(Document doc, String watermarkText) throws Exception
{
// Create a watermark shape. This will be a WordArt shape.
// You are free to try other shape types as watermarks.
Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
// Set up the text of the watermark.
watermark.getTextPath().setText(watermarkText);
watermark.getTextPath().setFontFamily("Arial");
watermark.setWidth(500);
watermark.setHeight(100);
// Text will be directed from the bottom-left to the top-right corner.
watermark.setRotation(-40);
// Remove the following two lines if you need a solid black text.
watermark.getFill().setColor(Color.GRAY); // Try LightGray to get more Word-style watermark
watermark.setStrokeColor(Color.GRAY); // Try LightGray to get more Word-style watermark
// Place the watermark in the page center.
watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
watermark.setWrapType(WrapType.NONE);
watermark.setVerticalAlignment(VerticalAlignment.CENTER);
watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
// Create a new paragraph and append the watermark to this paragraph.
Paragraph watermarkPara = new Paragraph(doc);
watermarkPara.appendChild(watermark);
// Insert the watermark into all headers of each document section.
for (Section sect : doc.getSections())
{
// There could be up to three different headers in each section, since we want
// the watermark to appear on all pages, insert into all headers.
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
}
System.out.println("Watermark Set");
}
private static void insertWatermarkIntoHeader(Paragraph watermarkPara, Section sect, int headerType) throws Exception
{
HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
if (header == null)
{
// There is no header of the specified type in the current section, create it.
header = new HeaderFooter(sect.getDocument(), headerType);
sect.getHeadersFooters().add(header);
}
// Insert a clone of the watermark into the header.
header.appendChild(watermarkPara.deepClone(true));
}