I am trying to build a rather crude tool that converts a ppt/pptx file to a HTML format.
I have found out that, unfortunately, apache poi does not provide a unified programming model for working with power point files and code has to be written for parsing each format.
I feel that the pptx file support is much more limited than the ppt support.
One problem I'm facing is getting information regarding the background (color, pattern, background image) of a pptx slide.
I find the XSLFBackground (pptx api) class to be much more limited than its corresponding Background class (ppt api).
Has anyone managed to get get information regarding the background of a pptx slide using apache poi ?
Also can someone please point me to some good resources on this subject. I find the apache poi javadoc almost unusable and the examples on the poi website only cover basic functionality.
Best regards, Sergiu
The content of the background element is described in the Office Open Schema - check the zip-link at the bottom and the pml-slide.xsd inside.
With the schema in the hand you will understand the XML beans below the usermodel interface.
For a starter, here is an example of reading a background image and also of exporting the slides to pngs (maybe useful for your html export?):
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import org.apache.poi.xslf.usermodel.*;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
public class PptxBackground {
public static void main(String[] args) throws Exception {
// sorry for the content, but it was one of the first non-commercial google matches ...
URL url = new URL("http://newkilpatrickblog.typepad.com/files/sunday_june_03_2012_trinity_and_majesty_communion.pptx");
InputStream is = url.openStream();
XMLSlideShow ss = new XMLSlideShow(is);
is.close();
XSLFSlide sld = ss.getSlides()[0];
XSLFBackground bg = sld.getBackground();
CTBackground xmlBg = (CTBackground)bg.getXmlObject();
String relId = xmlBg.getBgPr().getBlipFill().getBlip().getEmbed();
XSLFPictureData pic = (XSLFPictureData)sld.getRelationById(relId);
String filename = pic.getFileName();
byte fileBytes[] = pic.getData();
/***** or convert the slides to images ****/
double zoom = 2; // magnify it by 2
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
Dimension pgsize = ss.getPageSize();
XSLFSlide slides[] = ss.getSlides();
for (int i = 0; i < slides.length; i++) {
BufferedImage img = new BufferedImage((int)Math.ceil(pgsize.width*zoom), (int)Math.ceil(pgsize.height*zoom), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setTransform(at);
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
slides[i].draw(graphics);
FileOutputStream out = new FileOutputStream("slide-" + (i+1) + ".png");
javax.imageio.ImageIO.write(img, "png", out);
out.close();
}
}
}
Related
i try to write a java program, which converts the pptx to jpeg images. There are many options (e.g., aspose, groupdocs, cloudmersive). But they are limited (either generating images in the evaluation mode or limited by the number of API calls); i prefer an open source library and up till now, i have known 2 libreries which are Apache POI and Docx4j. By using the Apache POI, i was able to implement the conversion PPTX-JPEG; however, the generated images' quality is low even the rendering parameters were set.
// create an empty presentation
public static void Pptx_Img(String slidePath, String outputDir, String fileName) throws Exception {
// create an empty presentation
File file = new File(slidePath);
FileInputStream in = new FileInputStream(file);
XMLSlideShow ppt = new XMLSlideShow(in);
// get the dimension and size of the slide
Dimension pgsize = ppt.getPageSize();
List<XSLFSlide> slides = ppt.getSlides();
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
BufferedImage img = null;
outputDir = outputDir + "\\apache\\pptx\\" + fileName;
Apache.createDirIfNotExists(outputDir);
for (int i = 0; i < 10; i++) {
img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setRenderingHint(Drawable.BUFFERED_IMAGE, new WeakReference<>(img));
// clear area
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
// draw the images
slides.get(i).draw(graphics);
FileOutputStream out = new FileOutputStream(outputDir + "\\slide_" + i + ".jpg");
/*
// specifies where the jpg image has to be written
final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
writer.setOutput(ImageIO.createImageOutputStream(out));
// writes the file with given compression level
writer.write(null, new IIOImage(img, null, null), jpegParams);
*/
ImageIO.write(img, "jpeg", out);
ppt.write(out);
graphics.dispose();
out.close();
img.flush();
}
System.out.println("Images successfully created");
in.close();
ppt.close();
}
Comparison between the original slide and the generated images
I also came up with another indirect way, which converts pptx-pdf-jpeg (because i have the implementation for conversion pdf-jpeg and the conversion can actually maintain the image quality). But i couldnt find any open source libs which can do the conversion pptx-jpeg. For Apache POI, it can convert pptx-pdf but the mechanism is just similar to pptx-jpeg: writes the Graphic2D-instance to pdf instead of jpeg, which basically does not improve the rendering quality.
Added: Regarding to the comparison, the wrong rendering is also another issue !
I am able to open a 3DS file in MeshLab and when I export to Collada DAE format the textures are visible but they are not being projected onto the mesh in the same way as the preview in MeshLab. For example, the front/back faces of a cube would have the proper texture (suppose it's a polka dot) but the top and bottom have a striped look. How can I apply a single texture and have it appear as intended on all faces, like the imported model before I convert it?
This problem is a result of the end software being used to view the DAE file. It's not a problem with MeshLab.
For example, if loading the file into Away3D be sure to handle the texture materials using the TextureMaterial class instead of the simpler SinglePassMaterialBase such as what you might find in their example code. Here is what I use now, and it displays texture properly:
var material:TextureMaterial = cast(asset, TextureMaterial);
material.ambientColor = 0xffffff;
material.lightPicker = _lightPicker;
material.shadowMethod = new FilteredShadowMapMethod(_light);
material.lightPicker = _lightPicker;
material.gloss = 30;
material.specular = 1;
material.ambient = 1;
material.repeat = true;
I am using the wonderful twelve monkeys library to create TIFF files, but I am having a problem setting the image resolution units to inches. I have spent 2 days researching both Google and the twelve monkeys source code, without success. I am hoping that someone else knows how to solve this. This is the simplified code:
final BufferedImage bufferedImage = someImage;
final int dpi = 300;
final String filePath = someFilePath;
final ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ImageOutputStream output = ImageIO.createImageOutputStream(buffer);
writer.setOutput(output);
final double resolution = dpi / 10.0; // --- This is a hack (possibly a MM/CM conversion)
final String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
final IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(bufferedImage),null);
final IIOMetadataNode customMetadata = new IIOMetadataNode(standardFormat);
final IIOMetadataNode dimensionMetadataNode = new IIOMetadataNode("Dimension");
customMetadata.appendChild(dimensionMetadataNode);
final IIOMetadataNode horizontalMetadataNode = new IIOMetadataNode("HorizontalPixelSize");
dimensionMetadataNode.appendChild(horizontalMetadataNode);
horizontalMetadataNode.setAttribute("value",String.valueOf(resolution));
final IIOMetadataNode verticalMetadataNode = new IIOMetadataNode("VerticalPixelSize");
dimensionMetadataNode.appendChild(verticalMetadataNode);
verticalMetadataNode.setAttribute("value",String.valueOf(resolution));
metadata.mergeTree(standardFormat,customMetadata);
final IIOImage iioImage = new IIOImage(bufferedImage,null,metadata);
writer.write(null,iioImage,params);
final File file = new File(filePath);
final FileOutputStream fos = new FileOutputStream(file);
buffer.writeTo( fos );
This code creates a TIFF file which ImageMagick reports as:
Resolution: 300x300
Print size: 8.26667x11.6933
Units: PixelsPerCentimeter
And yet com.twelvemonkeys.imageio.plugins.tiff.TIFFBaseline states:
int RESOLUTION_UNIT_NONE = 1;
int RESOLUTION_UNIT_DPI = 2; // Default
int RESOLUTION_UNIT_CENTIMETER = 3;
I know that I could exec ImageMagick from Java to set the required resolution units, but that is something of a hack and it would be much better to simply generate Tiff file data with the correct resolution unit from my Java code.
If my question is foolish (or I have been stupid), I apologise in advance. I would welcome any help. Thank-you.
I'm trying to use Apache poi word 3.8 to create word document in persian/arabic language.
My question is: how change text direction in document? ( it means changing text direction not changing just paragraph text alignment)
In MS Word we could use Right-to-left text direction to change text direction and Align Right to set alignment. What’s equivalent of the first one in poi set property?
This is bidirectional text direction support (bidi) and is not yet implemented in apache poi per default. But the underlying object org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPrBase supports this. So we must get this underlying object from the XWPFParagraph.
Example:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
public class CreateWordRTLParagraph {
public static void main(String[] args) throws Exception {
XWPFDocument doc= new XWPFDocument();
XWPFParagraph paragraph = doc.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("Paragraph 1 LTR");
paragraph = doc.createParagraph();
CTP ctp = paragraph.getCTP();
CTPPr ctppr;
if ((ctppr = ctp.getPPr()) == null) ctppr = ctp.addNewPPr();
ctppr.addNewBidi().setVal(STOnOff.ON);
run = paragraph.createRun();
run.setText("السلام عليكم");
paragraph = doc.createParagraph();
run = paragraph.createRun();
run.setText("Paragraph 3 LTR");
FileOutputStream out = new FileOutputStream("WordDocument.docx");
doc.write(out);
out.close();
doc.close();
}
}
I'm trying to create a new PDF file using iText, and the new file should be composed of pages that are generated from an area within an SVG file (tile). And each generated page needs to have a 'drawing border' superimposed upon it, so that it appears as the top layer of each generated page. I think the superimposing can be achieved with the iText stamper, but examples I see work only with an existing PDF, which I don't have as I want to do all this on-the-fly to reduce the time required to generate the resulting PDF. I have a one page PDF file that represents the PDF layer to superimpose upon each page generated in the PDF.
I found an example on the net that divides the SVG canvas into tiles and creates separate PDF files from each tile. However, creating intermediate PDF files wastes time, as I need to read them in again to create the file I am trying to create (with the superimposed layer for each page).
I don't want to dump loads of code here, but here is the code sample that I used to generate one page PDF files for each SVG tile:
http://people.apache.org/~clay/batik/rasterizerTutorial.pdf (see page 5: SaveAsJPEGTiles.java)
As I am an iText newbie, maybe someone here has achieved something similar, or knows how to do this?
Thanks.
I'm using a ByteArrayOutputStream instead of the FileOutputStream, but when I try to combine this with iText's Document type, I keep getting an exception saying no pages in document - see code below. I think I need to add the ByteArrayOutputStream for each tile to the iText document so that it creates a new page for each tile, but I can't see how to do that from the iText API. Here's my code so far, but doesn't quite work:
package examples.aoi;
import java.io.*;
import java.awt.*;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.fop.svg.PDFTranscoder;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
public class FromCanvasToPDFPages {
PDFTranscoder trans = new PDFTranscoder();
public FromCanvasToPDFPages() {
}
public void tile(TranscoderInput input, TranscoderOutput output, Rectangle aoi) throws Exception {
trans.addTranscodingHint(PDFTranscoder.KEY_WIDTH, new Float(aoi.width));
trans.addTranscodingHint(PDFTranscoder.KEY_HEIGHT, new Float(aoi.height));
trans.addTranscodingHint(PDFTranscoder.KEY_AOI, aoi);
trans.transcode(input, output);
}
public static void main(String [] args) throws Exception {
FromCanvasToPDFPages p = new FromCanvasToPDFPages();
String in = "C:\\Documents and Settings/krell/My Documents/1.svg";
String svgURI = new File(in).toURL().toString();
TranscoderInput input = new TranscoderInput(svgURI);
String outputFilename = "canvasPages.pdf";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(baos);
int A4_landscape_width = 1103; // use proper dimensions from class when found
int A4_landscape_height = 780; // use proper dimensions from class when found
int documentWidth = 3309; // read this directly from canvas file (svg)
int documentHeight = 1560; // read this directly from canvas file (svg)
int columns = documentWidth / A4_landscape_width;
int rows = documentHeight / A4_landscape_height;
int tile_width = A4_landscape_width;
int tile_height = A4_landscape_height;
System.err.println(">>> Canvas document width = "+documentWidth);
System.err.println(">>> Canvas document height = "+documentHeight);
System.err.println(">>> A4 width = "+A4_landscape_width);
System.err.println(">>> A4 height = "+A4_landscape_height);
System.err.println(">>> canvas columns = "+columns);
System.err.println(">>> canvas rows = "+rows);
System.err.println(">>> tile_width = "+tile_width);
System.err.println(">>> tile_height = "+tile_height);
// Create A4 document to write tile data into
Document document = new Document(PageSize.A4_LANDSCAPE, 10, 10, 10, 10);
PdfWriter writer = PdfWriter.getInstance(document, baos);
// open the document
document.open();
// now process each tile, row by row, column by column until done
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
// get tile coordinates
Rectangle tile = new Rectangle(column*tile_width, row*tile_height, (column+1)*tile_width, (row+1)*tile_height);
p.tile(input, output, tile);
}
}
// now write the baos to disk:
OutputStream fileOutputStream = new FileOutputStream(outputFilename);
baos.writeTo(fileOutputStream);
// close stuff
fileOutputStream.flush();
fileOutputStream.close();
document.close();
baos.close();
System.exit(0);
}
}