I have a html page with text, image and I am parsing the HTML content to iText to generate the PDF. In the generated PDF,Included images are not getting displayed and , only the text is getting displayed.
If I pass the absolute path like D:/Deiva/CRs/HTMLPage/article-101-horz.jpg then the image will get printed. But if I try to print the image from the server like
http://localhost:8085/content/dam/article-101-h1.jpg or http://www.google.co.in/intl/en_ALL/images/logos/images_logo_lg.gif
then it is not getting printed in the PDF.
NOTE: I am using itextpdf-5.2.1.jar to generate the PDF.
My HTML Code (Article.html):
<html>
<head>
</head>
<body>
<p>Generate PDF with image using iText.</p>
<img src="http://localhost:8085/content/dam/article-10-h1.jpg"></img>
<img src="http://www.google.co.in/intl/en_ALL/images/logos/imgs_logo_lg.gif"></img>
<img class="right horz" src="D:/Deiva/CRs/HTMLPage/article-101-horz.jpg"></img>
</body>
</html>
I am using the below java code for generating the PDF:
private void createPDF (){
String path = "D:/Deiva/Test.pdf";
PdfWriter pdfWriter = null;
//create a new document
Document document = new Document();
try {
//get Instance of the PDFWriter
pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(path));
//document header attributes
document.addAuthor("betterThanZero");
document.addCreationDate();
document.addProducer();
document.addCreator("MySampleCode.com");
document.addTitle("Demo for iText XMLWorker");
document.setPageSize(PageSize.LETTER);
//open document
document.open();
InputStream is = new FileInputStream("D:/Deiva/CRs/Oncology/Phase5/CR1/HTMLPage/Article.html");
// create new input stream reader
InputStreamReader isr = new InputStreamReader(is);
//get the XMLWorkerHelper Instance
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
//convert to PDF
worker.parseXHtml(pdfWriter, document, isr);
//close the document
document.close();
//close the writer
pdfWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Please suggest a solution to display the image in PDF.
Thanks in advance.
Deiva
I think you can do it easily using a Servlet for viewing the image. How to write a servlet for this is here
Here a sample dispatcher for you. Just edit the required places as needed
#Controller
public class ImageController extends DispatcherServlet {
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
// Properties ---------------------------------------------------------------------------------
private String imagePath;
#RequestMapping(value="images/{imageId:.+}", method = RequestMethod.GET)
public #ResponseBody void getImage(#PathVariable String imageId,HttpServletRequest request, HttpServletResponse response){
String requestedImage = request.getPathInfo();
this.imagePath ="image path in server here";
if (requestedImage == null) {
// Do your thing if the image is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}catch(IOException ioException){
logger.error("error image path incorrect:{}", ioException);
} // 404.
return;
}
File image=null;
try {
image = new File(imagePath, URLDecoder.decode(imageId, "UTF-8"));
} catch (UnsupportedEncodingException unsupportedEncodingException) {
logger.error("error image can not decode:{}", unsupportedEncodingException);
}
// Check if file actually exists in filesystem.
if (!image.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}catch(IOException ioException){
logger.error("error image does not exists:{}", ioException);
} // 404.
return;
}
// Get content type by filename.
String contentType = "jpeg";
contentType="image/"+contentType;
// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open streams.
try {
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
} catch (FileNotFoundException e) {
logger.error("error creating file input stream to the image file :{}", e);
}
try {
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
} catch (IOException e) {
logger.error("error creating output stream to the http response :{}", e);
}
// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
try {
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} catch (IOException e) {
logger.error("error writing the image file to outputstream :{}", e);
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}
// Helpers (can be refactored to public utility class) ----------------------------------------
private void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
logger.error("error closing resources:{}", e);
}
}
}
}
Here are some examples: https://developers.itextpdf.com/examples/xml-worker-itext5/html-images
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() { return "src/main/resources/html/"; }
});
If the HTML file you're parsing is stored in a directory that is different from the working directory, iText won't be able to create Image objects. We have to supply an implementation of the ImageProvider interface that tells iText what to do if an img tag is encountered. This interface has the following methods:
Image retrieve(final String src);
String getImageRootPath();
void store(String src, Image img);
void reset();
You can write your own class implementing these four methods, or you can subclass AbstractImageProvider. It is preferred to do the latter. XML Worker will use the store() method of the AbstractImageProvider class to cache all the Image objects that are encountered in a Map. These objects will be reused when the retrieve() method is called for an image with the same src. If you don't cache images, your PDF will be bloated. The same image bits and bytes will be written to the PDF more than once. The reset() method clears the cache; it is used when an ImageProvider is cloned. Finally, the getImageRootPath() method isn't implemented.
If the HTML file you're parsing is stored in a directory that is different from the working directory, iText won't be able to create Image objects. We have to supply an implementation of the ImageProvider interface that tells iText what to do if an img tag is encountered. This interface has the following methods:
You can write your own class implementing these four methods, or you can subclass AbstractImageProvider. It is preferred to do the latter. XML Worker will use the store() method of the AbstractImageProvider class to cache all the Image objects that are encountered in a Map. These objects will be reused when the retrieve() method is called for an image with the same src. If you don't cache images, your PDF will be bloated. The same image bits and bytes will be written to the PDF more than once. The reset() method clears the cache; it is used when an ImageProvider is cloned. Finally, the getImageRootPath() method isn't implemented. You have to implement it yourself, as is done in the following snippet:
to show image with Itext, you have to Changing the default configuration about Image Provider Like it :
i do it from http://demo.itextsupport.com/xmlworker/itextdoc/flatsite.html
public class HtmlToPDF1 {
public static void main(String ... args ) throws DocumentException, IOException {
FontFactory.registerDirectories();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("src/test/ressources/mypdf.pdf"));
document.open(); HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return "/home/fallphenix/workspace/JAVA/JEE/testHTMLtoPDF/src/test/ressources/";
}
}); CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
Pipeline<?> pipeline =
new CssResolverPipeline(cssResolver,
new HtmlPipeline(htmlContext,
new PdfWriterPipeline(document, writer)));
XMLWorker worker = new XMLWorker(pipeline, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream("src/test/ressources/other.html"));
document.close();
System.out.println("Done.");
}}
Try getting the image into a memory or byte stream object and then cast that image object to an itextsharp image one.
explore the overloads of iTextSharp.text.Image
EDIT:
Although the code is in C#, it might help you.
Get image from your local drive as:
Bitmap image1;
image1 = new Bitmap(#"C:\Documents and Settings\All Users\"
+ #"Documents\My Music\music.jpeg", true);
Note:: If you have the image on your application folder then we have functions to get the local file path of them in C#. Don't know about Java. Images from external site can be downloaded as
System.Net.WebClient client = new WebClient();
client.DownloadFile(imageURL, localPathname); // look into java to get local path
Now convert this byte stream to an image object as
MemoryStream imgMemoryStream = new MemoryStream(imgByteArray);
Image myImage = Drawing.Image.FromStream(imgMemoryStream);
Now acreate an iTextSharp image object from it and add it to your doucment as
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(myImage, System.Drawing.Imaging.ImageFormat.Jpeg);
document.Add(pic);
Hope this helps you.
I also faced to same issue..
but it was working with the image absolute path. it seems not working with remote path.
What id did here is save the image in temp location of file system and generates pdf , finally delete the image file from temp location.
<img src="/home/jboss/temp/imgs/img.png"/>
I was looking for same requirement and this is what worked for me:
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return null;
}
#Override
public Image retrieve(String src) {
try {
Image img = com.itextpdf.text.Image.getInstance(new URL(src));
return Image.getInstance(img);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
Related
I'm trying to write a web app that converts images to PDF file. The user sends a couple of images (JPEG, PNG) and should receive and download a PDF file.
The main problem, for now, is that I don't know how to return the PDF file back to the client.
Here is my controller:
#PostMapping(path = "/upload",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void uploadFiles(#RequestParam("files") MultipartFile[] files) throws IOException {
imageToPdfConversionService.convert(files);
}
This is the service that converts images to PDF file (here I'm using itextpdf library):
public void convert(MultipartFile[] files) throws IOException {
List<ImageData> imagesData = Arrays.stream(files)
.map(file -> {
try {
return ImageDataFactory.create(file.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
// PdfDocument pdfDocument = new PdfDocument(new PdfWriter("ImageToPdf.pdf"));
FileOutputStream fileOutputStream = new FileOutputStream("letspdf-server/src/main/resources/documents/file.pdf");
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(fileOutputStream));
Document document = new Document(pdfDocument);
for (ImageData image : imagesData) {
Image img = new Image(image);
img.setWidth(pdfDocument.getDefaultPageSize().getWidth() - 50);
img.setAutoScaleHeight(true);
document.add(img);
pdfDocument.addNewPage();
}
pdfDocument.close();
}
Also, maybe store a PDF file somewhere and create a 'Download' button on the client-side when a file is generated to download the file from storage?
So first of all you need to change your api to return ResponseEntity and convert your resulted pdf into byte array. I'll attach a code snippet as an example
public static ResponseEntity<Resource> makeResponse(byte[] file, String filename, MultiValueMap<String, String> customHeaders) {
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
HttpHeaders headers = new HttpHeaders();
if (StringUtils.isNotEmpty(filename)) {
try {
mediaType = MediaType.valueOf(MIME_TYPES.detect(filename));
} catch (Exception var6) {
}
ContentDisposition contentDisposition = ContentDisposition.builder("attachment").filename(filename, StandardCharsets.UTF_8).build();
headers.setAccessControlExposeHeaders(ACCESS_CONTROL_EXPOSE_HEADERS);
headers.setContentDisposition(contentDisposition);
}
if (customHeaders != null && !customHeaders.isEmpty()) {
headers.addAll(customHeaders);
}
ByteArrayResource body = null;
if (file != null) {
body = new ByteArrayResource(file);
}
return ((BodyBuilder)ResponseEntity.ok().headers(headers)).contentType(mediaType).body(body);
}
Facing a problem while implementing a java-ws service for downloading a pdf file from another webservice. Below is the piece of code for the same.decode() is used because of the webservice(this java code is invoking) is responding with encoded binary-base-64. I could see the PDF is downloaded in the given location but when i open with pdf reader, it says the file is corrupt. Could you please help me ?
public DownloadFileResponse DownloadResponseMapper(Header header, DownloadDocumentResponseType response){
DownloadFileResponse result = new DownloadFileResponse();
result.setHeader(header);
Status status = new Status();
status.setStatusCode(String.valueOf(String.valueOf(response.getStatus().getStatusCode())));
status.setStatusMessage(response.getStatus().getMessage());
result.setStatus(status);
if(String.valueOf(String.valueOf(String.valueOf(response.getStatus().getStatusCode()))) != "0") {
String qNameFile = FileExchange.getProperty("fileSystem.sharedLocation") + "/" + "result.pdf";
try {
byte[] fileContent = FileUtil.decode(response.getFile());
System.out.println(response.getFile());
FileUtil.writeByteArraysToFile(qNameFile, fileContent);
} catch (Exception e) {
_logger.info(e.getStackTrace());
}
// calculate the hash of the file using two algorithm SHA-256/SHA-512
List<FileHashType> hashes = FileUtil.calculateHash(result.getFile());
result.setFileHash(hashes);
}
return result;
}
public static void writeByteArraysToFile(String fileName, byte[] content) throws IOException {
File file = new File(fileName);
BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(file));
writer.write(content);
writer.flush();
writer.close();
}
I am converting html to ppt using aspose java library. But, I couldn't generate styles like (padding,background-color,etc) whereas styles like(color,font-size) are working just fine,have a look at the code..
public class poi {
public static void main(String[] args) throws Exception {
// The path to the documents directory.
String dataDir = Utils.getDataDir(poi.class);
// Create Empty presentation instance
Presentation pres = new Presentation();
// Access the default first slide of presentation
ISlide slide = pres.getSlides().get_Item(0);
// Adding the AutoShape to accommodate the HTML content
IAutoShape ashape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 50, 150, 300, 150);
ashape.getFillFormat().setFillType(FillType.NoFill);
// Adding text frame to the shape
ashape.addTextFrame("");
// Clearing all paragraphs in added text frame
ashape.getTextFrame().getParagraphs().clear();
// Loading the HTML file using InputStream
InputStream inputStream = new FileInputStream(dataDir + "file.html");
Reader reader = new InputStreamReader(inputStream);
int data = reader.read();
String content = ReadFile(dataDir + "file.html");
// Adding text from HTML stream reader in text frame
ashape.getTextFrame().getParagraphs().addFromHtml(content);
// Saving Presentation
pres.save(dataDir + "output.pptx", SaveFormat.Pptx);
}
public static String ReadFile(String FileName) throws Exception {
File file = new File(FileName);
StringBuilder contents = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String text = null;
// repeat until all lines is read
while ((text = reader.readLine()) != null) {
contents.append(text).append(System.getProperty("line.separator"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
return contents.toString();
}
}
As you can see I am loading the html file which has inline styling, but I couldn't quite make most of the css elements to load. Any suggestions?
#Balchandar Reddy,
I have observed your requirements and like to share that at present Aspose.Slides support basic text import along with limited tag support in presentations generated using Aspose.Slides. I request you to please share the required HTML with desired tags for which you intend to have support in Aspose.Slides. I will discuss that with our product team and will add that as new feature request in our issue tracking system.
I am working as Support developer/ Evangelist at Aspose.
I've a desktop java application that get images from the user clipboard ("paste" action), and I need to check their mime type before further processing (only jpg, png and gif are admitted).
I'm using this code to get the image from the clipboard:
Transferable transferable = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if (transferable != null && transferable.isDataFlavorSupported(DataFlavor.imageFlavor)) {
try {
Image pastedImage = (Image) transferable.getTransferData(DataFlavor.imageFlavor);
// how to get mime type?
} catch (Exception e) {/*cutted for brevity*/}
}
Now, I know how to get the mime type from a file using apache Tika and I've tried writing the image to disk in order to reuse this technique, but also the ImageIO.write method requires a format name:
BufferedImage bi = convertImageToBI(img);
File outputfile = File.createTempFile("img_", "_upload");
ImageIO.write(bi, "jpg", outputfile);
To convert an image to a BufferedImage I'm using this method. The only difference is that I'm using TYPE_INT_RGB instead of TYPE_INT_ARGB.
How can I get the pasted image's mime type?
I tried a crazy approach to check whether it's JPG/GIF or PNG. When there's transparency, I use PNG, other than that I always use JPG, and this proven to work also with GIF, just the GIF lost it's animation tho
protected BufferedImage img;
protected void loadImage() {
try {
// Well we read the temp file first, I test it using local file
File f = new File(loc);
// Read the file as Image
this.img = ImageIO.read(f);
} catch(Exception e) {
JOptionPane.showMessageDialog(this, e.getMessage());
}
this.revalidate();
this.repaint();
}
public byte[] toBlob() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// Check if this image contains transparency? If no then write as JPG
if (this.img.getTransparency() == java.awt.Transparency.OPAQUE) {
ImageIO.write((BufferedImage)this.img, "jpg", baos);
} else { // If it does contain transparency then write as PNG
ImageIO.write((BufferedImage)this.img, "png", baos);
}
} catch(Exception e) {
JOptionPane.showMessageDialog(this, e.toString());
}
byte[] data = baos.toByteArray();
return data;
}
public void saveImageToBlob(String location) {
try {
File f = new File(location);
FileOutputStream o = new FileOutputStream(f);
byte[] d = this.toBlob();
o.write(d, 0, d.length);
o.close();
} catch(Exception e) {
JOptionPane.showMessageDialog(this, e.toString());
}
}
Here is a snippet of my Servlet code which generates a PDF and then opens it. It can not open the "AvtoSolaZaposleniXSL.xsl" file. If I run the same procedure in a normal Java class everything runs smooth.
public class PDF extends HttpServlet {
private static final long serialVersionUID = 1L;
public PDF() { super(); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Generiraj PDF
File xmlfile = new File(getServletContext().getRealPath("AvtoSolaZ.xml"));
File xsltfile = new File(getServletContext().getRealPath("AvtoSolaZaposleniXSL.xsl"));
ExampleXML2PDF.generirajPDF(xmlfile, xsltfile);
//Počakaj da se v miru zgenerira PDF
try {
Thread.sleep(5000L);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//Zaženi pdf
File f1 = new File(getServletContext().getRealPath("Avtosola.pdf"));
String pdfKoncni = f1.toString();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(pdfKoncni);
PdfStamper stamper = null;
try {
stamper = new PdfStamper(reader, baos);
} catch (DocumentException e) {
e.printStackTrace();
}
try {
stamper.close();
} catch (DocumentException e) {
e.printStackTrace();
}
// set some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentType("application/pdf");
response.setContentLength(baos.size());
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
}
All my files are in the WebContent folder and my Servlet in a default package.
Error:
(Location of error unknown)java.io.FileNotFoundException: C:\Eclipse\eclipse\WebContent\AvtoSolaZaposleniXSL.xsl (The system cannot find the file specified)
java.lang.NullPointerException
Believe me that I have searched for an answer like this and haven't found anything that could actually help me. Even if I put the whole path (Which is not C:\Eclipse\eclipse... and I don't know why it states that way..) it still does not work.
Like I said. If I run it in a normal Java class it generates the PDF normally and works just fine...
import java.io.File;
public class Test {
public static void main(String[] args) {
File xmlfile = new File("WebContent/AvtoSolaZ.xml");
File xsltfile = new File("WebContent/AvtoSolaZaposleniXSL.xsl");
ExampleXML2PDF.generirajPDF(xmlfile, xsltfile);
}
}
Please help!
Server referring to absolute path to read the file.
So here in your case .. put your file under projectRootName/AvtoSolaZaposleniXSL.xsl.
It will work.
I re-thinked my problem and came up with an easier solution on how to display a pdf which was generated. I just used my class, which generates a pdf(XSL-FO transformation, for which an xml and xsl is needed..) and copied the code into the servlet. Adjusted the output stream and voula!
Here is the code of the new servlet which works perfectly fine:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
response.setContentType("application/pdf");
// Setup directories
File xmlfile = new File(getServletContext().getRealPath("/AvtoSolaZ.xml"));
File xsltfile = new File(getServletContext().getRealPath("/AvtoSolaZaposleniXSL.xsl"));
File outDir = new File("WebContent");
outDir.mkdirs();
// configure fopFactory as desired
FopFactory fopFactory = FopFactory.newInstance();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup output
OutputStream out = response.getOutputStream();
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory
.newTransformer(new StreamSource(xsltfile));
// Set the value of a <param> in the stylesheet
transformer.setParameter("versionParam", "2.0");
// Setup input for XSLT transformation
Source src = new StreamSource(xmlfile);
// Resulting SAX events (the generated FO) must be piped through
// to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}