I am working in html to pdf conversion using flying saucer(itextrenderer)...I have to render image..I have rendered the image which was in my local storage(it works fine)..I have to do the same thing with external image..
Here is my code snippet for html to pdf image renderer...
{
try {
String url = new File(inputHtmlPath).toURI().toURL().toString();
System.out.println("URL: " + url);
OutputStream out = new FileOutputStream(outputPdfPath);
File signUpTemplate = new File("C:/Users/SFLTP022/Desktop/task/index1.html");
String content=FileUtils.readFileToString(signUpTemplate);
//Flying Saucer part
ITextRenderer renderer = new ITextRenderer();
renderer.getSharedContext().setReplacedElementFactory(new MediaReplacedElementFactory(renderer.getSharedContext().getReplacedElementFactory()));
renderer.setDocumentFromString(content.toString());
renderer.layout();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
renderer.createPDF(baos);
//ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(url);
renderer.layout();
renderer.createPDF(out);
out.close();
}
Here is my default class to render html image,in which i have to load external image
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;
import com.lowagie.text.Image;
public class MediaReplacedElementFactory implements ReplacedElementFactory {
private final ReplacedElementFactory superFactory;
public MediaReplacedElementFactory(ReplacedElementFactory superFactory) {
this.superFactory = superFactory;
}
#Override
public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox, UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) {
Element element = blockBox.getElement();
if (element == null) {
return null;
}
String nodeName = element.getNodeName();
String className = element.getAttribute("class");
// Replace any <div class="media" data-src="image.png" /> with the
// binary data of `image.png` into the PDF.
if ("div".equals(nodeName) && "media".equals(className)) {
if (!element.hasAttribute("data-src")) {
throw new RuntimeException("An element with class `media` is missing a `data-src` attribute indicating the media file.");
}
InputStream input = null;
try {
input = new FileInputStream("https://cdn.zetran.com/testasset/images/banner/zetran/banner-parts/base/png/" + element.getAttribute("data-src"));
final byte[] bytes = IOUtils.toByteArray(input);
final Image image = Image.getInstance(bytes);
final FSImage fsImage = new ITextFSImage(image);
if (fsImage != null) {
if ((cssWidth != -1) || (cssHeight != -1)) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
} catch (Exception e) {
throw new RuntimeException("There was a problem trying to read a template embedded graphic.", e);
} finally {
IOUtils.closeQuietly(input);
}
}
return this.superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight);
}
#Override
public void reset() {
this.superFactory.reset();
}
public void remove(Element e) {
this.superFactory.remove(e);
}
#Override
public void setFormSubmissionListener(FormSubmissionListener listener) {
// TODO Auto-generated method stub
}
}
When i tried this by loading local image it works fine,as shown below
input = new FileInputStream("C:\Users\Public\Pictures\Sample Pictures\" + element.getAttribute("data-src"));
My html part(local storage image) looks like
<div id="logo" class="media" data-src="Desert.jpg" style="width: 177px; height: 60px" />
My html part(External storage image) looks like
<div id="logo" class="media" data-src="base.png" style="width: 177px; height: 60px" />
The error message is
java.lang.RuntimeException: There was a problem trying to read a template embedded graphic.
at com.boot.MediaReplacedElementFactory.createReplacedElement(MediaReplacedElementFactory.java:56)
at org.xhtmlrenderer.render.BlockBox.calcDimensions(BlockBox.java:716)
at org.xhtmlrenderer.render.BlockBox.calcDimensions(BlockBox.java:666)
at org.xhtmlrenderer.render.BlockBox.collapseBottomMargin(BlockBox.java:1205)
at org.xhtmlrenderer.render.BlockBox.collapseBottomMargin(BlockBox.java:1228)
at org.xhtmlrenderer.render.BlockBox.collapseMargins(BlockBox.java:1126)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:811)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:776)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:321)
at org.xhtmlrenderer.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:299)
at org.xhtmlrenderer.layout.BlockBoxing.layoutContent(BlockBoxing.java:90)
at org.xhtmlrenderer.render.BlockBox.layoutChildren(BlockBox.java:967)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:847)
at org.xhtmlrenderer.render.BlockBox.layout(BlockBox.java:776)
at org.xhtmlrenderer.pdf.ITextRenderer.layout(ITextRenderer.java:229)
at com.boot.App6.generatePDF(App6.java:67)
at com.boot.App6.main(App6.java:27)
Caused by: java.io.FileNotFoundException: https:\cdn.zetran.com\testasset\images\banner\zetran\banner-parts\base\png\base.png (The filename, directory name, or volume label syntax is incorrect)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at com.boot.MediaReplacedElementFactory.createReplacedElement(MediaReplacedElementFactory.java:45)
Yes, you can write file paths as URLs, e.g. file://...., but FileInputStream can only handle those kind of file-protocol-URLs pointing to a local file. Http-URLs must be loaded with some kind of HTTP Client.
Related
Right now, I have a JTextPane in Java Swing that loads contents from a file into the pane. However, it loads everything including all the tags. I would like it to only load the contents. Is there a way to get to the tag and load the portion in between <body> and </body>?
Here is the code
public class LoadContent {
String path = "../WordProcessor_MadeInSwing/backups/testDir/cool_COPY3.rtf";
public void load(JTextPane jTextPane){
try {
FileReader fr = new FileReader(path);
BufferedReader reader = new BufferedReader(fr);
jTextPane.read(reader, path);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch(IOException e){
}
}
}
If my .rtf file contains the word "Here is a test", it will load as:
<html>
<head>
<style>
<!--
p.default {
family:Dialog;
size:3;
bold:normal;
italic:;
foreground:#333333;
}
-->
</style>
</head>
<body>
<p class=default>
<span style="color: #333333; font-size: 12pt; font-family: Dialog">
Here is a test
</span>
</p>
</body>
</html>
I only want it to load "Here is a test"
I would like it to only load the contents
Then you need to parse out the contents first before displaying the text.
Here is a simple example to display the text between the Span tags:
import java.io.*;
import java.net.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
class GetSpan
{
public static void main(String[] args)
throws Exception
{
// Create a reader on the HTML content
Reader reader = getReader( args[0] );
// Parse the HTML
EditorKit kit = new HTMLEditorKit();
HTMLDocument doc = (HTMLDocument)kit.createDefaultDocument();
doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
kit.read(reader, doc, 0);
// Find all the Span elements in the HTML document
HTMLDocument.Iterator it = doc.getIterator(HTML.Tag.SPAN);
while (it.isValid())
{
int start = it.getStartOffset();
int end = it.getEndOffset();
String text = doc.getText(start, end - start);
System.out.println( text );
it.next();
}
}
// If 'uri' begins with "http:" treat as a URL,
// otherwise, treat as a local file.
static Reader getReader(String uri)
throws IOException
{
// Retrieve from Internet.
if (uri.startsWith("http"))
{
URLConnection conn = new URL(uri).openConnection();
return new InputStreamReader(conn.getInputStream());
}
// Retrieve from file.
else
{
return new FileReader(uri);
}
}
}
Just run the class with your file as the parameter.
Edit:
Just noticed the question has been changed to look for text in the <body> tag instead of the <span> tag. For some reason an iterator is not returned for the <body> tag.
So another option is to use a ParserCallback. The callback will notify you every time a starting tag (or ending tag) is found, or when text of any tag is found.
A basic example would be:
import java.io.*;
import java.net.*;
import javax.swing.text.*;
import javax.swing.text.html.parser.*;
import javax.swing.text.html.*;
public class ParserCallbackText extends HTMLEditorKit.ParserCallback
{
private boolean isBody = false;
public void handleText(char[] data, int pos)
{
if (isBody)
System.out.println( data );
}
public void handleStartTag(HTML.Tag tag, MutableAttributeSet a, int pos)
{
if (tag.equals(HTML.Tag.BODY))
{
isBody = true;
}
}
public static void main(String[] args)
throws Exception
{
Reader reader = getReader(args[0]);
ParserCallbackText parser = new ParserCallbackText();
new ParserDelegator().parse(reader, parser, true);
}
static Reader getReader(String uri)
throws IOException
{
// Retrieve from Internet.
if (uri.startsWith("http"))
{
URLConnection conn = new URL(uri).openConnection();
return new InputStreamReader(conn.getInputStream());
}
// Retrieve from file.
else
{
return new FileReader(uri);
}
}
}
The above example will ignore any text found the <head> tag.
Try with a HTML parser. jsoup is nice one and very easy to use.
public static String extractText(Reader reader) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(reader);
String line;
while ( (line=br.readLine()) != null) {
sb.append(line);
}
String textOnly = Jsoup.parse(sb.toString()).text();
return textOnly;
}
Friends, I am using PDFBox 2.0.6. I have been successfull in extracting images from the pdf file, But right now it is creating an image for single pdf page. But the issue is that there can be any no. of images in a pdf page, And I want that each embedded image should be extracted as a single image itself.
Here is the code,
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
public class DemoPdf {
public static void main(String args[]) throws Exception {
//Loading an existing PDF document
File file = new File("C:/Users/ADMIN/Downloads/Vehicle_Photographs.pdf");
PDDocument document = PDDocument.load(file);
//Instantiating the PDFRenderer class
PDFRenderer renderer = new PDFRenderer(document);
File imageFolder = new File("C:/Users/ADMIN/Desktop/image");
for (int page = 0; page < document.getNumberOfPages(); ++page) {
//Rendering an image from the PDF document
BufferedImage image = renderer.renderImage(page);
//Writing the image to a file
ImageIO.write(image, "JPEG", new File(imageFolder+"/" + page +".jpg"));
System.out.println("Image created"+ page);
}
//Closing the document
document.close();
}
}
Is it possible in PDFBox that I can extract all embedded images as separate images, Thanks
Yes. It is possible to extract all images from all the pages in pdf.
You may refer this link, extract images from pdf using PDFBox.
The basic idea here is that, extend the class with PDFStreamEngine, and override processOperator method. Call PDFStreamEngine.processPage for all the pages. And if the object that has been passed to processOperator is an Image Object, get BufferedImage from the object, and save it.
Extend PDFStreamEngine and override the processOperator some thing like
#Override
protected void processOperator( Operator operator, List<COSBase> operands) throws IOException
{
String operation = operator.getName();
if( "Do".equals(operation) )
{
COSName objectName = (COSName) operands.get( 0 );
PDXObject xobject = getResources().getXObject( objectName );
if( xobject instanceof PDImageXObject)
{
PDImageXObject image = (PDImageXObject)xobject;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
// same image to local
BufferedImage bImage = new BufferedImage(imageWidth,imageHeight,BufferedImage.TYPE_INT_ARGB);
bImage = image.getImage();
ImageIO.write(bImage,"PNG",new File("c:\\temp\\image_"+imageNumber+".png"));
imageNumber++;
}
else
{
}
}
else
{
super.processOperator( operator, operands);
}
}
This answer is similar with #jprism. But this is intended for someone who want just copy and paste this ready to use code with demo.
import org.apache.pdfbox.contentstream.PDFStreamEngine;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class ExtractImagesUseCase extends PDFStreamEngine{
private final String filePath;
private final String outputDir;
// Constructor
public ExtractImagesUseCase(String filePath,
String outputDir){
this.filePath = filePath;
this.outputDir = outputDir;
}
// Execute
public void execute(){
try{
File file = new File(filePath);
PDDocument document = PDDocument.load(file);
for(PDPage page : document.getPages()){
processPage(page);
}
}catch(IOException e){
e.printStackTrace();
}
}
#Override
protected void processOperator(Operator operator, List<COSBase> operands) throws IOException{
String operation = operator.getName();
if("Do".equals(operation)){
COSName objectName = (COSName) operands.get(0);
PDXObject pdxObject = getResources().getXObject(objectName);
if(pdxObject instanceof PDImageXObject){
// Image
PDImageXObject image = (PDImageXObject) pdxObject;
BufferedImage bImage = image.getImage();
// File
String randomName = UUID.randomUUID().toString();
File outputFile = new File(outputDir,randomName + ".png");
// Write image to file
ImageIO.write(bImage, "PNG", outputFile);
}else if(pdxObject instanceof PDFormXObject){
PDFormXObject form = (PDFormXObject) pdxObject;
showForm(form);
}
}
else super.processOperator(operator, operands);
}
}
Demo
public class ExtractImageDemo{
public static void main(String[] args){
String filePath = "C:\\Users\\John\\Downloads\\Documents\\sample-file.pdf";
String outputDir = "C:\\Users\\John\\Downloads\\Documents\\Output";
ExtractImagesUseCase useCase = new ExtractImagesUseCase(
filePath,
outputDir
);
useCase.execute();
}
}
I under gone a situation of converting html to pdf, Thankfully I can achieved this through flying saucer api. But My HTML consists of svg tags while converting I am unable to get the svg in pdf. It can be achieved using a Stackoverflow question
and Tutorial.
What is meant by the replacedElementFactory?
ChainingReplacedElementFactory chainingReplacedElementFactory
= new ChainingReplacedElementFactory();
chainingReplacedElementFactory.addReplacedElementFactory(replacedElementFactory);
chainingReplacedElementFactory.addReplacedElementFactory(new SVGReplacedElementFactory());
renderer.getSharedContext().setReplacedElementFactory(chainingReplacedElementFactory);
It's just an error in the tutorial, the line with replacedElementFactory is not needed.
Here is my working example.
Java:
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;
public class PdfSvg {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document inputDoc = builder.parse("svg.html");
ByteArrayOutputStream output = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
ChainingReplacedElementFactory chainingReplacedElementFactory = new ChainingReplacedElementFactory();
chainingReplacedElementFactory.addReplacedElementFactory(new SVGReplacedElementFactory());
renderer.getSharedContext().setReplacedElementFactory(chainingReplacedElementFactory);
renderer.setDocument(inputDoc, "");;
renderer.layout();
renderer.createPDF(output);
OutputStream fos = new FileOutputStream("svg.pdf");
output.writeTo(fos);
}
}
HTML:
<html>
<head>
<style type="text/css">
svg {display: block;width:100mm;height:100mm}
</style>
</head>
<body>
<div>
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3"
fill="red" />
</svg>
</div>
</body>
</html>
The ChainingReplacedElementFactory, SVGReplacedElement and SVGReplacedElementFactory comes from the tutorial.
If you wanted an in page solution, here's an alternate using #cloudformatter which is a remote formatting service. I added their Javascript to your fiddle along with some text and your Highchart chart.
http://jsfiddle.net/yk0Lxzg0/1/
var click="return xepOnline.Formatter.Format('printme', {render:'download'})";
jQuery('#buttons').append('<button onclick="'+ click +'">PDF</button>');
The above code placed in the fiddle will format the div with 'id' printme to PDF for download. That div includes your chart and some text.
http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage shows usage instructions and has many more samples of charts in SVG formatted to PDF either by themselves or as part of pages combined with text, tables and such.
#Rajesh I hope you already found a solution to your problem. If not (or anyone having issues working with flying saucer, batik and svg tags) then you might want to consider this-
removing all clip-path="url(#highcharts-xxxxxxx-xx)" from <g> tags did the trick for me.
My code is referring to the missing code part "SVGReplacedElementFactory".
And I use it like this:
renderer
.getSharedContext()
.setReplacedElementFactory( new B64ImgReplacedElementFactory() );
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.codec.Base64;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class B64ImgReplacedElementFactory implements ReplacedElementFactory
{
public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight)
{
Element e = box.getElement();
if(e == null)
{
return null;
}
String nodeName = e.getNodeName();
if(nodeName.equals("img"))
{
String attribute = e.getAttribute("src");
FSImage fsImage;
try
{
fsImage = buildImage(attribute, uac);
}
catch(BadElementException e1)
{
fsImage = null;
}
catch(IOException e1)
{
fsImage = null;
}
if(fsImage != null)
{
if(cssWidth != -1 || cssHeight != -1)
{
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException, BadElementException
{
if(srcAttr.startsWith("data:image/"))
{
// BASE64Decoder decoder = new BASE64Decoder();
// byte[] decodedBytes = decoder.decodeBuffer(b64encoded);
// byte[] decodedBytes = B64Decoder.decode(b64encoded);
byte[] decodedBytes = Base64.decode(srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(), srcAttr.length()));
return new ITextFSImage(Image.getInstance(decodedBytes));
}
FSImage fsImage = uac.getImageResource(srcAttr).getImage();
if(fsImage == null)
{
return convertToPNG(srcAttr);
}
return null;
}
private FSImage convertToPNG(String srcAttr) throws IOException, BadElementException
{
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PNGTranscoder t = new PNGTranscoder();
// t.addTranscodingHint(JPEGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, (25.4f / 72f));
t.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, 4000.0F);
t.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, 4000.0F);
try
{
t.transcode(
new TranscoderInput(srcAttr),
new TranscoderOutput(byteArrayOutputStream)
);
}
catch(TranscoderException e)
{
e.printStackTrace();
}
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
return new ITextFSImage(Image.getInstance(byteArrayOutputStream.toByteArray()));
}
public void remove(Element e)
{
}
#Override
public void setFormSubmissionListener(FormSubmissionListener formSubmissionListener)
{
}
public void reset()
{
}
}
I'm trying to write a program to extract all the embedded images from a PDF file. Unfortunately, many input files result in similar exceptions:
com.itextpdf.text.exceptions.UnsupportedPdfException: The color space [blah blah blah] is not supported.
The file that generated the traceback is password protected and I cannot unprotect it nor share the password, I'm afraid. However, I've encountered the error with more than one file from multiple sources. These files are perfectly viewable and printable in both OS X Preview and Acrobat Reader, so I'm pretty sure the problem is with iText and not the files.
I'm using iText 5.5.6 and Oracle JDK 1.8.0_31 on OS X 10.10.3 but the same error has been occurring over several iText, JDK and OS versions; I've just now gotten around to asking about it.
The code (main loop just calls PdfReaderContentParser.processContent with an instance of this class):
package info.metalfatigue;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfImageObject;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
public class MyImageRenderListener implements RenderListener {
private final String path;
public MyImageRenderListener(final String path) {
this.path = path;
}
#Override
public void beginTextBlock() {
// NOP
}
#Override
public void renderText(
#SuppressWarnings("unused") final TextRenderInfo renderInfo) {
// NOP
}
#Override
public void endTextBlock() {
// NOP
}
#Override
public void renderImage(final ImageRenderInfo renderInfo) {
try {
final PdfImageObject image = renderInfo.getImage();
final PdfName filter = (PdfName)image.get(PdfName.FILTER);
if (PdfName.DCTDECODE.equals(filter)) {
#SuppressWarnings("boxing")
final String filename =
String.format(
path,
renderInfo.getRef().getNumber(),
"jpg");
final OutputStream os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.close();
} else if (PdfName.JPXDECODE.equals(filter)) {
#SuppressWarnings("boxing")
final String filename =
String.format(
path,
renderInfo.getRef().getNumber(),
"jp2");
final OutputStream os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.close();
} else {
final BufferedImage awtImage = image.getBufferedImage();
if (null != awtImage) {
#SuppressWarnings("boxing")
final String filename =
String.format(
path,
renderInfo.getRef().getNumber(),
"png");
final OutputStream os = new FileOutputStream(filename);
ImageIO.write(awtImage, "png", os);
os.close();
}
}
} catch (final IOException e) {
e.printStackTrace();
}
}
}
An example exception traceback:
com.itextpdf.text.exceptions.UnsupportedPdfException: The color space [/DeviceN, [/Black], /DeviceCMYK, 1153 0 R, 1152 0 R] is not supported.
at com.itextpdf.text.pdf.parser.PdfImageObject.decodeImageBytes(PdfImageObject.java:323)
at com.itextpdf.text.pdf.parser.PdfImageObject.<init>(PdfImageObject.java:200)
at com.itextpdf.text.pdf.parser.PdfImageObject.<init>(PdfImageObject.java:169)
at com.itextpdf.text.pdf.parser.ImageRenderInfo.prepareImageObject(ImageRenderInfo.java:124)
at com.itextpdf.text.pdf.parser.ImageRenderInfo.getImage(ImageRenderInfo.java:114)
at info.metalfatigue.MyImageRenderListener.renderImage(MyImageRenderListener.java:42)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor$ImageXObjectDoHandler.handleXObject(PdfContentStreamProcessor.java:1268)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor.displayXObject(PdfContentStreamProcessor.java:352)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor.access$6100(PdfContentStreamProcessor.java:60)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor$Do.invoke(PdfContentStreamProcessor.java:988)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor.invokeOperator(PdfContentStreamProcessor.java:286)
at com.itextpdf.text.pdf.parser.PdfContentStreamProcessor.processContent(PdfContentStreamProcessor.java:429)
at com.itextpdf.text.pdf.parser.PdfReaderContentParser.processContent(PdfReaderContentParser.java:80)
at info.metalfatigue.PdfImgEx.main(PdfImgEx.java:23)
I have been trying to programatically create one png file from a number of other png files in Java using javax.imageio.
In particular I have been trying to use the answer outlined in How do I convert multiple png images to a single tiff file
However when I call the writeInsert(..) method I keep getting the below Exception.
java.lang.UnsupportedOperationException: Unsupported write variant!
at javax.imageio.ImageWriter.unsupported(Unknown Source)
at javax.imageio.ImageWriter.writeInsert(Unknown Source)
I understand that the canInsertImage returns whether it is possible to insert or not (and I can see that this method returns false) however I do not know how to change this.
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
public class ImageTest
{
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException
{
ImageOutputStream ios = null;
ImageWriter writer = null;
try
{
String dirName = "C:/png/test";
File dir = new File(dirName);
if (dir.exists() && dir.isDirectory())
{
File[] files = dir.listFiles();
if (null != files && files.length > 0)
{
File outFile = new File("C:/png", "output.png");
ios = ImageIO.createImageOutputStream(outFile);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
if (null != writers && writers.hasNext())
{
writer = writers.next();
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
for (int i = 0; i < files.length; i++)
{
InputStream fis = null;
try
{
fis = new BufferedInputStream(new FileInputStream(files[i]));
BufferedImage image = ImageIO.read(fis);
IIOImage img = new IIOImage(image, null, null);
if (i == 0)
{
writer.write(null, img, param);
}
else
{
writer.writeInsert(-1, img, param);
}
image.flush();
} finally
{
if (null != fis)
{
fis.close();
}
}
}
}
}
}
} catch (Exception e)
{
System.err.println("OOOps: " + e.getMessage() + "\n");
e.printStackTrace();
} finally
{
if (null != ios)
{
ios.close();
}
if (null != writer)
{
writer.dispose();
}
}
}
}