I state that I use NetBeans 8.2. I need to transfer a jframe (which represents an invoice) on a paragraph of IText. Everything works and is displayed. However, I get that the writings and details of the pdf I created are not well defined and displayed.
For example, the strings seem to have a shaded effect so that instead of being only black, they have gray shades. It is particularly annoying when I print: the smaller text is not readable. The same effect does not occur in the video display.
I tried modifying the jframe size and scaling the graphic2d instance. Then I returned to normal size and I modified the scale of the paragraph and so I got a result a bit 'better but not satisfactory.
Any suggestions?
Edit: this is the code of the method that manages the creation of the paragraph:
private Paragraph creaParPdf(float scaleFactorW, float scaleFactorH) throws BadElementException, IOException {
BufferedImage img = new BufferedImage(fatt.getWidth(), fatt.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D img2D = img.createGraphics();
img2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
fatt.paint(img2D);
Paragraph p = new Paragraph();
com.itextpdf.text.Image itextImg =
com.itextpdf.text.Image.getInstance(img, Color.white, false);
itextImg.scaleAbsolute(PageSize.A4.getWidth()*scaleFactorW, PageSize.A4.getHeight()*scaleFactorH);
p.add(itextImg);
return p;
}
And this is the code of the method that manages the creation of the pdf:
public void printPDF() throws FileNotFoundException, DocumentException, SQLException, ClassNotFoundException, IOException{
fatt = this;
Document d = new Document(PageSize.A4,10,10,10,10);
d.setMargins(10, 10, 0, 10);
String salvPath = "C:\\"+cliente+".pdf";
filePDF = new File(salvPath);
filePDF.getParentFile().mkdirs();
if (filePDF.exists())
out.println("Il file " + salvPath + " esiste");
else try {
if (filePDF.createNewFile())
out.println("Il file " + salvPath + " è stato creato");
else
out.println("Il file " + salvPath + " non può essere creato");
} catch (IOException ex) {
getLogger(JFrameStart.class.getName()).log(SEVERE, null, ex);
}
FileOutputStream fs = new FileOutputStream (salvPath);
PdfWriter writer = PdfWriter.getInstance(d, fs);
writer.setFullCompression();
d.open ();
try {
float scaleFactorW = 0.98f;
float scaleFactorH = 0.98f;
float offset = 0.0f;
p = creaParPdf(scaleFactorW,scaleFactorH);
} catch (BadElementException ex) {
Logger.getLogger(JFrameTracc.class.getName()).log(Level.SEVERE, null, ex);
}
d.add(p);
d.close();
}
This is the final result, by printing the pdf you can see how the smaller parts are practically illegible:
enter image description here
Related
I used the following method to convert a pdf into multiple png images:
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.imgscalr.Scalr;
public class ImgUtil {
public static List<String> convertPDFPagesToImages(String sourceFilePath, String desFilePath){
List<String> urlList = new ArrayList<>();
try {
File sourceFile = new File(sourceFilePath);
File destinationFile = new File(desFilePath);
if (!destinationFile.exists()) {
destinationFile.mkdir();
log.info("Folder Created ->:{} ", destinationFile.getAbsolutePath());
}
if (sourceFile.exists()) {
log.info("Images copied to Folder Location: ", destinationFile.getAbsolutePath());
PDDocument document = PDDocument.load(sourceFile);
PDFRenderer pdfRenderer = new PDFRenderer(document);
int numberOfPages = document.getNumberOfPages();
log.info("Total files to be converting ->{} ", numberOfPages);
String fileName = sourceFile.getName().replace(".pdf", "");
String fileExtension = "png";
/*
* 600 dpi give good image clarity but size of each image is 2x times of 300 dpi.
* Ex: 1. For 300dpi 04-Request-Headers_2.png expected size is 797 KB
* 2. For 600dpi 04-Request-Headers_2.png expected size is 2.42 MB
*/
int dpi = 300;// use less dpi for to save more space in harddisk. For professional usage you can use more than 300dpi
for (int i = 0; i < numberOfPages; ++i) {
File outPutFile = new File(desFilePath + fileName +"_"+ (i+1) +"."+ fileExtension);
BufferedImage bImage = pdfRenderer.renderImageWithDPI(i, dpi, ImageType.RGB);
ImageIO.write(bImage, fileExtension, outPutFile);
urlList.add(outPutFile.getPath().replaceAll("\\\\", "/"));
}
document.close();
log.info("Converted Images are saved at ->{} ", destinationFile.getAbsolutePath());
} else {
log.error(sourceFile.getName() +" File not exists");
}
} catch (Exception e) {
e.printStackTrace();
}
return urlList;
}
public static void main(String[] args) {
convertPDFPagesToImages("D:\\tmp\\report\\pdfPath\\61199020100754118.pdf", "D:\\tmp\\report\\pdfPath\\");
}
}
But I found that when the number of pdf pages is relatively large, the image conversion is slower. I consider using multithreading to parse the images. Is it possible to convert a pdf into a picture through multiple threads or is there a similar method?
A simple way to speed up this conversion would be to split image writing to a background thread. Set up an executorService before opening the PDF:
ExecutorService exec = Executors.newFixedThreadPool(1);
List<Future<?>> pending = new ArrayList<>();
Instead of writing the image in same calling thread, just submit a new task to the service:
// ImageIO.write(bImage, fileExtension, outPutFile);
pending.add(exec.submit(() -> write(bImage, fileExtension, outImage.toFile())));
And function to perform the task:
private static void write(BufferedImage image, String fileExtension, File file) {
try {
ImageIO.write(image, fileExtension, file);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
After closing the PDF document make sure the executor is finished:
for (Future<?> fut : pending) {
fut.get();
}
exec.shutdown();
exec.awaitTermination(365, TimeUnit.DAYS);
Using more than one thread for ImageIO.write may not benefit you as it is heavy IO operation but as I said in the comment, experiment with writing to a large ByteArrayOutputStream and then the file may also help on your specific hardware.
If I use font size appearance.setLayer2FontSize(6.0f); it sets font size for both Name and Description.
PdfReader reader = null;
PdfSigner signer = null;
try {
reader = new PdfReader(inStream);
signer = new PdfSigner(reader, pdfos, false);
} catch (IOException e) {
LOGGER.error("Error while loading PDF");
throw new DigitalSignException("Error while loading PDF", e);
}
int noOfPages = signer.getDocument().getNumberOfPages();
PdfSignatureAppearance appearance = signer.getSignatureAppearance().setReason(reason).setLocation(loc)
.setReuseAppearance(false);
Rectangle rect = new Rectangle(250, 100, 200, 80);
appearance.setRenderingMode(RenderingMode.NAME_AND_DESCRIPTION);
appearance.setLayer2FontSize(6.0f);
appearance.setPageRect(rect).setPageNumber(noOfPages);
signer.setFieldName("sign");
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, bouncyCastleProvider.getName());
IExternalDigest digest = new BouncyCastleDigest();
try {
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
} catch (IOException | GeneralSecurityException e) {
LOGGER.error("Error while adding digital signature to PDF");
throw new DigitalSignException("Error while adding digital signature to PDF", e);
}
Is there a way to set different font sizes for Name and description
(Name should be little bigger than description)
The whole Layer2Text is a single String, whether you set it or iText builds it, and it is typeset as a single paragraph using a single font and font size. Thus, NO, you cannot ask iText to draw your Layer2Text or its default text using multiple styles for different parts of it.
What you can do, though, is to retrieve the PdfFormXObject Layer2 before iText has created its appearance on it, and you can draw anything in any style on it.
So, instead of
appearance.setRenderingMode(RenderingMode.NAME_AND_DESCRIPTION);
appearance.setLayer2FontSize(6.0f);
appearance.setPageRect(rect).setPageNumber(noOfPages);
you'd do
appearance.setPageRect(rect).setPageNumber(noOfPages);
PdfFormXObject layer2 = getLayer2();
[...shape the layer2 contents as you desire...]
Of course you can use the source of the PdfSignatureAppearance method getAppearance for inspiration, in particular if you don't want your design to deviate much from the default.
Thus, YES, you can completely customize the signature appearance.
For example
An example customized layer2 content might be shaped like this:
PdfFormXObject layer2 = appearance.getLayer2();
PdfCanvas canvas = new PdfCanvas(layer2, signer.getDocument());
float MARGIN = 2;
PdfFont font = PdfFontFactory.createFont();
String name = null;
CertificateInfo.X500Name x500name = CertificateInfo.getSubjectFields((X509Certificate)chain[0]);
if (x500name != null) {
name = x500name.getField("CN");
if (name == null)
name = x500name.getField("E");
}
if (name == null)
name = "";
Rectangle dataRect = new Rectangle(rect.getWidth() / 2 + MARGIN / 2, MARGIN, rect.getWidth() / 2 - MARGIN, rect.getHeight() - 2 * MARGIN);
Rectangle signatureRect = new Rectangle(MARGIN, MARGIN, rect.getWidth() / 2 - 2 * MARGIN, rect.getHeight() - 2 * MARGIN);
try (Canvas layoutCanvas = new Canvas(canvas, signer.getDocument(), signatureRect);) {
Paragraph paragraph = new Paragraph(name).setFont(font).setMargin(0).setMultipliedLeading(0.9f).setFontSize(20);
layoutCanvas.add(paragraph);
}
try (Canvas layoutCanvas = new Canvas(canvas, signer.getDocument(), dataRect);) {
Paragraph paragraph = new Paragraph().setFont(font).setMargin(0).setMultipliedLeading(0.9f);
paragraph.add(new Text("Digitally signed by ").setFontSize(6));
paragraph.add(new Text(name + '\n').setFontSize(9));
paragraph.add(new Text("Date: " + new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z").format(signer.getSignDate().getTime()) + '\n').setFontSize(6));
paragraph.add(new Text("Reason: " + appearance.getReason() + '\n').setFontSize(6));
paragraph.add(new Text("Location: " + appearance.getLocation()).setFontSize(6));
layoutCanvas.add(paragraph);
}
This essentially is a copy&paste&refactoring of the iText code creating its default appearance with different font sizes for different text parts of it.
At the moment I'm trying to print some pdfs in java. The API used is Apache PDF Box in Version 2.0. After converting the images I write them to disk to save memory. In the next step I read them again and write the title in the head of the image. After that I write them again. To use them I read them again separately. When I read them for the last time I get the following exception every 200-300 images:
java.lang.IndexOutOfBoundsException: off < 0 || len < 0 || off+len > b.length || off+len < 0!
at javax.imageio.stream.MemoryCacheImageInputStream.read(MemoryCacheImageInputStream.java:100)
at com.sun.imageio.plugins.common.SubImageInputStream.read(SubImageInputStream.java:61)
at com.sun.imageio.plugins.common.InputStreamAdapter.read(InputStreamAdapter.java:47)
at java.io.SequenceInputStream.read(SequenceInputStream.java:207)
at java.util.zip.InflaterInputStream.fill(InflaterInputStream.java:238)
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:158)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at com.sun.imageio.plugins.png.PNGImageReader.decodePass(PNGImageReader.java:1104)
at com.sun.imageio.plugins.png.PNGImageReader.decodeImage(PNGImageReader.java:1215)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1330)
at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1606)
at javax.imageio.ImageIO.read(ImageIO.java:1448)
at javax.imageio.ImageIO.read(ImageIO.java:1400)
at my.code.Class.method()
I use the following code to convert the PDFs:
final HashMap<Integer, File> images = new HashMap<>();
PDDocument document = PDDocument.load(sourceFile);
PDFRenderer pdfRenderer = new PDFRenderer(document);
final ExecutorService service = Executors.newFixedThreadPool(4);
for (int page = 0; page < document.getNumberOfPages(); ++page)
{
final int finalPageNumber = page;
Runnable r = () -> {
try
{
//Java could only print with 72 dpi so I'll use it
BufferedImage image = pdfRenderer.renderImageWithDPI(finalPageNumber, 72);
File imageFile = new File(sourceFile.getAbsolutePath() + "-" + (finalPageNumber + 1) + ".png");
ImageIO.write(image, "png", imageFile);
image.flush();
images.put(finalPageNumber, imageFile);
}
catch (final IOException e)
{
e.printStackTrace();
}
};
Thread t = new Thread(r, page + "");
t.setName("" + page);
service.submit(t);
}
And for reading is the following code used:
// example url: /tmp/example.pdf-17.png
Image i = ImageIO.read(url);
What about to solve this problem
edit
What I've forgotten to say I add a Title manually to the Image:
BufferedImage bimage = new BufferedImage( simple.getValue().getWidth(null),
simple.getValue().getHeight(null) + 50,
BufferedImage.TYPE_INT_ARGB);
Graphics bGr = bimage.createGraphics();
bGr.setColor(Color.WHITE);
bGr.fillRect(0, 0, bimage.getWidth(), bimage.getHeight());
bGr.setFont(new Font("Arial", Font.PLAIN, 15));
bGr.setColor(Color.BLACK);
bGr.drawImage(simple.getValue(), 0, 50, null);
bGr.drawString(entry.getValue(), 20, 20);
try
{
ImageIO.write(bimage, "PNG", new File(simple.getKey().toURI()));
}
catch (IOException | URISyntaxException e)
{
e.printStackTrace();
}
bGr.dispose();
And here are the links to the files (It could occur with every page):
Image which throws the exception
PDF file which is used (generated by Word2007)
I have solved my Problem. I hadn't wait for the writing of the Image. Now I wait for the finish of the ExecutorService and everything works fine.
I think there was a problem to free resources, since I've seen that at MemoryCacheImageInputStream line 100 every thing was fine when the exception was thrown.
I succesfully converted image files (gif, png, jpg, bmp) to pdf's using iText 1.3.
I can't change the version since we can't just change versions of a jar obviously in a professional environment.
The problem that I have is that the size of the image in the pdf is larger than the image itself. I am not talking about the file size but about the size of the image when the zoom is set to 100% on both the original image file and the pdf.
The pdf shows the image about a 20% to 30% bigger than the original image.
What am I doing wrong?
public void convertOtherImages2pdf(byte[] in, OutputStream out, String title, String author) throws IOException {
Image image = Image.getInstance(in);
Rectangle imageSize = new Rectangle(image.width() + 1f, image.height() + 1f);
image.scaleAbsolute(image.width(), image.height());
com.lowagie.text.Document document = new com.lowagie.text.Document(imageSize, 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
document.add(image);
document.close();
writer.close();
}
Make MultipleImagesToPdf Class
public void imagesToPdf(String destination, String pdfName, String imagFileSource) throws IOException, DocumentException {
Document document = new Document(PageSize.A4, 20.0f, 20.0f, 20.0f, 150.0f);
String desPath = destination;
File destinationDirectory = new File(desPath);
if (!destinationDirectory.exists()){
destinationDirectory.mkdir();
System.out.println("DESTINATION FOLDER CREATED -> " + destinationDirectory.getAbsolutePath());
}else if(destinationDirectory.exists()){
System.out.println("DESTINATION FOLDER ALREADY CREATED!!!");
}else{
System.out.println("DESTINATION FOLDER NOT CREATED!!!");
}
File file = new File(destinationDirectory, pdfName + ".pdf");
FileOutputStream fileOutputStream = new FileOutputStream(file);
PdfWriter pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
document.open();
System.out.println("CONVERTER START.....");
String[] splitImagFiles = imagFileSource.split(",");
for (String singleImage : splitImagFiles) {
Image image = Image.getInstance(singleImage);
document.setPageSize(image);
document.newPage();
image.setAbsolutePosition(0, 0);
document.add(image);
}
document.close();
System.out.println("CONVERTER STOPTED.....");
}
public static void main(String[] args) {
try {
MultipleImagesToPdf converter = new MultipleImagesToPdf();
Scanner sc = new Scanner(System.in);
System.out.print("Enter your destination folder where save PDF \n");
// Destination = D:/Destination/;
String destination = sc.nextLine();
System.out.print("Enter your PDF File Name \n");
// Name = test;
String name = sc.nextLine();
System.out.print("Enter your selected image files name with source folder \n");
String sourcePath = sc.nextLine();
// Source = D:/Source/a.jpg,D:/Source/b.jpg;
if (sourcePath != null || sourcePath != "") {
converter.imagesToPdf(destination, name, sourcePath);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
=================================
Here i use itextpdf-5.4.0 Library
Happy Coding :)
You need to scale the image by the dpi.
float scale = 72 / dpi;
I don't know if such an ancient iText has that image information, more recent iText versions have it.
It seems to me there are two ways to store an attachment in a NotesDocument.
Either as a RichTextField or as a "MIME Part".
If they are stored as RichText you can do stuff like:
document.getAttachment(fileName)
That does not seem to work for an attachment stored as a MIME Part. See screenshot
I have thousands of documents like this in the backend. This is NOT a UI issue where I need to use the file Download control of XPages.
Each document as only 1 attachment. An Image. A JPG file. I have 3 databases for different sizes. Original, Large, and Small. Originally I created everything from documents that had the attachment stored as RichText. But my code saved them as MIME Part. that's just what it did. Not really my intent.
What happened is I lost some of my "Small" pictures so I need to rebuild them from the Original pictures that are now stored as MIME Part. So my ultimate goal is to get it from the NotesDocument into a Java Buffered Image.
I think I have the code to do what I want but I just "simply" can't figure out how to get the attachment off the document and then into a Java Buffered Image.
Below is some rough code I'm working with. My goal is to pass in the document with the original picture. I already have the fileName because I stored that out in metaData. But I don't know how to get that from the document itself. And I'm passing in "Small" to create the Small image.
I think I just don't know how to work with attachments stored in this manner.
Any ideas/advice would be appreciated! Thanks!!!
public Document processImage(Document inputDoc, String fileName, String size) throws IOException {
// fileName is the name of the attachment on the document
// The goal is to return a NEW BLANK document with the image on it
// The Calling code can then deal with keys and meta data.
// size is "Original", "Large" or "Small"
System.out.println("Processing Image, Size = " + size);
//System.out.println("Filename = " + fileName);
boolean result = false;
Session session = Factory.getSession();
Database db = session.getCurrentDatabase();
session.setConvertMime(true);
BufferedImage img;
BufferedImage convertedImage = null; // the output image
EmbeddedObject image = null;
InputStream imageStream = null;
int currentSize = 0;
int newWidth = 0;
String currentName = "";
try {
// Get the Embedded Object
image = inputDoc.getAttachment(fileName);
System.out.println("Input Form : " + inputDoc.getItemValueString("form"));
if (null == image) {
System.out.println("ALERT - IMAGE IS NULL");
}
currentSize = image.getFileSize();
currentName = image.getName();
// Get a Stream of the Imahe
imageStream = image.getInputStream();
img = ImageIO.read(imageStream); // this is the buffered image we'll work with
imageStream.close();
Document newDoc = db.createDocument();
// Remember this is a BLANK document. The calling code needs to set the form
if ("original".equalsIgnoreCase(size)) {
this.attachImage(newDoc, img, fileName, "JPG");
return newDoc;
}
if ("Large".equalsIgnoreCase(size)) {
// Now we need to convert the LARGE image
// We're assuming FIXED HEIGHT of 600px
newWidth = this.getNewWidth(img.getHeight(), img.getWidth(), 600);
convertedImage = this.getScaledInstance(img, newWidth, 600, false);
this.attachImage(newDoc, img, fileName, "JPG");
return newDoc;
}
if ("Small".equalsIgnoreCase(size)) {
System.out.println("converting Small");
newWidth = this.getNewWidth(img.getHeight(), img.getWidth(), 240);
convertedImage = this.getScaledInstance(img, newWidth, 240, false);
this.attachImage(newDoc, img, fileName, "JPG");
System.out.println("End Converting Small");
return newDoc;
}
return newDoc;
} catch (Exception e) {
// HANDLE EXCEPTION HERE
// SAMLPLE WRITE TO LOG.NSF
System.out.println("****************");
System.out.println("EXCEPTION IN processImage()");
System.out.println("****************");
System.out.println("picName: " + fileName);
e.printStackTrace();
return null;
} finally {
if (null != imageStream) {
imageStream.close();
}
if (null != image) {
LibraryUtils.incinerate(image);
}
}
}
I believe it will be some variation of the following code snippet. You might have to change which mimeentity has the content so it might be in the parent or another child depending.
Stream stream = session.createStream();
doc.getMIMEEntity().getFirstChildEntity().getContentAsBytes(stream);
ByteArrayInputStream bais = new ByteArrayInputStream(stream.read());
return ImageIO.read(bais);
EDIT:
session.setConvertMime(false);
Stream stream = session.createStream();
Item itm = doc.getFirstItem("ParentEntity");
MIMEEntity me = itm.getMIMEEntity();
MIMEEntity childEntity = me.getFirstChildEntity();
childEntity.getContentAsBytes(stream);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
stream.getContents(bo);
byte[] mybytearray = bo.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(mybytearray);
return ImageIO.read(bais);
David have a look at DominoDocument,http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/XPagesExtAPI/8.5.2/com/ibm/xsp/model/domino/wrapped/DominoDocument.html
There you can wrap every Notes document
In the DominoDocument, there such as DominoDocument.AttachmentValueHolder where you can access the attachments.
I have explained it at Engage. It very powerful
http://www.slideshare.net/flinden68/engage-use-notes-objects-in-memory-and-other-useful-java-tips-for-x-pages-development