PDFBox Out of memory when adding image - image

I am using PDFBox to extract data from my webapp and put it into a PDF. I have a method that draws the header on each PDF page. However, when I add an image to the each page, the document runs out of memory. I was wondering if anybody had any ideas on a solution? Here is my drawHeader method:
public static void drawHeader(PDDocument doc, PDPage page, PDPageContentStream contentStream, int[] columnWidths, int pageNumber) throws IOException {
contentStream.beginText();
PDFont font = PDType1Font.HELVETICA_BOLD;
contentStream.setFont(font, 24);
contentStream.moveTextPositionByAmount(50, 750);
contentStream.drawString("Producer License Report");
contentStream.endText();
contentStream.beginText();
contentStream.moveTextPositionByAmount(550, 750);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 8);
contentStream.drawString("Page " + pageNumber);
contentStream.endText();
contentStream.drawLine(50, 740, 340, 740);
contentStream.drawLine(16, 680, 595, 680);
List<String> headerList = new LinkedList<String>();
headerList.add("NPN");
headerList.add("First Name");
headerList.add("Last Name");
headerList.add("Suffix");
headerList.add("License State");
headerList.add("Resident State");
headerList.add("License Number");
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 9);
float textx = 15;
float texty = 685;
InputStream in = new FileInputStream(new File("logo.jpg"));
PDJpeg img = new PDJpeg(doc, in);
contentStream.drawImage(img, 375, 720);
for (int i = 0; i < headerList.size(); i++) {
String text = headerList.get(i);
contentStream.beginText();
contentStream.moveTextPositionByAmount(textx, texty);
contentStream.drawString(text);
contentStream.endText();
textx += (columnWidths[i] * 6.5);
}
}

I found a solution! You have to create the Image-Object before opening the contentStream.
Example:
/* Step 1: Prepare the document.
*/
doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
/* Step 2: Prepare the image
* PDJpeg is the class you use when dealing with jpg images.
* You will need to mention the jpg file and the document to which it is to be added
* Note that if you complete these steps after the creating the content stream the PDF
* file created will show "Out of memory" error.
*/
PDXObjectImage image = null;
image = new PDJpeg(doc, new FileInputStream("image.jpg"));
PDPageContentStream contentStream = new PDPageContentStream(doc,
page);
....

I'm trying to comment the answer by Timo Hoen but don't have enough rep yet...
Another issue I've found with the "out of memory" error is if the image is large, or you have tried to draw it off the page.
Start with your coordinates as 100, 100 and then work from there.
e.g. contentStream.drawImage(img, 100, 100);
Cheers,
Sam

Related

How do I set LogicalScreenDescriptor and ImageDescriptor gif metadata

I want to create a GIF with a Logical Screen Descriptor larger than any image that I have in my gif image sequence. Each image in the gif will have its top and left offset modified. Here's the code I have that looks like it ought to work, but it doesn't
void test() throws IOException {
Image image1 = textToImage ("m",12.0 );
Image image2 = textToImage("n", 24.0);
Image[] images = {image2, image1};
String[] imageTopOffset = {"6", "30"};
String[] imageLeftOffset = {"6", "36"};
ImageWriter iw = ImageIO.getImageWritersByFormatName("gif").next();
ImageWriteParam params = iw.getDefaultWriteParam();
int type = ((BufferedImage)getRenderedImage(image1)).getType();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(type);
IIOMetadata metadata = iw.getDefaultImageMetadata(imageTypeSpecifier, params);
IIOMetadataNode root = (IIOMetadataNode)metadata.getAsTree(metadata.getNativeMetadataFormatName());
IIOMetadataNode lsdNode = getNode(root, "LogicalScreenDescriptor");
lsdNode.setAttribute("logicalScreenHeight", "100");
lsdNode.setAttribute("logicalScreenWidth", "75");
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", "100");
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by: http://example.com");
IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
boolean loop = true;
int loopContinuously = loop ? 0 : 1;
child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) ((loopContinuously >> 8) & 0xFF)});
appExtensionsNode.appendChild(child);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
iw.setOutput(ios);
iw.prepareWriteSequence(metadata);
int i = 0;
for (Image image : images) {
graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("delayTime", "50");
IIOMetadataNode imageDescriptorNode = getNode(root, "ImageDescriptor");
imageDescriptorNode.setAttribute("imageLeftPosition", imageLeftOffset[i]);
imageDescriptorNode.setAttribute("imageTopPosition", imageTopOffset[i]);
imageDescriptorNode.setAttribute("imageWidth", String.valueOf(image.getWidth()));
imageDescriptorNode.setAttribute("imageHeight", String.valueOf(image.getHeight()));
imageDescriptorNode.setAttribute("interlaceFlag", "FALSE");
IIOImage ii = new IIOImage(getRenderedImage(image), null, metadata);
iw.writeToSequence(ii, params);
i++;
}
iw.endWriteSequence();
ios.close();
byte[] gifContent = os.toByteArray();
os.close();
File outputFile = new File("test.gif");
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
outputStream.write(gifContent);
outputStream.close();
}
}
private WritableImage textToImage(String text, Double size) {
Text t = new Text();
t.setFont(getFont("Calibi",
"NORMAL",
"REGULAR",
size));
t.setStroke(Color.BLACK);
t.setText(text);
Scene scene = new Scene(new StackPane(t));
return t.snapshot(null, null);
}
IIOMetadataNode getNode(IIOMetadataNode rootNode, String name) {
NodeList childNodes = rootNode.getChildNodes();
for (int i=0; i<childNodes.getLength(); i++) {
if (childNodes.item(i).getNodeName().equals(name) ) {
return (IIOMetadataNode)childNodes.item(i);
}
}
// no child node with the given name found, create one!
IIOMetadataNode metadataNode = new IIOMetadataNode(name);
rootNode.appendChild(metadataNode);
return metadataNode;
}
Font getFont(String fontname, String fontWeight, String fontPosture, double size) {
FontPosture posture = FontPosture.valueOf(fontPosture);
FontWeight weight = FontWeight.valueOf(fontWeight);
Font font = Font.font (fontname, weight, posture, size);
return font;
}
public RenderedImage getRenderedImage(Image image) {
return SwingFXUtils.fromFXImage(image, null);
}
The gif image it produces is the size of the first image in the sequence even though I set the LogicalScreenDescriptor to a bigger size than the image that gets written out. The actual size of the gif is the size of the 1st image. The other problem is that imageTopPosition and imageLeftPosition doesn't get applied.
The two images are of different sizes. The two images are generated, one image is a 12 point image of the letter m, and the other image is a 24 point image of the letter n.
So how do I make a larger logical screen descriptor and how do I change the image descriptor offsets. Although the above code looks like it should work, it doesn't. Most examples I've found assume that all images in a gif are the same size and that the display of subsequent images in the gif completely replace the previous image.
Here are the coding changes I made that solved the problem for the gif not displaying properly:
void test() throws IOException {
Image image1 = textToImage ("m",12.0 );
Image image2 = textToImage("n", 24.0);
Image[] images = {image2, image1};
String[] imageTopOffset = {"6", "30"};
String[] imageLeftOffset = {"6", "36"};
ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/gif").next();
ImageWriteParam params = iw.getDefaultWriteParam();
int type = ((BufferedImage)getRenderedImage(image1)).getType();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(type);
IIOMetadata imageMetadata = iw.getDefaultImageMetadata(imageTypeSpecifier, params);
IIOMetadata streamMetadata = iw.getDefaultStreamMetadata(params);
IIOMetadataNode streamRoot = (IIOMetadataNode)streamMetadata.getAsTree(streamMetadata.getNativeMetadataFormatName());
IIOMetadataNode imageRoot = (IIOMetadataNode)imageMetadata.getAsTree(imageMetadata.getNativeMetadataFormatName());
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
iw.setOutput(ios);
IIOMetadataNode lsdNode = getNode(streamRoot, "LogicalScreenDescriptor");
lsdNode.setAttribute("logicalScreenHeight", "100");
lsdNode.setAttribute("logicalScreenWidth", "75");
/*
* The following extension nodes may not be put in the streamMetadata. If you do add them
* to the streamMetadata you'll get any error when you prepareWriteSequence
*
IIOMetadataNode graphicsControlExtensionNode = getNode(streamRoot, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", "100");
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode commentsNode = getNode(streamRoot, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by: http://example.com");
IIOMetadataNode appExtensionsNode = getNode(streamRoot, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
boolean loop = true;
int loopContinuously = loop ? 0 : 1;
child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) ((loopContinuously >> 8) & 0xFF)});
appExtensionsNode.appendChild(child);
*/
streamMetadata.setFromTree(streamMetadata.getNativeMetadataFormatName(), streamRoot);
iw.prepareWriteSequence(streamMetadata);
int i = 0;
for (Image image : images) {
IIOMetadataNode graphicsControlExtensionNode = getNode(imageRoot, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("delayTime", "50");
IIOMetadataNode imageDescriptorNode = getNode(imageRoot, "ImageDescriptor");
imageDescriptorNode.setAttribute("imageLeftPosition", imageLeftOffset[i]);
imageDescriptorNode.setAttribute("imageTopPosition", imageTopOffset[i]);
imageMetadata.setFromTree(imageMetadata.getNativeMetadataFormatName(),imageRoot);
IIOImage ii = new IIOImage(getRenderedImage(image), null, imageMetadata);
iw.writeToSequence(ii, params);
i++;
}
iw.endWriteSequence();
ios.close();
byte[] gifContent = os.toByteArray();
os.close();
File outputFile = new File("test.gif");
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
outputStream.write(gifContent);
outputStream.close();
}
}
The prepareWriteSequence command did not like streamMetadata that contains the extensions graphicControlExtension and ApplicationExtensions. I figured that out by examining the source code for GifImageWriter. There's also some problem with the value I provided to the set "imageWidth and "imageHeight". Not sure what the value for those attributes should look like. I just avoid that problem by not setting those values.
The output is a 75x100 gif with a 12pt letter m offset by 30 from the top and 36 from the left and a 24 point letter n offset 6 from the top and 6 from the left.

iTextSharp - Add image to PDF from Datatable

I try to create a PDF report from a datatable. One of the columns contents image. How can I extract the image from datatable and insert into PDF table? I'm using iTextShap version 5.4.2.0. Here is the code:
public void Report(DataTable dt, string output)
{
Document doc = new Document(PageSize.LETTER, 50, 50, 80, 50);
PdfWriter PDFWriter = PdfWriter.GetInstance(doc, new FileStream(output, FileMode.Create));
PDFWriter.ViewerPreferences = PdfWriter.PageModeUseOutlines;
iTextSharp.text.Font hel8 = FontFactory.GetFont(BaseFont.HELVETICA, 8);
doc.Open();
PdfPTable table = new PdfPTable(dt.Columns.Count);
float[] widths = new float[] { 1.2f, 1.2f, 1.2f, 1.2f, 1f, 4f, 1f, 4f };
table.SetWidths(widths);
table.WidthPercentage = 100;
PdfPCell cell = new PdfPCell(new Phrase("NewCells"));
cell.Colspan = dt.Columns.Count;
foreach (DataColumn c in dt.Columns)
{
table.AddCell(new Phrase(c.ColumnName, hel8));
}
foreach (DataRow r in dt.Rows)
{
if (dt.Rows.Count > 0)
{
table.AddCell(new Phrase(r[0].ToString(), hel8));
table.AddCell(new Phrase(r[1].ToString(), hel8));
table.AddCell(new Phrase(r[2].ToString(), hel8));
table.AddCell(new Phrase(r[3].ToString(), hel8));
table.AddCell(new Phrase(r[4].ToString(), hel8));
table.AddCell(new Phrase(r[5].ToString(), hel8));
byte[] byt = (byte[])r[6];
MemoryStream ms = new MemoryStream(byt);
System.Drwaing.Image sdi = System.Drawing.Image.FromStream(ms);
Image img = Image.GetInstance(sdi); <-- this is the problem code
table.AddCell(img);
table.AddCell(new Phrase(r[7].ToString(), hel8));
}
}
doc.Add(table);
}
doc.Close();
}
Update: #nekno, all of your suggestions are worked.
But I still need to correct the casting at line:
byte[] byt = (byte[])r[6];
It gave me a casting exception from VS2008. So I added the conversion function (pulled it from stackoverflow):
byte[] ImageToByte(System.Drawing.Image img)
{
byte[] byteArray = new byte[0];
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Close();
byteArray = stream.ToArray();
}
return byteArray;
}
And revised the code:
byte[] byt = ImageToByte((System.Drawing.Image)dt.Rows[e][6]);
Thanks.
What exactly is the problem? What happens when you use your problem code?
Try one of the other Image.GetInstance() overloads:
You can pass the byte array directly:
byte[] byt = (byte[])r[6];
Image img = Image.GetInstance(byt);
Or you can pass the Stream:
byte[] byt = (byte[])r[6];
MemoryStream ms = new MemoryStream(byt);
Image img = Image.GetInstance(ms);
Or you can give iTextSharp more info about the image format:
byte[] byt = (byte[])r[6];
MemoryStream ms = new MemoryStream(byt);
System.Drawing.Image sdi = System.Drawing.Image.FromStream(ms);
Image img = Image.GetInstance(sdi, ImageFormat.Png);
If your column can be cast to a System.Drawing.Image, then you can use it directly:
Image img = Image.GetInstance((System.Drawing.Image)r[6], System.Drawing.Imaging.ImageFormat.Png);
I have suggested steps how shows how to add image into PDF, given below code snippet show how to add logo into your PDF using iTextsharp, follow provided below steps:
I have provided link to download "itextsharp" component from given link http://sourceforge.net/projects/itextsharp/
You have to add reference into your application.
Next you have to add required namespaces "iTextsharp.text.html", "iTextsharp.text" to consume its best properties.
Now you have to add code snippet into your application given at the end, add code snippet under "button click" in code behind.
Hope it will work for you !!!
protected void btnPDF_Click(object sender, ImageClickEventArgs e)
{
DataTable dtn = new DataTable();
dtn = GetDataTable();
dtPDF = dtn.Copy();
for (int i = 0; i <= dtn.Rows.Count - 1; i++)
{
ExportToPdf(dtPDF);
}
}
public void ExportToPdf(DataTable myDataTable)
{
Document pdfDoc = new Document(PageSize.A4, 10, 10, 10, 10);
try
{
PdfWriter.GetInstance(pdfDoc, System.Web.HttpContext.Current.Response.OutputStream);
pdfDoc.Open();
Chunk c = new Chunk("" + System.Web.HttpContext.Current.Session["CompanyName"] + "", FontFactory.GetFont("Verdana", 11));
Paragraph p = new Paragraph();
p.Alignment = Element.ALIGN_CENTER;
p.Add(c);
pdfDoc.Add(p);
string clientLogo = Server.MapPath(".") + "/logo/tpglogo.jpg";
string imageFilePath = Server.MapPath(".") + "/logo/tpglogo.jpg";
iTextSharp.text.Image jpg = iTextSharp.text.Image.GetInstance(imageFilePath);
//Resize image depend upon your need
jpg.ScaleToFit(80f, 60f);
//Give space before image
jpg.SpacingBefore = 0f;
//Give some space after the image
jpg.SpacingAfter = 1f;
jpg.Alignment = Element.HEADER;
pdfDoc.Add(jpg);
Font font8 = FontFactory.GetFont("ARIAL", 7);
DataTable dt = myDataTable;
if (dt != null)
{
//Craete instance of the pdf table and set the number of column in that table
PdfPTable PdfTable = new PdfPTable(dt.Columns.Count);
PdfPCell PdfPCell = null;
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
for (int column = 0; column < dt.Columns.Count; column++)
{
PdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows][column].ToString(), font8)));
PdfTable.AddCell(PdfPCell);
}
}
//PdfTable.SpacingBefore = 15f; // Give some space after the text or it may overlap the table
pdfDoc.Add(PdfTable); // add pdf table to the document
}
pdfDoc.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename= SampleExport.pdf");
System.Web.HttpContext.Current.Response.Write(pdfDoc);
Response.Flush();
Response.End();
//HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (DocumentException de)
{
System.Web.HttpContext.Current.Response.Write(de.Message);
}
catch (IOException ioEx)
{
System.Web.HttpContext.Current.Response.Write(ioEx.Message);
}
catch (Exception ex)
{
System.Web.HttpContext.Current.Response.Write(ex.Message);
}
}

cropping a specific image from sdcard

i want to crop an image present in sdcard .My code is:
Intent intent = new Intent("com.android.camera.action.CROP");
Uri uriOfImageToCrop = Uri.parse(Environment.getExternalStorageDirectory()+"/bookpage.jpg");
intent.setDataAndType(uriOfImageToCrop, "image/*");
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 200);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriOfImageCrop);
startActivity(intent);
But it showing the following exception:
java.lang.IllegalStateException: Target host must not be null, or set in parameters.
can anybody help me please.
Android doesn't include a crop API anymore. You need to create your own or import one like :
https://github.com/lvillani/android-cropimage
You can use http://code.google.com/p/catalano-framework/
FastBitmap fb = new FastBitmap(bitmap);
int startX = 10;
int startY = 10;
int newWidth = 100;
int newheigth = 100;
Crop crop = new Crop(startX, startY, newWidth, newHeigth);
crop.applyInPlace(fb);

How to create PowePoint presentation in OpenXML format with Apache Poi and XSLF?

If I go to Apache POI XSLF there should be samples for both OLE2 and OpenXML specs, but there are only the OLE2 based Horrible Slide Layout Format examples.
Could please anybody help me out with XML Slide Layout Format example ? The API is quite different.
It is not like with spreadsheet where one just change the implementation of HSSFWorkbook to XSSFWorkbook.
How would this look like with XSLF implementation ? POI apparently can't create a document from scratch, so we need an existing empty dummy document, right ?
//table data
String[][] data = {
{"INPUT FILE", "NUMBER OF RECORDS"},
{"Item File", "11,559"},
{"Vendor File", "300"},
{"Purchase History File", "10,000"},
{"Total # of requisitions", "10,200,038"}
};
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
//create a table of 5 rows and 2 columns
Table table = new Table(5, 2);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
TableCell cell = table.getCell(i, j);
cell.setText(data[i][j]);
RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
rt.setFontName("Arial");
rt.setFontSize(10);
cell.setVerticalAlignment(TextBox.AnchorMiddle);
cell.setHorizontalAlignment(TextBox.AlignCenter);
}
}
//set table borders
Line border = table.createBorder();
border.setLineColor(Color.black);
border.setLineWidth(1.0);
table.setAllBorders(border);
//set width of the 1st column
table.setColumnWidth(0, 300);
//set width of the 2nd column
table.setColumnWidth(1, 150);
slide.addShape(table);
table.moveTo(100, 100);
FileOutputStream out = new FileOutputStream(file);
ppt.write(out);
out.close();
It is not implemented yet, org.apache.poi version 3.8-beta3, when it will be implemented is very unknown to me.
XMLSlideShow.java
public MasterSheet createMasterSheet() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}
public Slide createSlide() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}

Blackberry - ListField with images from filesystem

I use the following code to retrieve image from the phone or SDCard and I use that image in to my ListField. It gives the output but it takes very Long time to produce the screen. How to solve this problem ?? Can any one help me?? Thanks in advance!!!
String text = fileholder.getFileName();
try{
String path="file:///"+fileholder.getPath()+text;
//path=”file:///SDCard/BlackBerry/pictures/image.bmp”
InputStream inputStream = null;
//Get File Connection
FileConnection fileConnection = (FileConnection) Connector.open(path);
inputStream = fileConnection.openInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int j = 0;
while((j=inputStream.read()) != -1) {
baos.write(j);
}
byte data[] = baos.toByteArray();
inputStream.close();
fileConnection.close();
//Encode and Resize image
EncodedImage eImage = EncodedImage.createEncodedImage(data,0,data.length);
int scaleFactorX = Fixed32.div(Fixed32.toFP(eImage.getWidth()),
Fixed32.toFP(180));
int scaleFactorY = Fixed32.div(Fixed32.toFP(eImage.getHeight()),
Fixed32.toFP(180));
eImage=eImage.scaleImage32(scaleFactorX, scaleFactorY);
Bitmap bitmapImage = eImage.getBitmap();
graphics.drawBitmap(0, y+1, 40, 40,bitmapImage, 0, 0);
graphics.drawText(text, 25, y,0,width);
}
catch(Exception e){}
You should read files once (on App start or before screen open, maybe put a progress dialog there), put images in array and use this array in paint.

Resources