I am using Jpedal tool to convert PDF to Image. Jpedal tool helps to convert any or large number of PDF pages (let's say PDF pages = 1200) into .PNG images. In general this is working, however once in a while during converting these large number of PDF pages into images it causes the application and tomcat to stop without any information or logs.
It seems it's simply an OutOfMemoryError that is not being printed. While processing it prints the line logger.info("width = "+ width + " height= "+height); multiple times but at some point exits after that and stops tomcat.
Can anyone please help what to do for the same.
My Code: -
public boolean createPDF2ImageTask(String sourcePDFAbsPath, String destinationImageAbsPath, Float scalingFactor, String fileFormat, int softLimitInKB) throws Exception
{
System.setProperty("org.jpedal.flattenForm","true");
logger.info("createPDF2ImageTask ( sourcePDFAbsPath = "+sourcePDFAbsPath+" , destinationImageAbsPath = "+destinationImageAbsPath+ ", scalingFactor = "+scalingFactor+ " , fileFormat = "+fileFormat+ " softLimitInKB ="+softLimitInKB );
boolean status = true;
Float newScalingFactor;
int sizeOfImageInKB;
//PdfDecoder object provides the conversion
PdfDecoderServer decoder = null;
Map mapValues = null;
BufferedImage imageToSave = null;
BufferedOutputStream bufferedOutputStream = null;
long startTime = System.currentTimeMillis();
try
{
Helper.deleteFile(destinationImageAbsPath);
//mappings for non-embedded fonts to use
FontMappings.setFontReplacements();
decoder = new PdfDecoderServer(true);
decoder.openPdfFile(sourcePDFAbsPath);
mapValues = new HashMap();
mapValues.put(JPedalSettings.EXTRACT_AT_BEST_QUALITY_MAXSCALING, 2);
//alternatively secify a page size (aspect ratio preserved so will do best fit)
//set a page size (JPedal will put best fit to this)
PdfPageData pageData = decoder.getPdfPageData();
int width = (int)(scalingFactor*pageData.getCropBoxWidth(1));
int height = (int)(scalingFactor*pageData.getCropBoxHeight(1));
logger.info("width = "+ width + " height= "+height);
mapValues.put(JPedalSettings.EXTRACT_AT_PAGE_SIZE, new String[]{String.valueOf(width),String.valueOf(height)});
//which takes priority (default is false)
mapValues.put(JPedalSettings.PAGE_SIZE_OVERRIDES_IMAGE, Boolean.TRUE);
PdfDecoderServer.modifyJPedalParameters(mapValues);
/////////////////////////////////////////////////////////////////////////////////////
try
{
imageToSave = decoder.getPageAsHiRes(1, null, false);
decoder.flushObjectValues(true);
if(imageToSave != null)
{
logger.info("Start saving image as a file");
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File(destinationImageAbsPath)));
ImageIO.write(imageToSave, fileFormat, bufferedOutputStream);
}
else
{
throw new Exception("imageToSave is null, Exception in extractPageAsImage ");
}
}
catch(Exception e)
{
logger.error("Exception in extractPageAsImage :: "+e);
logger.error("Exception stack trace in extractPageAsImage :: ",e);
throw new Exception("Exception in extractPageAsImage :: "+e);
}
Related
I am using Jpedal tool to convert PDF to Image.
When PDF pages are very large in number and we process it to convert then tomcat gets stopped and throws Exception-
javax.imageio.IIOException: I/O error writing PNG file.
Can anyone please help for this.
public boolean createPDF2ImageTask(String sourcePDFAbsPath, String destinationImageAbsPath, Float scalingFactor, String fileFormat, int softLimitInKB) throws Exception
{
System.setProperty("org.jpedal.flattenForm","true");
logger.info("createPDF2ImageTask ( sourcePDFAbsPath = "+sourcePDFAbsPath+" , destinationImageAbsPath = "+destinationImageAbsPath+ ", scalingFactor = "+scalingFactor+ " , fileFormat = "+fileFormat+ " softLimitInKB ="+softLimitInKB );
boolean status = true;
Float newScalingFactor;
int sizeOfImageInKB;
//PdfDecoder object provides the conversion
PdfDecoderServer decoder = null;
Map mapValues = null;
BufferedImage imageToSave = null;
BufferedOutputStream bufferedOutputStream = null;
long startTime = System.currentTimeMillis();
try
{
Helper.deleteFile(destinationImageAbsPath);
//mappings for non-embedded fonts to use
FontMappings.setFontReplacements();
decoder = new PdfDecoderServer(true);
decoder.openPdfFile(sourcePDFAbsPath);
mapValues = new HashMap();
mapValues.put(JPedalSettings.EXTRACT_AT_BEST_QUALITY_MAXSCALING, 2);
//alternatively secify a page size (aspect ratio preserved so will do best fit)
//set a page size (JPedal will put best fit to this)
PdfPageData pageData = decoder.getPdfPageData();
int width = (int)(scalingFactor*pageData.getCropBoxWidth(1));
int height = (int)(scalingFactor*pageData.getCropBoxHeight(1));
logger.info("width = "+ width + " height= "+height);
mapValues.put(JPedalSettings.EXTRACT_AT_PAGE_SIZE, new String[]{String.valueOf(width),String.valueOf(height)});
//which takes priority (default is false)
mapValues.put(JPedalSettings.PAGE_SIZE_OVERRIDES_IMAGE, Boolean.TRUE);
PdfDecoderServer.modifyJPedalParameters(mapValues);
/////////////////////////////////////////////////////////////////////////////////////
try
{
imageToSave = decoder.getPageAsHiRes(1, null, false);
decoder.flushObjectValues(true);
if(imageToSave != null)
{
logger.info("Start saving image as a file");
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File(destinationImageAbsPath)));
ImageIO.write(imageToSave, fileFormat, bufferedOutputStream);
}
else
{
throw new Exception("imageToSave is null, Exception in extractPageAsImage ");
}
}
catch(Exception e)
{
logger.error("Exception in extractPageAsImage :: "+e);
logger.error("Exception stack trace in extractPageAsImage :: ",e);
throw new Exception("Exception in extractPageAsImage :: "+e);
}
It's throwing Exception - Exception in extractPageAsImage :: javax.imageio.IIOException: I/O error writing PNG file!
Maybe you could try to solve this by increasing memory of your Tomcat instance. On Unix platforms this can be achieved by adding some Java options in setenv.sh:
export JAVA_OPTS="$JAVA_OPTS -Xms128m -Xmx2048m -XX:MaxPermSize=512m"
or on Windows in the file setenv.bat:
set "JAVA_OPTS=%JAVA_OPTS% -Xms128m -Xmx2048m -XX:MaxPermSize=512m"
Please note that the numbers in the examples above are just examples, as they depend on the memory available on your platform.
Please refer to Tomcat's RUNNING.txt for further details on how to configure the Tomcat on your platform.
I have a problem that needs solving where we use OpenOffice 1.1.4 templated reports and programmatically export them to PDF.
The team who create the templates have recently changed the header image and some images in a table to background images (before they were just inserted) since this change the current program is not creating the PDFs with the images. We can export from OpenOffice manually and the images are included. Can anyone help with a change I may need to make to get these background images included please?
The current code:
private void print(XInterface xComponent,
PrintRequestDTO printReq, File sourceFile,
Vector<String> pages) throws java.lang.Exception {
String pageRange;
// XXX create the PDF via OOo export facility
com.sun.star.frame.XStorable pdfCreator = (com.sun.star.frame.XStorable) UnoRuntime
.queryInterface(
com.sun.star.frame.XStorable.class,
xComponent);
PropertyValue[] outputOpts = new PropertyValue[2];
outputOpts[0] = new PropertyValue();
outputOpts[0].Name = "CompressionMode";
outputOpts[0].Value = "1"; // XXX Change this perhaps?
outputOpts[1] = new PropertyValue();
outputOpts[1].Name = "PageRange";
if (printReq.getPageRange() == null) {
pageRange = "1-";
}
else {
if (printReq.getPageRange().length() > 0) {
pageRange = printReq.getPageRange();
}
else {
pageRange = "1-";
}
}
log.debug("Print Instruction - page range = "
+ pageRange);
PropertyValue[] filterOpts = new PropertyValue[3];
filterOpts[0] = new PropertyValue();
filterOpts[0].Name = "FilterName";
filterOpts[0].Value = "writer_pdf_Export"; // MS Word 97
filterOpts[1] = new PropertyValue();
filterOpts[1].Name = "Overwrite";
filterOpts[1].Value = new Boolean(true);
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
if (pages.size() == 0) { // ie no forced page breaks
// set page range
outputOpts[1].Value = pageRange;
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
File outputFile = new File(
sourceFile.getParent(),
printReq.getOutputFileName()
+ ".pdf");
StringBuffer sPDFUrl = new StringBuffer(
"file:///");
sPDFUrl.append(outputFile.getCanonicalPath()
.replace('\\', '/'));
log.debug("PDF file = " + sPDFUrl.toString());
if (pdfCreator != null) {
sleep();
pdfCreator.storeToURL(sPDFUrl.toString(),
filterOpts);
}
}
else if (pages.size() > 1) {
throw new PrintDocumentException(
"Only one forced split catered for currently");
}
else { // a forced split exists.
log.debug("Page break found in "
+ (String) pages.firstElement());
String[] newPageRanges = calculatePageRanges(
(String) pages.firstElement(), pageRange);
int rangeCount = newPageRanges.length;
for (int i = 0; i < rangeCount; i++) {
outputOpts[1].Value = newPageRanges[i];
log.debug("page range = " + newPageRanges[i]);
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
String fileExtension = (i == 0 && rangeCount > 1) ? "__Summary.pdf"
: ".pdf";
File outputFile = new File(
sourceFile.getParent(),
printReq.getOutputFileName()
+ fileExtension);
StringBuffer sPDFUrl = new StringBuffer(
"file:///");
sPDFUrl.append(outputFile.getCanonicalPath()
.replace('\\', '/'));
log.debug("PDF file = " + sPDFUrl.toString());
if (pdfCreator != null) {
log.debug("about to create the PDF file");
sleep();
pdfCreator.storeToURL(
sPDFUrl.toString(), filterOpts);
log.debug("done");
}
}
}
}
Thanks in advance.
Glad that suggestion of making the document visible helped. Since it has ALSO fixed the problem you have a timing/threading issue. I suspect you'll find that another dodgy option of doing a sleep before executing the save to PDF will also allow the images to appear. Neither of these solutions is good.
Most likley best fix is to upgrade to a newer version of Open Office (the API calls you have should still work). Another option would be to try to call the API to ask the document to refresh itself.
After finding the correct property I was able to open the file with the hidden property set to false, this meant when the file was exported to PDF it included the background images. Its a shame I could not find another solultion that kept the file hidden but at least its working.
I have a problem with some Java servlet I developed a few days ago and finally uploaded it to my test application server.
First I will describe what the Servlet does: Basically it creates a website counter by using two parameters: First parameter is the usernames identifier (username) and the second one is an integer identity which identifies the background image and design which should be applied to the counter, so that the user can change the used counter design without losing his counts. I use a Java servlet to generate the PNG file in these steps:
Load counter and design from database to obtain data
Load background image from PNG image source file to a BufferedImage
Draw the current counter value to the background image using the specified font, xPos, yPos, font size, etc..
Write the BufferedImage as PNG file to the servlet output stream specifying the content type is PNG.
The problem here is that the image which will be generated is incomplete (!). I do a flush and close on the output stream buy anyway it is still incomplete. I also tried to leave out all my modifications to draw anything on the Graphics2D of the BufferedImage, but it did not help at all. When I run the same code base in a stand alone application the output image is just fine so I don't think there is a problem with ImageIO or my general code.
Perhaps I missed some mandatory stuff in the servlet output declaration, but I can't find the bug on my own.
Here is the real running application:
http://csz-online.net:8080/CounterBuilder/CounterServlet?name=clemens&layout=61
As you can see the file in incomplete! Firefox for example shows the PNG content it received, but if I download the file Eye of Gnome for example won't display the corrupt file at all! The same image created by the stand alone application is complete and works fine.
THANKS!
Here is the code of the Java servlet processRequest method, which is to be executed on post and get. Since I don't have the original source code at the moment this is what JD-GUI outputs. It pretty looks the same except the exception handling at the end of the method:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
ServletContext cntx = getServletContext();
try
{
String creationStr = request.getParameter("layout");
long cId = Long.valueOf(creationStr).longValue();
String name = request.getParameter("name");
Counter counter = this.counterFacade.findByNickname(name);
Creation creation = this.creationFacade.find(Long.valueOf(cId));
String filename = cntx.getRealPath(creation.getBackground());
if (filename == null) {
throw new FileNotFoundException("BG not found: " + creation.getBackground());
}
String mime = cntx.getMimeType(filename);
int cCounter = counter.getCounter() + 1;
response.setContentType(mime);
File file = new File(filename);
response.setContentLength((int)file.length());
OutputStream out = response.getOutputStream();Throwable localThrowable4 = null;
try
{
String fontStr = creation.getFont();
BufferedImage image = ImageIO.read(file);
BufferedImage[] digits = new BufferedImage[10];
image.flush();
switch (fontStr)
{
case "gold":
Graphics2D g = image.createGraphics();
digits[0] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/0.png")));
digits[1] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/1.png")));
digits[2] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/2.png")));
digits[3] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/3.png")));
digits[4] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/4.png")));
digits[5] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/5.png")));
digits[6] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/6.png")));
digits[7] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/7.png")));
digits[8] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/8.png")));
digits[9] = ImageIO.read(new File(cntx.getRealPath("images/digits/gold/9.png")));
drawNumbersToImage(g, digits, cCounter, creation.getxPos(), creation.getyPos());
break;
default:
Font font = new Font(creation.getFont(), 0, creation.getFontSize());
FontRenderContext frc = new FontRenderContext(null, true, true);
TextLayout layout = new TextLayout(String.valueOf(cCounter), font, frc);
Graphics2D h = image.createGraphics();
h.setColor((Color)Color.class.getField(creation.getColor()).get(null));
layout.draw(h, creation.getxPos(), creation.getyPos());
h.dispose();
}
counter.setCounter(cCounter);
this.counterFacade.edit(counter);
ImageIO.write(image, "PNG", out);
out.flush();
out.close();
}
catch (Throwable localThrowable1)
{
localThrowable4 = localThrowable1;throw localThrowable1;
}
finally
{
if (out != null) {
if (localThrowable4 != null) {
try
{
out.close();
}
catch (Throwable x2)
{
localThrowable4.addSuppressed(x2);
}
} else {
out.close();
}
}
}
}
catch (IOException|NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException ex)
{
ex.printStackTrace();
response.setContentType("text/HTML");
PrintWriter writer = response.getWriter();Throwable localThrowable3 = null;
try
{
writer.print("Could not generate counter due to missing or invalid parameters <b>bg</b> and <b>name</b>.");
}
catch (Throwable localThrowable2)
{
localThrowable3 = localThrowable2;throw localThrowable2;
}
finally
{
if (writer != null) {
if (localThrowable3 != null) {
try
{
writer.close();
}
catch (Throwable x2)
{
localThrowable3.addSuppressed(x2);
}
} else {
writer.close();
}
}
}
}
}
I have been trying to find a way to write metadata to a PNG and I have tried quite alot.
I can read the data using the pngj library using:
PngReader pngr = new PngReader(file);
pngr.readSkippingAllRows(); // reads only metadata
for (PngChunk c : pngr.getChunksList().getChunks()) {
if (!ChunkHelper.isText(c)) continue;
PngChunkTextVar ct = (PngChunkTextVar) c;
String key = ct.getKey();
String val = ct.getVal();
System.out.print(key + " " + val + "\n" );
}
pngr.close();
And it works great. But I need to write to it.
I have tried:
public boolean writeCustomData(String key, String value) throws Exception {
PngReader pngr = new PngReader(currentImage);
PngWriter png = new PngWriter(new FileOutputStream(currentImage), pngr.imgInfo);
png.getMetadata().setText(key, value);
return true;
}
But this does nothing.
And I have tried using the answer from Writing image metadata in Java, preferably PNG
this works (kinda) but my read function cant see it.
If you want to add a chunk to the image, you must read and write the full image. Example
PngReader pngr = new PngReader(origFile);
PngWriter pngw = new PngWriter(destFile, pngr.imgInfo, true);
// instruct the writer to copy all ancillary chunks from source
pngw.copyChunksFrom(pngr.getChunksList(), ChunkCopyBehaviour.COPY_ALL);
// add a new textual chunk (can also be done after writing the rows)
pngw.getMetadata().setText("my key", "my val");
// copy all rows
for (int row = 0; row < pngr.imgInfo.rows; row++) {
IImageLine l1 = pngr.readRow();
pngw.writeRow(l1);
}
pngr.end();
pngw.end();
If you need more performance, you can read/write the chunks at a lower level, see this example.
Try this:
Stream pngStream = new System.IO.FileStream("smiley.png", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
PngBitmapDecoder pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapFrame pngFrame = pngDecoder.Frames[0];
InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter();
if (pngInplace.TrySave() == true)
{
pngInplace.SetQuery("/Text/Description", "Have a nice day.");
}
pngStream.Close();
I'd like to make my Java program compare the actual screen with a picture (screenshot).
I don't know if it's possible, but I have seen it in Jitbit (a macro recorder) and I would like to implement it myself. (Maybe with that example you understand what I mean).
Thanks
----edit-----
In other words, is it possible to check if an image is showing in? To find and compare that pixels in the screen?
You may try aShot: documentation link
1) aShot can ignore areas you mark with special color.
2) aShot can provide image which display difference between images.
private void compareTowImages(BufferedImage expectedImage, BufferedImage actualImage) {
ImageDiffer imageDiffer = new ImageDiffer();
ImageDiff diff = imageDiffer
.withDiffMarkupPolicy(new PointsMarkupPolicy()
.withDiffColor(Color.YELLOW))
.withIgnoredColor(Color.MAGENTA)
.makeDiff(expectedImage, actualImage);
// areImagesDifferent will be true if images are different, false - images the same
boolean areImagesDifferent = diff.hasDiff();
if (areImagesDifferent) {
// code in case of failure
} else {
// Code in case of success
}
}
To save image with differences:
private void saveImage(BufferedImage image, String imageName) {
// Path where you are going to save image
String outputFilePath = String.format("target/%s.png", imageName);
File outputFile = new File(outputFilePath);
try {
ImageIO.write(image, "png", outputFile);
} catch (IOException e) {
// Some code in case of failure
}
}
You can do this in two steps:
Create a screenshot using awt.Robot
BufferedImage image = new Robot().createScreenCapture(new Rctangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("/screenshot.png"));
Compare the screenshots using something like that: How to check if two images are similar or not using openCV in java?
Have a look at Sikuli project. Their automation engine is based on image comparison.
I guess, internally they are still using OpenCV for calculating image similarity, but there are plenty of OpenCV Java bindings like this, which allow to do so from Java.
Project source code is located here: https://github.com/sikuli/sikuli
Ok then, so I found an answer after a few days.
This method takes the screenshot:
public static void takeScreenshot() {
try {
BufferedImage image = new Robot().createScreenCapture(new Rectangle(490,490,30,30));
/* this two first parameters are the initial X and Y coordinates. And the last ones are the increment of each axis*/
ImageIO.write(image, "png", new File("C:\\Example\\Folder\\capture.png"));
} catch (IOException e) {
e.printStackTrace();
} catch (HeadlessException e) {
e.printStackTrace();
} catch (AWTException e) {
e.printStackTrace();
}
}
And this other one will compare the images
public static String compareImage() throws Exception {
// savedImage is the image we want to look for in the new screenshot.
// Both must have the same width and height
String c1 = "savedImage";
String c2 = "capture";
BufferedInputStream in = new BufferedInputStream(new FileInputStream(c1
+ ".png"));
BufferedInputStream in1 = new BufferedInputStream(new FileInputStream(
c2 + ".png"));
int i, j;
int k = 1;
while (((i = in.read()) != -1) && ((j = in1.read()) != -1)) {
if (i != j) {
k = 0;
break;
}
}
in.close();
in1.close();
if (k == 1) {
System.out.println("Ok...");
return "Ok";
} else {
System.out.println("Fail ...");
return "Fail";
}
}