is there a way to automatically compress/optimize images in a spring-boot-application?
As in my application the user can put any images in a folder themselves, I cannot make sure, they are compressed the best way. And as they are not uploaded through the application, I can also not create an optimized version.
So what I would like to do is to compress/optimize the images once they are requested and maybe save them in a kind of "image-cache" for a while.
Or is there a tomcat/apache-module, which already does this kind of things out-of-the box?
Thanks for your help
You can use javax.imageio's classes and interface to compress a given image. Below is an example of image compression of JPG image. You can add the below main method code to your service in spring boot application.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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 ImageCompression {
public static void main(String[] args) throws FileNotFoundException, IOException{
File imageFile = new File("YOUR_IMAGE.jpg");
File compressedImageFile = new File("YOUR_COMPRESSED_IMAGE.jpg");
InputStream inputStream = new FileInputStream(imageFile);
OutputStream outputStream = new FileOutputStream(compressedImageFile);
float imageQuality = 0.3f;
//Create the buffered image
BufferedImage bufferedImage = ImageIO.read(inputStream);
//Get image writers
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("jpg");
if (!imageWriters.hasNext())
throw new IllegalStateException("Writers Not Found!!");
ImageWriter imageWriter = (ImageWriter) imageWriters.next();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
//Set the compress quality metrics
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(imageQuality);
//Created image
imageWriter.write(null, new IIOImage(bufferedImage, null, null), imageWriteParam);
// close all streams
inputStream.close();
outputStream.close();
imageOutputStream.close();
imageWriter.dispose();
}
}
Related
Some background: in my app, there are some pdf reports. But, these pdf reports need to be "image" based and I was told that the report server is unable to do this. The call to the report server is done from a pl/sql procedure and the result is a blob, so now all I have at my disposal to try to do this conversion is a java stored procedure. Here is what I came up with (using Apache PDFBox):
create or replace and compile java source named "APDFUtil"
as
import oracle.sql.*;
import oracle.jdbc.driver.*;
import java.sql.*;
import oracle.sql.BLOB;
import java.sql.Blob;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.*;
import java.util.*;
import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.rendering.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import java.awt.image.BufferedImage;
public class APDFUtil{
static OracleDriver ora = new OracleDriver();
static Connection conn;
static ByteArrayOutputStream out;
static {
try {
conn = ora.defaultConnection();
} catch (Exception ex) {}
}
public static oracle.sql.BLOB flattenPDF (oracle.sql.BLOB value) throws Exception {
if (conn == null) conn = ora.defaultConnection();
BLOB retBlob = BLOB.createTemporary(conn, true, oracle.sql.BLOB.DURATION_SESSION);
/*BEGIN TO_JPG*/
InputStream inputStream = value.getBinaryStream();
PDDocument document = PDDocument.load(inputStream);
PDFRenderer pdfRenderer = new PDFRenderer(document);
int noOfPages = document.getNumberOfPages();
BufferedImage[] pdfJPEG = new BufferedImage[noOfPages];
for (int page = 0; page < noOfPages; ++page) {
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
pdfJPEG[page] = bim;
}
/*write images to new pdf*/
PDDocument documentOut = new PDDocument();
for (int page = 0; page < noOfPages;++page) {
/*get page from old document to determine width and height*/
PDPage oldPage = document.getPage(page);
Float pw = oldPage.getMediaBox().getWidth();
Float ph = oldPage.getMediaBox().getHeight();
PDRectangle rec = new PDRectangle(pw,ph);
PDPage newPage = new PDPage(rec);
documentOut.addPage(newPage);
PDImageXObject pdImage = LosslessFactory.createFromImage(documentOut, pdfJPEG[page]);
PDPageContentStream contents = new PDPageContentStream(documentOut, newPage);
contents.drawImage(pdImage, 0, 0,pw,ph);
contents.close();
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
documentOut.save(out);
documentOut.close();
document.close();
/*END OF TO_JPG*/
/*out - we used to get this back from TO_JPG*/
try {
java.io.OutputStream outStr = retBlob.setBinaryStream(0);
outStr.write(out.toByteArray());
outStr.flush();
} finally {
out.close();
}
return retBlob;
}
}
the pdfbox jars have been loaded into the database
database is oracle 19c standard edition 2 release 19.0.0.0.0
I tried this code as a standalone java project with the exception that the pdf file is being read from the disk, and new file written to the disk and there it works flawlessly.
The issue:
I believe the problem starts at this line: BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
but I don't know what is causing the error or how to debug it (I came to this conclusion by a painstaking process of elimination of code and throwing exceptions) especially since it works in a standalone project. Java stored procedures are not a specialty of mine and this code was pieced together from many different sources online.
Good evening
I want to fill in the jpg photo file windows properties
Apparently these are the exiftags
[Exif IFD0] Windows XP Title
[Exif IFD0] Windows XP Author
[Exif IFD0] Windows XP Subject
I looked at the side of icafe.jar but have not found these tags.
Can I make it with icafe or other jar library ?
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import com.icafe4j.image.meta.Metadata;
import com.icafe4j.image.meta.exif.Exif;
import com.icafe4j.image.meta.jpeg.JpegExif;
import com.icafe4j.image.meta.exif.ExifTag;
import com.icafe4j.image.tiff.TiffTag;
import com.icafe4j.image.tiff.FieldType;
fin = new FileInputStream(Fm_filePathIn);
fout = new FileOutputStream(Fm_filePathOut);
List<Metadata> metaList = new ArrayList<Metadata>();
metaList.add(populateExif(JpegExif.class));
Exif populateExif(Class<?> exifClass) throws IOException {
Exif exif = new JpegExif();
exif.addImageField(ExifTag.WINDOWS_XP_AUTHOR, FieldType.WINDOWSXP, "Toto");
exif.addImageField(ExifTag.WINDOWS_XP_KEYWORDS, FieldType.WINDOWSXP, "Copyright;Authorbisou");
// Insert ThumbNailIFD
// Since we don't provide thumbnail image, it will be created later from the input stream
exif.setThumbnailRequired(true);
return exif;
}
fin.close();
fout.close();
Those tags do exist in ICAFE but they are not Exiftag. They are TiffTag. Replace the ExifTag with TiffTag, it will work. Look at the TestMetada.java, it clearly shows that.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.icafe4j.image.meta.Metadata;
import com.icafe4j.image.meta.exif.Exif;
import com.icafe4j.image.meta.jpeg.JpegExif;
import com.icafe4j.image.meta.exif.ExifTag;
import com.icafe4j.image.tiff.TiffTag;
import com.icafe4j.image.tiff.FieldType;
public class TestWindowsXP {
public static void main(String[] args) throws IOException {
FileInputStream fin = new FileInputStream(Fm_filePathIn);
FileOutputStream fout = new FileOutputStream(Fm_filePathOut);
List<Metadata> metaList = new ArrayList<Metadata>();
Exif exif = new JpegExif();
exif.addImageField(TiffTag.WINDOWS_XP_AUTHOR, FieldType.WINDOWSXP, "Toto");
exif.addImageField(TiffTag.WINDOWS_XP_KEYWORDS, FieldType.WINDOWSXP, "Copyright;Authorbisou");
// Insert ThumbNailIFD
// Since we don't provide thumbnail image, it will be created later from the input stream
exif.setThumbnailRequired(true);
metaList.add(exif);
Metadata.insertMetadata(metaList, fin, fout);
fin.close();
fout.close();
}
}
And the following is a screenshot when I right-click the resulting image->show properties. You can see the information you wanted to insert is showing.
Description:
ouput: pdf file
input : index.css, bootstrap.min.css, index.html
Problem: if i use index.css file without bootsrap its working fine, but when i use boot strap its throw exception.
CODE is here:
package test.test1;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.codec.Charsets;
import com.google.common.io.CharStreams;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.Pipeline;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.css.CssFile;
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
public class Table {
File oFile = new File("c:\\test\\1.pdf");
Document document = new Document(PageSize.A4, 0, 0, 0, 0);
PdfWriter writer =null;
public Table() throws IOException, DocumentException {
oFile.createNewFile();
writer=PdfWriter.getInstance(document,new FileOutputStream(oFile));
InputStream htmlpathtest = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("index.html");
String htmlstring = CharStreams.toString(new InputStreamReader(htmlpathtest, Charsets.UTF_8));
InputStream is = new ByteArrayInputStream(htmlstring.getBytes());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, baos);
writer.setInitialLeading(12.5f);
document.open();
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
// CSS
CSSResolver cssResolver = new StyleAttrCSSResolver();
InputStream csspathtest = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("css\\index.css");
InputStream csspathtest1 = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("css\\bootstrap.min.css");
CssFile cssfiletest = XMLWorkerHelper.getCSS(csspathtest);
cssResolver.addCss(cssfiletest);
cssResolver.addCss(XMLWorkerHelper.getCSS(csspathtest1));
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(is);
document.close();
}
public static void main(String[] args) throws IOException, DocumentException { new Table();}
}
Exception:
Exception in thread "main" java.lang.NumberFormatException: For input
string: "100%" at
sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
at java.lang.Float.parseFloat(Float.java:422) at
com.itextpdf.tool.xml.css.FontSizeTranslator.getFontSize(FontSizeTranslator.java:186)
at
com.itextpdf.tool.xml.css.FontSizeTranslator.translateFontSize(FontSizeTranslator.java:165)
at
com.itextpdf.tool.xml.html.AbstractTagProcessor.startElement(AbstractTagProcessor.java:120)
at
com.itextpdf.tool.xml.pipeline.html.HtmlPipeline.open(HtmlPipeline.java:105)
at com.itextpdf.tool.xml.XMLWorker.startElement(XMLWorker.java:103)
at
com.itextpdf.tool.xml.parser.XMLParser.startElement(XMLParser.java:372)
at
com.itextpdf.tool.xml.parser.state.TagEncounteredState.process(TagEncounteredState.java:104)
at
com.itextpdf.tool.xml.parser.XMLParser.parseWithReader(XMLParser.java:237)
at com.itextpdf.tool.xml.parser.XMLParser.parse(XMLParser.java:215)
at com.itextpdf.tool.xml.parser.XMLParser.parse(XMLParser.java:188)
at test.test1.Table.(Table.java:95) at
test.test1.Table.main(Table.java:104)
AFAIK CSS support from the itext HTML renderer is very limited. I've recently used a more complete HTML to PDF library called flying-saucer that supports CSS2 and some CSS3 features. flying-saucer uses itext as backend. You should give it a go - it might not support all bootstrap features but may be able to still fulfill your requirements.
Is there any way to convert generated .ppt file using apache poi to .pdf file?
OR
Any way to convert PPT file to PDF file using JAVA?
Gagravarr, thanks you for your comment with following approach: PPT -> images -> PDF. It gave me clues for further solutions.
Recently, I've faced the same task: convert PPT reports into PDF reports using Java facilities. PPT reports are generated via Apache POI lib, and I intended to reuse ready created PPT structure.
I developed two solutions, each has its own advantages/disadvantages. And both of them using iText library with version 2.1.7.(which is free to use, and which is great)). Both of them do support Japanese symbols after additional enhancement.
1. Apache POI Slide -> image -> PDF
Demonstration code example:
package com.test.pdf;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfWriter;
public class PPTtoImageToPDFexample {
public static void main(String[] args) throws IOException, DocumentException {
//load any ppt file
FileInputStream inputStream = new FileInputStream("d:/temp/initialPPT.ppt");
SlideShow ppt = new SlideShow(inputStream);
inputStream.close();
Dimension pgsize = ppt.getPageSize();
//take first slide and save it as an image
Slide slide = ppt.getSlides()[0];
BufferedImage img = new BufferedImage(pgsize.width, pgsize.height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width,
pgsize.height));
slide.draw(graphics);
FileOutputStream out = new FileOutputStream("d:/temp/slideImage.png");
javax.imageio.ImageIO.write(img, "png", out);
out.close();
//get saved slide-image and save it into pdf
Image slideImage = Image.getInstance("d:/temp/slideImage.png");
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("d:/temp/PPTtoImageTest.pdf"));
document.setPageSize(new Rectangle(slideImage.getWidth(), slideImage.getHeight()));
document.open();
slideImage.setAbsolutePosition(0, 0);
document.add(slideImage);
document.close();
}
}
2. This approach works on-fly: take Apache POI Slide -> get awt.Graphics2 instance from it -> pass this interface to the iText
draw engine.
Demonstration code example:
package com.test.pdf;
import java.awt.Dimension;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfGraphics2D;
import com.lowagie.text.pdf.PdfWriter;
public class PPTtoPDFdirectly {
public static void main(String[] args) throws IOException, DocumentException {
//load any ppt file
FileInputStream inputStream = new FileInputStream("d:/temp/initialPPT.ppt");
SlideShow ppt = new SlideShow(inputStream);
inputStream.close();
Dimension pgsize = ppt.getPageSize();
//take first slide and draw it directly into PDF via awt.Graphics2D interface.
Slide slide = ppt.getSlides()[0];
Document document = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("d:/temp/PPTtoPDF.pdf"));
document.setPageSize(new Rectangle((float)pgsize.getWidth(), (float) pgsize.getHeight()));
document.open();
PdfGraphics2D graphics = (PdfGraphics2D) pdfWriter.getDirectContent().createGraphics((float)pgsize.getWidth(), (float)pgsize.getHeight());
slide.draw(graphics);
graphics.dispose();
document.close();
}
}
One option is to use POI to convert each slide into an image, then use something like Apache PDFBox to place each image onto it's own PDF page. This should work well for simpler PPT files, but the code to render slides is still a WIP. So, if you have a very complex slide, you may find some bits missing/incorrect, do send in patches if you fix any of these gaps!
Otherwise, your other option is to use the Java bindings for OpenOffice, and have that do the conversion for you
Hi I have created a PDF file with an image in it, I want to print my pdf after creating. Better if I have the PDF in memory instead of having a file, and then send it to the printer... Any Idea ?
I am using iText. Check my code:
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPrinterGraphics2D;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
private boolean exportToPdfThroughPNG(String fileName, float width, float height) throws DocumentException, IOException {
logger.debug("[boolean exportToPdfQuick() throws IOException, DocumentException]");
BufferedImage pngFile = createPngFile();
Document document = new Document();
document.setPageSize(new Rectangle(width, height));
PdfWriter.getInstance(document, new FileOutputStream(fileName));
document.open();
Image image = Image.getInstance(Toolkit.getDefaultToolkit().createImage(pngFile.getSource()), Color.WHITE);
document.add(image);
// If some day anyone wants to put text in the pdf. #Eduardo
// document.add(new Paragraph("title of the process"));
document.close();
return true;
}
Thanks in advance!
You can always use a ByteArrayOutputStream instead of a FileOutputStream.
After you have the PDF bytes, its a normal "how do you print in Java" question. Many printers (or at least their drivers) will take PDF directly these days, so at that point one could argue that you're done.
PS: Once I tagged your question "Java" it colored your code block using "import" as a keyword and so forth. Something to keep in mind in the future.