How to create multi page table of content using itext in java - itext

I am using example MergeWithToc2.java to create the TOC.
I have tried couple of things to resolve the issue but didn't succeed.
public class MergeWithToc2 {
public static final String SRC1 = "PositionPdf.pdf";
public static final String SRC2 = "concatenated1.pdf";
public static final String SRC3 = "new_page.pdf";
public static final String DEST = "test/merge_with_toc2.pdf";
public Map<String, PdfReader> filesToMerge;
public static void main(String[] args) throws IOException, DocumentException {
File file = new File(DEST);
file.getParentFile().mkdirs();
MergeWithToc2 app = new MergeWithToc2();
app.createPdf(DEST);
}
public MergeWithToc2() throws IOException {
filesToMerge = new TreeMap<String, PdfReader>();
for(int i=0 ; i <50 ; i++ ){
filesToMerge.put(i + "Hello World", new PdfReader(SRC1));
//filesToMerge.put("02 Movies / Countries", new PdfReader(SRC2));
}
}
public void createPdf(String filename) throws IOException, DocumentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Map<Integer, String> toc = new TreeMap<Integer, String>();
Document document = new Document();
PdfCopy copy = new PdfCopy(document, baos);
PageStamp stamp;
document.open();
int n;
int pageNo = 0;
PdfImportedPage page;
Chunk chunk;
for (Map.Entry<String, PdfReader> entry : filesToMerge.entrySet()) {
n = entry.getValue().getNumberOfPages();
toc.put(pageNo + 1, entry.getKey());
for (int i = 0; i < n; ) {
pageNo++;
page = copy.getImportedPage(entry.getValue(), ++i);
stamp = copy.createPageStamp(page);
chunk = new Chunk(String.format("Page %d", pageNo));
if (i == 1)
chunk.setLocalDestination("p" + pageNo);
ColumnText.showTextAligned(stamp.getUnderContent(),
Element.ALIGN_RIGHT, new Phrase(chunk),
559, 810, 0);
stamp.alterContents();
copy.addPage(page);
}
}
PdfReader reader = new PdfReader(SRC3);
page = copy.getImportedPage(reader, 1);
stamp = copy.createPageStamp(page);
Paragraph p;
PdfAction action;
PdfAnnotation link;
float y = 770;
ColumnText ct = new ColumnText(stamp.getOverContent());
ct.setSimpleColumn(36, 36, 559, y);
for (Map.Entry<Integer, String> entry : toc.entrySet()) {
p = new Paragraph(entry.getValue());
p.add(new Chunk(new DottedLineSeparator()));
p.add(String.valueOf(entry.getKey()));
ct.addElement(p);
ct.go();
action = PdfAction.gotoLocalPage("p" + entry.getKey(), false);
link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
stamp.addAnnotation(link);
y = ct.getYLine();
}
ct.go();
stamp.alterContents();
copy.addPage(page);
document.close();
for (PdfReader r : filesToMerge.values()) {
r.close();
}
reader.close();
reader = new PdfReader(baos.toByteArray());
n = reader.getNumberOfPages();
reader.selectPages(String.format("%d, 1-%d", n, n-1));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(filename));
stamper.close();
}
}

Related

Integrate Signed Hash into original PDF

I am integrating a signed hash in an original PDF, and I still have an error on the validity of the signature. it's say that a pdf has been changed after signing.
below the steps: I calculate the hash then I send it for signature and finally I get the hash sign and I proceed to the integration in the original pdf
package com.example.hashdocument;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;
import com.lexpersona.commons.utils.ProcessLauncher;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;
public class Test2 {
private static final String SRC = "B:/Hash-et-Reconstitution/tmp/Doc_test.pdf";
private static final String DST = "B:/Hash-et-Reconstitution/tmp/Doc_test_DST.pdf";
private static final String HASH = "B:/Hash-et-Reconstitution/tmp/Doc_test_hashed.hash";
private static final String PATH_BAT = "C:/Repo_LP7/lpcommand.bat";
private static final String PIN = "123456";
private static final String CERTIFICATE = "C:/lp7command/tools/certificate.p12";
private static final String SIGNED_HASH = "B:/Hash-et-Reconstitution/tmp/doc_signed.hash";
private static byte[] readFileToByteArray(File file){
FileInputStream fis = null;
byte[] bArray = new byte[(int) file.length()];
try{
fis = new FileInputStream(file);
fis.read(bArray);
fis.close();
}catch(IOException ioExp){
ioExp.printStackTrace();
}
return bArray;
}
public static File bytesToFile(byte[] fileByte,String pathFile) {
File file = new File(pathFile);
try {
OutputStream os = new FileOutputStream(file);
os.write(fileByte);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
public static byte[] signDocument() throws IOException {
ProcessLauncher p = new ProcessLauncher(System.out, System.err);
int exec;
exec = p.exec("cmd.exe /c "+PATH_BAT+" <nul "+ SIGNED_HASH +" "+ PIN+" "
+ HASH+" "+CERTIFICATE, null, null);
byte[] signedHash = readFileToByteArray(new File(SIGNED_HASH));
return signedHash;
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
PdfSignatureAppearance appearance = null;
ByteArrayOutputStream os = null;
String hash_document = "";
InputStream data = null;
int contentEstimated = 8192;
PdfReader reader = new PdfReader(SRC);
reader.unethicalreading = true;
reader.setAppendable(true);
int pdfPagenumber = 1;
pdfPagenumber = reader.getNumberOfPages(); // Sign on last page
os = new ByteArrayOutputStream ();
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
Calendar cal = Calendar.getInstance();
appearance = stamper.getSignatureAppearance();
appearance.setSignDate(cal);
//appearance.setAcro6Layers(false);
appearance.setReason("Signature de contrat");
appearance.setLocation("MAROC");
appearance.setImage(null);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
Rectangle rect = new Rectangle(300, 300, 20, 20);
appearance.setVisibleSignature(rect, pdfPagenumber, null);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(appearance.getReason());
dic.setLocation(appearance.getLocation());
dic.setContact(appearance.getContact());
dic.setDate(new PdfDate(appearance.getSignDate()));
appearance.setCryptoDictionary(dic);
appearance.preClose(exc);
data = appearance.getRangeStream();
MessageDigest messageDigest;
String provider = null;
String hashAlgorithm = DigestAlgorithms.SHA256;
if (provider == null){
messageDigest = MessageDigest.getInstance(hashAlgorithm);
}else {
messageDigest = MessageDigest.getInstance(hashAlgorithm,provider);
}
int read = 0;
byte[] buff = new byte[contentEstimated];
while ((read = data.read(buff, 0, contentEstimated)) > 0)
{
messageDigest.update(buff,0,read);
}
byte[] hashDigest = messageDigest.digest();
byte[] documentHash = org.bouncycastle.util.encoders.Hex.encode(hashDigest);
//eSign Start
hash_document = new String(documentHash, "UTF-8");
System.out.println("Document Hash :"+hash_document);
PrintStream out = new PrintStream(new FileOutputStream(HASH));
out.print(hash_document);
byte[] hashdocumentByte = signDocument();
//////////////////// ADD SIGNED BYTES/HASH TO PDF DOCUMENT.
int contentEstimated2 = 8192;
byte[] paddedSig = new byte[contentEstimated2];
byte[] signedDocByte = hashdocumentByte;
System.arraycopy(signedDocByte, 0, paddedSig, 0, signedDocByte.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
appearance.close(dic2);
try(OutputStream outputStream = new FileOutputStream(DST)) {
os.writeTo(outputStream);
}
os.close();
}
}
what do you think abous this code : First i calculate the hash and send to server A for signature
PdfReader reader = new PdfReader(SRC);
FileOutputStream os = new FileOutputStream(TEMP);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
//appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new
ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
System.out.println("hash to sign : "+ hash);
bytesToFile(hash, HASH);
byte[] hashdocumentByte = TEST.signed_hash(hash);
PdfReader reader2 = new PdfReader(TEMP);
FileOutputStream os2 = new FileOutputStream(DEST);
ExternalSignatureContainer external2 = new
MyExternalSignatureContainer(hashdocumentByte,null);
MakeSignature.signDeferred(reader2, "sig", os2, external2);
And in the server B where i sign the hash :
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
// we load our private key from the key store
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(CERTIFICATE), PIN);
String alias = (String)ks.aliases().nextElement();
Certificate[] chain = ks.getCertificateChain(alias);
PrivateKey pk = (PrivateKey) ks.getKey(alias, PIN);
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", null);
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.sign(sh);
System.out.println(signature.getEncryptionAlgorithm());
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
Your signDocument method apparently does not accept a pre-calculated hash value but seems to calculate the hash of the data you give it, in your case the (lower case) hex presentation of the hash value you already calculated.
In your first example document you have these values (all hashes are SHA256 hashes):
Hash of the byte ranges to sign:
91A9F5EBC4F2ECEC819898824E00ECD9194C3E85E4410A3EFCF5193ED7739119
Hash of "91a9f5ebc4f2ecec819898824e00ecd9194c3e85e4410a3efcf5193ed7739119".getBytes():
2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
Hash value signed by the embedded signature container:
2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
And in your first example document you have these values (all hashes also are SHA256 hashes):
Hash of the byte ranges to sign:
79793C58489EB94A17C365445622B7F7945972A5A0BC4C93B6444BEDFFA5A5BB
Hash of "79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb".getBytes():
A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
Hash value signed by the embedded signature container:
A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
Thus, you have to correct your signDocument method to interpret the data correctly, or you have to give it a byte array containing the whole range stream to digest.

How I can make dynamic header column and dynamic data to export to Excel/CSV/PDF using MongoDB, Spring Boot, and apache poi

I want to make export function using Spring Boot, I have data on MongoDB NoSQL, and then want to export my document on MongoDB Dynamically using Apache POI ( If any better dependency you can recommend to me).
I don't want to declare header column, entity model, etc., I want to export data dynamically as shown as in my Document database, any one can give me an example for it?
Please try these code may be help for you.
->add Gson Depandencies in porm.xml
Controller code
MasterController.java
#Autowired
MasterServiceImpl masterServiceImpl;
#GetMapping(value="/dynamicfile/{flag}/{fileType}/{fileName}")
public ResponseEntity<InputStreamResource> downloadsFiles(#PathVariable("flag") int flag,#PathVariable("fileType") String fileType,#PathVariable("fileName") String fileName) throws IOException{
List<?> objects=new ArrayList<>();
if(flag==1) {
objects=masterServiceImpl.getData();
}
ByteArrayInputStream in = masterServiceImpl.downloadsFiles(objects,fileType);
HttpHeaders headers = new HttpHeaders();
if(fileType.equals("Excel")) {
headers.add("Content-Disposition", "attachment; filename="+fileName+".xlsx");
}else if(fileType.equals("Pdf")){
headers.add("Content-Disposition", "attachment; filename="+fileName+".pdf");
}else if(fileType.equals("Csv")) {
headers.add("Content-Disposition", "attachment; filename="+fileName+".csv");
}
return ResponseEntity.ok().headers(headers).body(new InputStreamResource(in));
}
Service code :
MasterServiceImpl.java
public static List<HashMap<Object, Object>> getListOfObjectToListOfHashMap(List<?> objects) {
List<HashMap<Object,Object>> list=new ArrayList<>();
for(int i=0;i<objects.size();i++) {
HashMap<Object,Object> map=new HashMap<>();
String temp=new Gson().toJson(objects.get(i)).toString();
String temo1= temp.substring(1, temp.length()-1);
String[] temp2=temo1.split(",");
for(int j=-1;j<temp2.length;j++) {
if(j==-1) {
map.put("SrNo",i+1);
}else {
String tempKey=temp2[j].toString().split(":")[0].toString();
String tempValue=temp2[j].toString().split(":")[1].toString();
char ch=tempValue.charAt(0);
if(ch=='"') {
map.put(tempKey.substring(1, tempKey.length()-1), tempValue.substring(1, tempValue.length()-1));
}else {
map.put(tempKey.substring(1, tempKey.length()-1), tempValue);
}
}
}
list.add(map);
}
return list;
}
public static ByteArrayInputStream downloadsFiles(List<?> objects,String fileType) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
List<HashMap<Object, Object>> list = getListOfObjectToListOfHashMap(objects);
String[] COLUMNs = getColumnsNameFromListOfObject(objects);
try{
if(fileType.equals("Excel")) {
generateExcel(list, COLUMNs,out);
}else if(fileType.equals("Pdf")) {
generatePdf(list, COLUMNs,out);
}else if(fileType.equals("Csv")) {
generatePdf(list, COLUMNs,out);
}
}catch(Exception ex) {
System.out.println("Error occurred:"+ ex);
}
return new ByteArrayInputStream(out.toByteArray());
}
public static final String[] getColumnsNameFromListOfObject(List<?> objects) {
String strObjects=new Gson().toJson(objects.get(0)).toString();
String[] setHeader= strObjects.substring(1, strObjects.length()-1).split(",");
String header="SrNo";
for(int i=0;i<setHeader.length;i++) {
String str=setHeader[i].toString().split(":")[0].toString();
header=header+","+str.substring(1, str.length()-1);
}
return header.split(",");
}
public static final void generateExcel(List<HashMap<Object, Object>> list, String[] COLUMNs,ByteArrayOutputStream out) throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Excelshit");
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setColor(IndexedColors.BLUE.getIndex());
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
Row headerRow = sheet.createRow(0);
for (int col = 0; col < COLUMNs.length; col++) {
Cell cell = headerRow.createCell(col);
cell.setCellValue(COLUMNs[col]);
cell.setCellStyle(headerCellStyle);
}
int rowIdx = 1;
for(int k = 0; k < list.size(); k++){
Row row =sheet.createRow(rowIdx++);
for (Map.Entry<Object, Object> entry : list.get(k).entrySet()){
Object key = entry.getKey();
Object value = entry.getValue();
for (int col = 0; col < COLUMNs.length; col++) {
if(key.toString().equals(COLUMNs[col].toString())) {
row.createCell(col).setCellValue(value.toString());
}
}
}
}
workbook.write(out);
System.out.println(workbook);
}
private static final void generatePdf(List<HashMap<Object, Object>> list, String[] COLUMNs,ByteArrayOutputStream out) throws DocumentException {
Document document = new Document();
com.itextpdf.text.Font headerFont =FontFactory.getFont(FontFactory.HELVETICA_BOLD,8);
com.itextpdf.text.Font dataFont =FontFactory.getFont(FontFactory.TIMES_ROMAN,8);
PdfPCell hcell=null;
PdfPTable table = new PdfPTable(COLUMNs.length);
for (int col = 0; col < COLUMNs.length; col++) {
hcell = new PdfPCell(new Phrase(COLUMNs[col], headerFont));
hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(hcell);
}
for(int index = 0; index < list.size(); index++){
PdfPCell cell = null;
for (Map.Entry<Object, Object> entry : list.get(index).entrySet()){
Object key = entry.getKey();
Object value = entry.getValue();
for (int col = 0; col < COLUMNs.length; col++) {
if(key.toString().equals(COLUMNs[col].toString())) {
cell = new PdfPCell(new Phrase(value.toString(),dataFont));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
}
}
table.addCell(cell);
}
}
PdfWriter.getInstance(document, out);
document.open();
document.add(table);
document.close();
}
public List<TblDepartment> getData() {
List<TblDepartment> list = new ArrayList<>();
departmentRepository.findAll().forEach(list::add);
return list;
}

iTextSharp 5 generated PDF-Document AdobeReader-compatibility [duplicate]

This question already has answers here:
iTextSharp-generated PDFs now cause Save dialog in Adobe Reader X
(2 answers)
Closed 5 years ago.
I am generating some reports with iTextSharp 5.
Opening the generated .PDF-file, everything looks and actually is fine with most PDF-readers.
When I open the PDF using AdobeReader(DC) however, it asks me if i want to save the changes on close. Although I didn't change anything.
Hitting 'Cancel' sure makes the message window go away, but hitting save causes the file to actually shrinks in size.
Now what is happening there? And why? How can I disable it?
The users of the application are most likely gonna use AdobeReader as well.
I don't want them to see the save dialog anytime they open a report.
Here is my BaseReport class
public abstract class BaseReport : PdfPageEventHelper
{
protected const string SPACE = " ";
protected const string COLON = ":";
protected static string NEWLINE = Environment.NewLine;
protected Document document;
protected PdfTemplate footerTemplate;
protected PdfContentByte contentByte;
protected PdfWriter writer;
private PdfTemplate totalPageNoTemplate;
private int lastPageNumber;
// properties for header
private bool done;
// needs to be overriden in subclass order to use header feature
protected string kundeHeader { get; set; }
// font definitions
protected BaseFont baseFont;
protected Font fontFooter;
protected Font fontGeneralText;
protected Font fontLabelText;
protected Font fontBoldLabelText;
protected Font fontBoldText;
protected Font fontSpace;
protected Font fontLargeBoldText;
protected int language;
protected bool useLogo = false;
protected bool usePageNumbers = false;
protected bool usePrintDate = false;
protected const string PRINT_FULLDATE_FORMAT = "dd.MM.yyyy HH:mm";
protected const string PRINT_DATE_ONLY_FORMAT = "dd.MM.yyyy";
protected Rectangle pagesize = PageSize.A4;
protected float marginLeft = 80;
protected float marginRight = 35;
protected float marginTop = 40;
protected float marginBottom = 40;
private MemoryStream PDFStream { get; set; } = new MemoryStream();
private DateTime printDate;
public BaseReport(int language = Languages.DE, bool landscape = false)
{
this.language = language;
if (landscape)
{
pagesize = pagesize.Rotate();
}
}
public byte[] GenerateReport()
{
CultureInfo cultureBefore = Resources.Culture;
try
{
Resources.Culture = SelectCultureForLangauge();
PrepareReport();
document = new Document(pagesize, marginLeft, marginRight, marginTop, marginBottom);
BuildFonts();
OpenDocument();
PrepareDocument();
GenerateContent();
document.Close();
return PDFStream.GetBuffer();
} finally
{
Resources.Culture = cultureBefore;
}
}
public void GenerateReport(string filename)
{
byte[] report = GenerateReport();
using (FileStream f = new FileStream(filename, FileMode.Create))
{
f.Write(report, 0, report.Length);
}
}
protected CultureInfo SelectCultureForLangauge()
{
string languageCode = GetLanguageCode();
return CultureInfo.GetCultureInfo(languageCode);
}
protected string GetLanguageCode()
{
string languageCode = string.Empty;
switch (language)
{
case Languages.FR: languageCode = "FR"; break;
case Languages.IT: languageCode = "IT"; break;
case Languages.EN: languageCode = "EN"; break;
default: languageCode = "DE"; break;
}
return languageCode;
}
protected virtual void PrepareReport() { }
protected virtual void PrepareDocument() { }
protected abstract void GenerateContent();
private void BuildFonts()
{
baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
fontFooter = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.ITALIC, BaseColor.DARK_GRAY);
fontGeneralText = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.NORMAL, BaseColor.BLACK);
fontLabelText = FontFactory.GetFont(FontFactory.HELVETICA, 8.5f, Font.NORMAL, BaseColor.BLACK);
fontBoldLabelText = FontFactory.GetFont(FontFactory.HELVETICA, 8.5f, Font.BOLD, BaseColor.BLACK);
fontBoldText = FontFactory.GetFont(FontFactory.HELVETICA, 11, Font.BOLD, BaseColor.BLACK);
fontSpace = FontFactory.GetFont(FontFactory.HELVETICA, 3.5f, Font.NORMAL, BaseColor.BLACK);
fontLargeBoldText = FontFactory.GetFont(FontFactory.HELVETICA, 17, Font.BOLD, BaseColor.BLACK);
GetFontIfAvailable();
}
private void GetFontIfAvailable()
{
string fileName = "IF_Rg";
try
{
baseFont = LoadFontFromFile(fileName, true);
fontFooter = new Font(baseFont, 11, Font.ITALIC, BaseColor.DARK_GRAY);
fontGeneralText = new Font(baseFont, 11, Font.NORMAL, BaseColor.BLACK);
fontLabelText = new Font(baseFont, 8.5f, Font.NORMAL, BaseColor.BLACK);
fontBoldLabelText = new Font(baseFont, 8.5f, Font.BOLD, BaseColor.BLACK);
fontBoldText = new Font(baseFont, 11, Font.BOLD, BaseColor.BLACK);
fontSpace = new Font(baseFont, 3.5f, Font.NORMAL, BaseColor.BLACK);
fontLargeBoldText = new Font(baseFont, 17, Font.BOLD, BaseColor.BLACK);
} catch (FileNotFoundException)
{
LogWrapper.Warn("Font not found - using default.");
}
}
protected BaseFont LoadFontFromFile(string fileName, bool embedded)
{
string fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\" + fileName + ".ttf";
if (File.Exists(fontPath))
{
return BaseFont.CreateFont(fontPath, BaseFont.WINANSI, embedded);
}
else
{
throw new FileNotFoundException($"Fontfile {fileName} was not found!");
}
}
protected Image HeaderLogo()
{
Image logo = Image.GetInstance(Resources.logo, BaseColor.BLACK);
// TODO msc pick logo from debitor
logo.ScaleToFit(100f, 100f);
return logo;
}
protected void OpenDocument()
{
writer = PdfWriter.GetInstance(document, PDFStream);
writer.PageEvent = this;
writer.SetFullCompression();
document.Open();
contentByte = writer.DirectContent;
}
protected void AddLabelAt(string label, float posX, float posY)
{
PdfContentByte cb = writer.DirectContent;
ColumnText column = new ColumnText(cb);
column.SetText(new Paragraph(label + NEWLINE, fontLabelText));
column.SetSimpleColumn(posX, 20, posX + 200, posY);
column.Go();
}
protected void AddLabelOnMargin(string label)
{
AddLabelAt(label, document.LeftMargin - 40, writer.GetVerticalPosition(false));
}
protected Phrase ParaLine(string Text, Font textfont)
{
return new Phrase(Text, textfont);
}
public override void OnOpenDocument(PdfWriter writer, Document document)
{
if (usePageNumbers)
{
totalPageNoTemplate = writer.DirectContentUnder.CreateTemplate(50, 50);
}
if (usePrintDate)
{
printDate = DateTime.Now;
}
}
public override void OnStartPage(PdfWriter writer, Document document)
{
if (useLogo || (document.PageNumber > 1 && !string.IsNullOrEmpty(kundeHeader)))
{
PdfContentByte canvas = writer.DirectContentUnder;
canvas.SaveState();
if (document.PageNumber > 1 && !string.IsNullOrEmpty(kundeHeader))
{
//showtextaligned only shows a single line
//therefor the header needs to be split and its parts need to be added seperately
string[] headerParts = kundeHeader.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
Phrase header = new Phrase(kundeHeader, fontLabelText);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(headerParts[0], fontLabelText),
document.LeftMargin,
document.Top + 30, 0);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(headerParts[1], fontLabelText),
document.LeftMargin,
document.Top + 20, 0);
}
if (useLogo)
{
Image logo = HeaderLogo();
logo.SetAbsolutePosition(marginLeft - 17.5f, document.Top + document.TopMargin - 50);
document.Add(logo);
}
canvas.RestoreState();
}
}
public override void OnEndPage(PdfWriter writer, Document document)
{
if (usePageNumbers || usePrintDate)
{
PdfContentByte canvas = writer.DirectContentUnder;
canvas.SaveState();
if (usePageNumbers)
{
// adds current page number to the footer section of the document
int pageN = writer.PageNumber;
string text = Resources.LabelSeite + SPACE + pageN + "/";
float len = fontLabelText.BaseFont.GetWidthPoint(text, fontLabelText.Size);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT,
ParaLine(text, fontLabelText),
document.LeftMargin,
document.Bottom - 10, 0);
// adds template to fill in total page number (see OnCloseDocument method)
canvas.AddTemplate(totalPageNoTemplate, document.LeftMargin + len, document.Bottom - 10);
lastPageNumber = pageN;
}
if (usePrintDate)
{
// adds the printdate to the footer secdtion of the document
string dateFormatted = printDate.ToString(PRINT_FULLDATE_FORMAT);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_RIGHT,
ParaLine(dateFormatted, fontLabelText),
document.Right,
document.Bottom - 10, 0);
}
canvas.RestoreState();
}
}
public override void OnCloseDocument(PdfWriter writer, Document document)
{
if (usePageNumbers)
{
// fills in the total page number to the prepared template in the footer section of the document
string text = lastPageNumber + "";
float widthPoint = fontLabelText.BaseFont.GetWidthPoint(text, fontLabelText.Size);
totalPageNoTemplate.Width = widthPoint;
ColumnText.ShowTextAligned(totalPageNoTemplate, Element.ALIGN_LEFT, ParaLine(text, fontLabelText), 0, 0, 0);
}
}
iTextSharp-generated PDFs now cause Save dialog in Adobe Reader X
I had to switch PDFStream.GetBuffer() with PDFStream.ToArray(); problem solved.

Create PDF with iText on iSeries leads to error "The document has no pages."

We use the nice library iText for one of my customer's project to generate a pdf from a string representing a html page. The iText version is 5.5.10.
The following piece of code works well on the development environments and servers running on Windows, but it is not working on the customer's server running on iSeries.
public class GeneratePDFCmdImpl extends ControllerCommandImpl implements
GeneratePDFCmd {
private String charsetStr = null;
private Charset charset = null;
private BaseFont bf = null;
private String destFile = null;
private String destFilename = null;
private String srcContent = null;
private String docName = null;
public void setDocName(String docname) {
this.docName = docname;
}
public void setSrcContent(String srcContent) {
this.srcContent = srcContent;
}
private void prepareDefaultsAndSettings() {
/* srcContent may be more complex html but even this simple one is not working */
srcContent = "<html><head></head><body>This is just a test</body></html>";
docName = "mypdf";
charsetStr = "UTF-8";
destFilename = docName+".pdf";
Date timestamp = new Date();
/* destFile = "/" is just for the sample. In my real project, the value is a folder where my app has full rights
*/
destFile = "/" + destFilename;
charset = Charset.forName(charsetStr);
FontFactory.register("/fonts/arial.ttf","Arial");
bf = FontFactory.getFont("Arial").getBaseFont();
}
#Override
public void performExecute() throws ECException {
super.performExecute();
Document document = null;
OutputStream os = null;
prepareDefaultsAndSettings();
try {
InputStream srcInputStream;
srcInputStream = new ByteArrayInputStream(srcContent.getBytes(charset));
document = new Document(PageSize.A4, 20, 20, 75, 80);
FileOutputStream destOutput = new FileOutputStream(destFile);
PdfWriter writer = PdfWriter.getInstance(document,destOutput);
writer.setPageEvent( new HeaderFooterPageEvent(bf));
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document, srcInputStream, charset);
document.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
if(document != null) {
document.close();
}
document = null;
try {
if (os != null) {
os.close();
}
} catch(IOException e) {
e.printStackTrace();
}
os = null;
}
}
private class HeaderFooterPageEvent extends PdfPageEventHelper {
PdfContentByte cb;
PdfTemplate template;
BaseFont bf;
Font f;
float fs;
public HeaderFooterPageEvent(BaseFont _bf) {
super();
bf = _bf;
f = new Font(bf);
}
#Override
public void onOpenDocument(PdfWriter writer, Document document) {
cb = writer.getDirectContent();
template = cb.createTemplate(50, 50);
}
#Override
public void onEndPage(PdfWriter writer, Document document) {
Date dat = new Date();
ColumnText ct = new ColumnText(writer.getDirectContent());
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
ct.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER, new Phrase(sdf.format(dat) ), 100, 30, 0);
String text = "Page " +writer.getPageNumber() + " to ";
float len = bf.getWidthPoint(text, 12);
cb.beginText();
cb.setFontAndSize(bf, 12);
cb.setTextMatrix(450, 30);
cb.showText(text);
cb.endText();
cb.addTemplate(template, 450 + len, 30);
}
#Override
public void onCloseDocument(PdfWriter writer, Document document) {
template.beginText();
template.setFontAndSize(bf, 12);
template.showText(String.valueOf(writer.getPageNumber()));
template.endText();
}
}
}
When executed on the iSeries, we have the error message
com.ibm.commerce.command.ECCommandTarget executeCommand CMN0420E: The following command exception has occurred during processing: "ExceptionConverter: java.io.IOException: The document has no pages.". ExceptionConverter: java.io.IOException: The document has no pages.
at com.itextpdf.text.pdf.PdfPages.writePageTree(PdfPages.java:112)
at com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1256)
at com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:900)
at com.itextpdf.text.Document.close(Document.java:415)
at be.ourcustomer.package.GeneratePDFCmdImpl.performExecute(GeneratePDFCmdImpl.java:107)
I don't have much idea about what we do wrong. Any help would be greatly appreciated

How do I merge two PDF files with attachments using itext?

I am trying to merge two pdf files (file1.pdf and file2.pdf) into a single file file3.pdf. One of the source files, file2.pdf has few attachments.
Using PdfCopyFields addDocument method does not include the attachments in the source pdf files to the destination pdf file. How do I achieve this?
Extracting the document level attachments from source files using PdfDictionary and adding them to the destination file using PdfWriter addFileAttachment method works.
Can you please let me know if there is any other efficient method to include the attachments from source pdf files to be included in destination pdf file after merging?
This is the sample code that I am using to replicate the scenario.
public class TestItext
{
public String[] attachments;
public TestItext()
{
attachments = new String[2];
}
public static void main(String[] args)
{
try
{
TestItext obj = new TestItext();
obj.extractDocLevelAttachments("C:\\source.pdf");
obj.addAttachments("C:\\source.pdf","C:\\temp\\dest.pdf");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void extractDocLevelAttachments(String filename) throws IOException
{
PdfReader reader = new PdfReader(filename);
PdfDictionary root = reader.getCatalog();
PdfDictionary documentnames = root.getAsDict(PdfName.NAMES);
PdfDictionary embeddedfiles = documentnames.getAsDict(PdfName.EMBEDDEDFILES);
PdfArray filespecs = embeddedfiles.getAsArray(PdfName.NAMES);
PdfDictionary filespec;
PdfDictionary refs;
FileOutputStream fos;
PRStream stream;
int count = 0;
for (int i = 0; i < filespecs.size(); ) {
filespecs.getAsString(i++);
filespec = filespecs.getAsDict(i++);
refs = filespec.getAsDict(PdfName.EF);
for (Object key : refs.getKeys()) {
fos = new FileOutputStream(String.format("C:\\temp\\"+ filespec.getAsString((PdfName)key).toString()));
attachments[count++] = String.format("C:\\temp\\"+ filespec.getAsString((PdfName)key).toString());
stream = (PRStream) PdfReader.getPdfObject(refs.getAsIndirectObject((PdfName)key));
fos.write(PdfReader.getStreamBytes(stream));
fos.flush();
fos.close();
}
}
reader.close();
}
public void addAttachments(String src, String dest) throws IOException, DocumentException
{
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
for (int i = 0; i < attachments.length; i++) {
addAttachment(stamper.getWriter(), new File(attachments[i]));
}
stamper.close();
}
protected void addAttachment(PdfWriter writer, File src) throws IOException {
PdfFileSpecification fs =
PdfFileSpecification.fileEmbedded(writer, src.getAbsolutePath(), src.getName(), null);
writer.addFileAttachment(src.getName().substring(0, src.getName().indexOf('.')), fs);
}
}