I'm using itext 7.1.8 and I need to add fields with the same names to pdf. I use the code like the following:
public class Main {
public static void main(String[] args) {
final PdfDocument emptyPdfDocument = createEmptyPdfDocument(pdf);
addTextField("Text_1", "Hello", emptyPdfDocument.getFirstPage(), PdfAcroForm.getAcroForm(emptyPdfDocument, true), emptyPdfDocument);
addTextField("Text_1", "Hello", emptyPdfDocument.addNewPage(), PdfAcroForm.getAcroForm(emptyPdfDocument, true), emptyPdfDocument);
savePdf(emptyPdfDocument);
}
private static void addTextField(String name, String value, PdfPage page, PdfAcroForm form, PdfDocument pdf) {
PdfFormField field = form.getField(name);
final Rectangle rect = new Rectangle(100, page.getCropBox().getHeight() - 100, 300, 20);
if (field != null) {
PdfWidgetAnnotation annotation = new PdfWidgetAnnotation(rect);
annotation.makeIndirect(pdf);
annotation.setVisibility(VISIBLE);
field.addKid(annotation);
page.addAnnotation(annotation);
return;
}
field = PdfFormField.createText(pdf, rect, name);
field.setValue(value);
field.setVisibility(VISIBLE);
page.addAnnotation(field.getWidgets().get(0));
form.addField(field, page);
}
private static PdfDocument createEmptyPdfDocument(final String pdfPath) throws IOException {
PdfWriter pdfWriter = new PdfWriter(new FileOutputStream(pdfPath));
final PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.addNewPage();
return pdfDocument;
}
public static void savePdf(PdfDocument pdf) {
pdf.close();
}
}
but when the method addTextField has been called the second time the kids of the field are empty.
I don't understand what I'm doing wrong.
Related
I'm writing a program that takes a template PDF with a bunch of blank form fields, makes a copy of it, fills in the forms, then flattens the fields.
One of these templates has a ton of fields so writing a method that fills in all the fields results in an error that says code is too large due to the size limits on methods.
To work around this, I closed the destination file then tried to open it in another method where I could continue to fill in the fields, but this results in an error that says "(The requested operation cannot be performed on a file with a user-mapped section open)"
I ended the first method by closing the PDF, so I'm not sure what the issue is. The program will execute the first method, fill the fields but throws the error when it get to the 2nd method. Sample code below.
public void E2fill(String srcE2, String destE2) throws IOException
{
try
{
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
PdfFormField field2;
fields2.get("fieldname1").setValue(stringname1);
//lots more field fills
pdf2.close()
}
catch(Exception x)
{
System.out.println(x.getMessage());
}
}
public void E2fill2(String destE2, String dest2E2) throws IOException
{
try
{
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
PdfFormField field2;
fields2.get("fieldname546").setValue(stringname546);
//more field fills
form2.flattenFields();
pdf2.close();
}
catch(Exception x)
{
System.out.println(x.getMessage());
}
}
I suggest you try this:
public void fill(String srcE2, String destE2) {
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
E2fill(fields2);
E2fill2(fields2);
form2.flattenFields();
pdf2.close();
}
public void E2fill(Map<String, PdfFormField> fields2) throws IOException
{
fields2.get("fieldname1").setValue(stringname1);
//lots more field fills
}
public void E2fill2(PdfAcroForm form2) throws IOException {
fields2.get("fieldname546").setValue(stringname546);
//more field fills
}
I am updating the values of an editable PDF using PDFBox. Instead of saving, I want to return stream. I saved it, it works all fine. Now I want to return byte[] instead of saving it.
public static void main(String[] args) throws IOException
{
String formTemplate = "myFormPdf.pdf";
try (PDDocument pdfDocument = PDDocument.load(new File(formTemplate)))
{
PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
if (acroForm != null)
{
PDTextField field = (PDTextField) acroForm.getField( "sampleField" );
field.setValue("Text Entry");
}
pdfDocument.save("updatedPdf.pdf"); // instead of this I need STREAM
}
}
I tried SerializationUtils.serialize but it fails to serialize it.
Failed to serialize object of type: class org.apache.pdfbox.pdfmodel.PDDcoumemt
Use the overloaded save method which accepts an OutputStream and use ByteArrayOutputStream.
public static void main(String[] args) throws IOException
{
String formTemplate = "myFormPdf.pdf";
try (PDDocument pdfDocument = PDDocument.load(new File(formTemplate)))
{
PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
if (acroForm != null)
{
PDTextField field = (PDTextField) acroForm.getField( "sampleField" );
field.setValue("Text Entry");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pdfDocument.save(baos);
byte[] pdfBytes = baos.toByteArray(); // PDF Bytes
}
}
Here is the code to read a PDF with iText5, and it works :
public class CreateTOC {
public static final String SRC = "file.pdf";
class FontRenderFilter extends RenderFilter {
public boolean allowText(TextRenderInfo renderInfo) {
String font = renderInfo.getFont().getPostscriptFontName();
return font.endsWith("Bold") || font.endsWith("Oblique");
}
}
public static void main(String[] args) throws IOException, DocumentException {
new CreateTOC().parse(SRC);
}
public void parse(String filename) throws IOException {
PdfReader reader = new PdfReader(filename);
Rectangle rect = new Rectangle(1000, 1000);
RenderFilter regionFilter = new RegionTextRenderFilter(rect);
FontRenderFilter fontFilter = new FontRenderFilter();
TextExtractionStrategy strategy = new FilteredTextRenderListener(
new LocationTextExtractionStrategy(), regionFilter, fontFilter);
System.out.println(PdfTextExtractor.getTextFromPage(reader, 56, strategy));
reader.close();
}
}
Can someone help me to do it working in iText7 ? There are problems with the Rectangle and the TextExtractionStrategy (it's not the same constructor as iText5)
Edit : RenderFilter isn't available in iText7...
I am currently trying to create an application that converts any font code from a software project into a PDF. I'm using iText to generate the PDF but I can't keep the tabbing of the file.
Here's the method that reads the files(simple bufferedReader, but I get every read line and put it in a linkedList):
public static LinkedList<String> lerArquivoQualquerDeTexto(String URL) {
LinkedList<String> textoLido = new LinkedList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(URL)))
{
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null)
{
System.out.println(sCurrentLine);
textoLido.add(sCurrentLine + System.lineSeparator());
}
return textoLido;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
And here's the iText convertion of this LinkedList i just read using BufferedReader:
private static String FILE = "c:/temp/FirstPdf.pdf";
private static Font catFont = new Font(Font.FontFamily.TIMES_ROMAN, 18,
Font.BOLD);
private static Font redFont = new Font(Font.FontFamily.TIMES_ROMAN, 9,
Font.NORMAL, BaseColor.RED);
private static Font subFont = new Font(Font.FontFamily.TIMES_ROMAN, 16,
Font.BOLD);
private static Font smallBold = new Font(Font.FontFamily.TIMES_ROMAN, 12,
Font.BOLD);
private static Font smallFont = new Font(Font.FontFamily.TIMES_ROMAN, 9,
Font.NORMAL);
/**
* gera o PDF de UM único arquivo já lido
* #param textoLido texto lido pelo buffer
* #param nomeDoArquivoLido nome do arquivo lido, já obtido pelo LeitorArquivoTexto.java
* #return
*/
public static boolean gerarPDFDeString(LinkedList<String> textoLido, String nomeDoArquivoLido)
{
try {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(FILE));
document.open();
addMetaData(document);
addTitlePage(document);
addContent(document, textoLido, nomeDoArquivoLido);
document.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// iText allows to add metadata to the PDF which can be viewed in your Adobe
// Reader
// under File -> Properties
private static void addMetaData(Document document) {
document.addTitle("My first project to register");
document.addSubject("Using iText");
document.addKeywords("Java, PDF, iText");
document.addAuthor("Lars Vogel");
document.addCreator("Lars Vogel");
}
private static void addTitlePage(Document document)
throws DocumentException {
Paragraph preface = new Paragraph();
// We add one empty line
addEmptyLine(preface, 1);
// Lets write a big header
preface.add(new Paragraph("Nome Do Projeto", redFont));
addEmptyLine(preface, 1);
// Will create: Report generated by: _name, _date
preface.add(new Paragraph("Report generated by: " + System.getProperty("user.name") + ", " + new Date(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
smallBold));
addEmptyLine(preface, 3);
document.add(preface);
// Start a new page
document.newPage();
}
private static void addContent(Document document, LinkedList<String> textoArquivoLido, String nomeDoArquivoLido) throws DocumentException {
Anchor anchor = new Anchor(nomeDoArquivoLido, redFont);
anchor.setName(nomeDoArquivoLido);
// Second parameter is the number of the chapter
Chapter catPart = new Chapter(new Paragraph(anchor), 1);
for(int i = 0; i < textoArquivoLido.size(); i++)
{
String umaLinhaLida = textoArquivoLido.get(i);
Phrase umaLinhaDoPdf = new Phrase(umaLinhaLida, smallFont);
catPart.add(umaLinhaDoPdf);
}
// now add all this to the document
document.add(catPart);
}
I'm trying to convert a .java file from my java project, but the problem is: my output file(the .pdf file) keeps being written without any of my formatting tabs! Any ideas how to solve this?
I'm creating an excel file using jxl. At first is should contain only some formatting and information about styles. Then, it should be updated every time someone adds new data to it.
public class WriteExcel {
private static WritableWorkbook workbook;
private static WritableCellFormat timesStandard;
private String inputFile;
final private static int FONT_SIZE = 12;
public void setOutputFile(String inputFile) {
this.inputFile = inputFile;
}
private void prepareSheet(WritableSheet sheet) throws WriteException {
sheet.mergeCells(0, 0, 1, 0);
sheet.mergeCells(3, 0, 4, 0);
sheet.mergeCells(6, 0, 7, 0);
WritableFont times12pt = new WritableFont(WritableFont.TIMES, FONT_SIZE);
timesStandard = new WritableCellFormat(times12pt);
CellView cv = new CellView();
cv.setFormat(timesStandard);
}
public void write() throws IOException, WriteException {
File file = new File(inputFile);
WorkbookSettings wbSettings = new WorkbookSettings();
wbSettings.setLocale(new Locale("en", "EN"));
WritableWorkbook workbook = Workbook.createWorkbook(file, wbSettings);
workbook.createSheet("First", 0);
WritableSheet excelSheet = workbook.getSheet(0);
prepareSheet(excelSheet);
workbook.write();
workbook.close();
}
public static void main(String[] args) throws WriteException, IOException {
WriteExcel test = new WriteExcel();
test.setOutputFile("c:/Users/H/Desktop/test.xls");
test.write();
}
}
I understand that I need another class that would let me access the file and add some data to it:
class Modify {
private static Logger logger = Logger.getLogger(Modify.class);
private File inputWorkbook;
private File outputWorkbook;
public Modify(String input, String output) {
inputWorkbook = new File(input);
outputWorkbook = new File(output);
logger.info("Input file: " + input);
logger.info("Output file: " + output);
}
public void readWrite() throws IOException, BiffException, WriteException {
logger.info("Reading...");
Workbook w1 = Workbook.getWorkbook(inputWorkbook);
logger.info("Copying...");
WritableWorkbook w2 = Workbook.createWorkbook(outputWorkbook, w1);
if (inputWorkbook.getName().equals("test.xls")) {
modify(w2);
}
w2.write();
w2.close();
logger.info("Done");
}
private void modify(WritableWorkbook w) throws WriteException {
logger.info("Modifying...");
WritableSheet sheet = w.getSheet("First");
//createContent(sheet); // contains methods responsible for adding data, for example:
addNumber(sheet, cols, rows, 2);
private static void addNumber(WritableSheet sheet, int column, int row, double d) throws WriteException, RowsExceededException {
Number number;
number = new Number(column, row, d, timesStandard);
sheet.addCell(number);
}
}
But I end up with a blank Excel file with the merged cells only.
How do I introduce the modifications?
Since you're manipulating a WritableWorkbook object which is not a member of your class for w2, shouldn't you have your modify() method not be void but instead return a WritableWorkbook ?
As I see it, a new one is instanciated when you call modify() but all changes at the end are dropped due to scope.
In the end you'll get something like
private WritableWorkbook modify(WritableWorkbook w) throws WriteException {
logger.info("Modifying...");
WritableSheet sheet = w.getSheet("First");
//createContent(sheet); // contains methods responsible for adding data, for example:
addNumber(sheet, cols, rows, 2);
return sheet;
}
quite basically. And a similar modification for addNumber seems in order too.
Then the respective calls would be sheet = addNumber(sheet, cols, rows, 2); and w2 = modify(w2);