javax.imageio.IIOException: I/O error writing PNG file - java

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.

Related

Java application and tomcat suddenly stops without apparent reason

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);
}

xuggler failed to write header to container

I am trying to download video from RTSP stream to a file on my computer using the Xuggler 5.4 library.
String outputFilename = "D:\\downloadedrtsp.avi";
String inputSource = "rtsp://[ip-address]:[port]/user=[username]&[password]=password&channel=1&stream=1.sdp";
try {
IContainer container = IContainer.make();
IMetaData im = IMetaData.make();
im.setValue("max_delay", (1000000l) + "");
int retval = im.setValue("rtsp_transport", "tcp");
container.open(inputSource, IContainer.Type.READ, null, false, true, im, null);
IMediaReader mediaReader = ToolFactory.makeReader(container);
IMediaWriter mediaWriter = ToolFactory.makeWriter(outputFilename, mediaReader);
mediaReader.addListener(mediaWriter);
IError error;
while ((error = mediaReader.readPacket()) == null) {
logger.info("reading packet");
}
} catch (Exception e) {
e.printStackTrace();
}
But the code fails with a stacktrace
15:40:52.500 [main] ERROR org.ffmpeg - [tcp # 00000000171C6BE0] Failed to resolve hostname \downloadedrtsp.avi: ???? ???? ??????????.
15:40:52.500 [main] ERROR com.xuggle.xuggler - Error: could not write header for container (../../../../../../../csrc/com/xuggle/xuggler/Container.cpp:827)
java.lang.RuntimeException: Error Operation not permitted, failed to write header to container com.xuggle.xuggler.IContainer#387681280[url:D:\downloadedrtsp.avi;type:WRITE;format:com.xuggle.xuggler.IContainerFormat#387719536[oname:rtsp;olongname:RTSP output format;omimetype:null;oextensions:null;];] while establishing stream com.xuggle.xuggler.IStream#387690704[index:1;id:0;streamcoder:com.xuggle.xuggler.IStreamCoder#384527536[codec=com.xuggle.xuggler.ICodec#387719392[type=CODEC_TYPE_AUDIO;id=CODEC_ID_AAC;name=libvo_aacenc;];time base=1/8000;frame rate=0/0;sample rate=8000;channels=1;];framerate:0/0;timebase:1/90000;direction:OUTBOUND;]
at com.xuggle.mediatool.MediaWriter.getStream(MediaWriter.java:1058)
at com.xuggle.mediatool.MediaWriter.encodeAudio(MediaWriter.java:830)
at com.xuggle.mediatool.MediaWriter.onAudioSamples(MediaWriter.java:1441)
at com.xuggle.mediatool.AMediaToolMixin.onAudioSamples(AMediaToolMixin.java:89)
at com.xuggle.mediatool.MediaReader.dispatchAudioSamples(MediaReader.java:628)
at com.xuggle.mediatool.MediaReader.decodeAudio(MediaReader.java:555)
at com.xuggle.mediatool.MediaReader.readPacket(MediaReader.java:469)
at ua.datalink.main.StreamTranscodingExample.readHigherLevel(StreamTranscodingExample.java:103)
at ua.datalink.main.StreamTranscodingExample.main(StreamTranscodingExample.java:121)
The file is created on program startup, but it's empty. Where can the problem lies? I have spend hours to figure it out, but still no result.

Batching multiple files to Amazon S3 using the Java SDK

I'm trying to upload multiple files to Amazon S3 all under the same key, by appending the files. I have a list of file names and want to upload/append the files in that order. I am pretty much exactly following this tutorial but I am looping through each file first and uploading that in part. Because the files are on hdfs (the Path is actually org.apache.hadoop.fs.Path), I am using the input stream to send the file data. Some pseudocode is below (I am commenting the blocks that are word for word from the tutorial):
// Create a list of UploadPartResponse objects. You get one of these for
// each part upload.
List<PartETag> partETags = new ArrayList<PartETag>();
// Step 1: Initialize.
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(
bk.getBucket(), bk.getKey());
InitiateMultipartUploadResult initResponse =
s3Client.initiateMultipartUpload(initRequest);
try {
int i = 1; // part number
for (String file : files) {
Path filePath = new Path(file);
// Get the input stream and content length
long contentLength = fss.get(branch).getFileStatus(filePath).getLen();
InputStream is = fss.get(branch).open(filePath);
long filePosition = 0;
while (filePosition < contentLength) {
// create request
//upload part and add response to our list
i++;
}
}
// Step 3: Complete.
CompleteMultipartUploadRequest compRequest = new
CompleteMultipartUploadRequest(bk.getBucket(),
bk.getKey(),
initResponse.getUploadId(),
partETags);
s3Client.completeMultipartUpload(compRequest);
} catch (Exception e) {
//...
}
However, I am getting the following error:
com.amazonaws.services.s3.model.AmazonS3Exception: The XML you provided was not well-formed or did not validate against our published schema (Service: Amazon S3; Status Code: 400; Error Code: MalformedXML; Request ID: 2C1126E838F65BB9), S3 Extended Request ID: QmpybmrqepaNtTVxWRM1g2w/fYW+8DPrDwUEK1XeorNKtnUKbnJeVM6qmeNcrPwc
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1109)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:741)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:461)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:296)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3743)
at com.amazonaws.services.s3.AmazonS3Client.completeMultipartUpload(AmazonS3Client.java:2617)
If anyone knows what the cause of this error might be, that would be greatly appreciated. Alternatively, if there is a better way to concatenate a bunch of files into one s3 key, that would be great as well. I tried using java's builtin SequenceInputStream but that did not work. Any help would be greatly appreciated. For reference, the total size of all the files could be as large as 10-15 gb.
I know it's probably a bit late but worth giving my contribution.
I've managed to solve a similar problem using the SequenceInputStream.
The tricks is in being able to calculate the total size of the result file and then feeding the SequenceInputStream with an Enumeration<InputStream>.
Here's some example code that might help:
public void combineFiles() {
List<String> files = getFiles();
long totalFileSize = files.stream()
.map(this::getContentLength)
.reduce(0L, (f, s) -> f + s);
try {
try (InputStream partialFile = new SequenceInputStream(getInputStreamEnumeration(files))) {
ObjectMetadata resultFileMetadata = new ObjectMetadata();
resultFileMetadata.setContentLength(totalFileSize);
s3Client.putObject("bucketName", "resultFilePath", partialFile, resultFileMetadata);
}
} catch (IOException e) {
LOG.error("An error occurred while combining files. {}", e);
}
}
private Enumeration<? extends InputStream> getInputStreamEnumeration(List<String> files) {
return new Enumeration<InputStream>() {
private Iterator<String> fileNamesIterator = files.iterator();
#Override
public boolean hasMoreElements() {
return fileNamesIterator.hasNext();
}
#Override
public InputStream nextElement() {
try {
return new FileInputStream(Paths.get(fileNamesIterator.next()).toFile());
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
throw new RuntimeException(e);
}
}
};
}
Hope this helps!

Java Servlet PNG image output display corrupt (not transmitted completely)

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();
}
}
}
}
}

NullPointerException using ImageIO.read

I'm getting an NPE while trying to read in an image file, and I can't for the life of me figure out why. Here is my line:
BufferedImage source = ImageIO.read(new File(imgPath));
imgPath is basically guaranteed to be valid and right before it gets here it copies the file from the server. When it hits that line, I get this stack trace:
Exception in thread "Thread-26" java.lang.NullPointerException
at com.ctreber.aclib.image.ico.ICOReader.getICOEntry(ICOReader.java:120)
at com.ctreber.aclib.image.ico.ICOReader.read(ICOReader.java:89)
at javax.imageio.ImageIO.read(ImageIO.java:1400)
at javax.imageio.ImageIO.read(ImageIO.java:1286)
at PrintServer.resizeImage(PrintServer.java:981) <---My function
<Stack of rest of my application here>
Also, this is thrown into my output window:
Can't create ICOFile: Can't read bytes: 2
I have no idea what is going on, especially since the File constructor is succeeding. I can't seem to find anybody who has had a similar problem. Anybody have any ideas? (Java 5 if that makes any difference)
I poked around some more and found that you can specify which ImageReader ImageIO will use and read it in that way. I poked around our codebase and found that we already had a function in place for doing EXACTLY what I was trying to accomplish here. Just for anybody else who runs into a similar issue, here is the crux of the code (some of the crap is defined above, but this should help anybody who tries to do it):
File imageFile = new File(filename);
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByFormatName("jpeg");
if ( imageReaders.hasNext() ) {
imageReader = (ImageReader)imageReaders.next();
stream = ImageIO.createImageInputStream(imageFile);
imageReader.setInput(stream, true);
ImageReadParam param = imageReader.getDefaultReadParam();
curImage = imageReader.read(0, param);
}
Thanks for the suggestions and help all.
The File constructor will almost certainly succeed, regardless of whether it points to a valid/existing file. At the very least, I'd check whether your underlying file exists via the exists() method.
Also note that ImageIO.read is not thread-safe (it reuses cached ImageReaders which are not thread-safe).
This means you can't easily read multiple files in parallel. To do that, you'll have to deal with ImageReaders yourself.
Have you considered that the file may simply be corrupted, or that ImageIO is trying to read it as the wrong type of file?
Googling for the ICOReader class results in one hit: IconsFactory from jide-common.
Apparently they had the same problem:
// Using ImageIO approach results in exception like this.
// Exception in thread "main" java.lang.NullPointerException
// at com.ctreber.aclib.image.ico.ICOReader.getICOEntry(ICOReader.java:120)
// at com.ctreber.aclib.image.ico.ICOReader.read(ICOReader.java:89)
// at javax.imageio.ImageIO.read(ImageIO.java:1400)
// at javax.imageio.ImageIO.read(ImageIO.java:1322)
// at com.jidesoft.icons.IconsFactory.b(Unknown Source)
// at com.jidesoft.icons.IconsFactory.a(Unknown Source)
// at com.jidesoft.icons.IconsFactory.getImageIcon(Unknown Source)
// at com.jidesoft.plaf.vsnet.VsnetMetalUtils.initComponentDefaults(Unknown Source)
// private static ImageIcon createImageIconWithException(final Class<?> baseClass, final String file) throws IOException {
// try {
// InputStream resource =
// baseClass.getResourceAsStream(file);
// if (resource == null) {
// throw new IOException("File " + file + " not found");
// }
// BufferedInputStream in =
// new BufferedInputStream(resource);
// return new ImageIcon(ImageIO.read(in));
// }
// catch (IOException ioe) {
// throw ioe;
// }
// }
What did they do instead?
private static ImageIcon createImageIconWithException(
final Class<?> baseClass, final String file)
throws IOException {
InputStream resource = baseClass.getResourceAsStream(file);
final byte[][] buffer = new byte[1][];
try {
if (resource == null) {
throw new IOException("File " + file + " not found");
}
BufferedInputStream in = new BufferedInputStream(resource);
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
buffer[0] = new byte[1024];
int n;
while ((n = in.read(buffer[0])) > 0) {
out.write(buffer[0], 0, n);
}
in.close();
out.flush();
buffer[0] = out.toByteArray();
} catch (IOException ioe) {
throw ioe;
}
if (buffer[0] == null) {
throw new IOException(baseClass.getName() + "/" + file
+ " not found.");
}
if (buffer[0].length == 0) {
throw new IOException("Warning: " + file
+ " is zero-length");
}
return new ImageIcon(Toolkit.getDefaultToolkit().createImage(
buffer[0]));
}
So you might want to try the same approach: read the raw bytes and use Toolkit to create an image from them.
"it's a jpeg but doesn't have a jpeg
extension."
That might be it.
It appears that the library AC.lib-ICO is throwing the NPE. Since this library is intended to read the Microsoft ICO file format, a JPEG might be a problem for it.
Consider explicitly providing the format using an alternative method.

Categories

Resources