Code: Select all
package pdfcm;
import java.util.List;
import com.sun.star.beans.PropertyValue;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XStorable;
import com.sun.star.io.IOException;
import com.sun.star.util.XCloseable;
import com.sun.star.lang.XComponent;
import com.sun.star.util.CloseVetoException;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import ooo.connector.BootstrapSocketConnector;
/**
* PDF conversion and merge class.
*
* This class depends on the following software being installed and configured:
*
* -- Open Office version 2.3.0 or better
* (Previous 2.X versions may work, but they have not been tested.)
* Latest version of Open Office can be obtained at http://www.openoffice.org
* (Tested with 2.3.0, 2.4.0)
*
* -- Ghostscript version 8.6.1 or better
* (Previous versions may work if they support the command line options found below.)
* Latest version of Ghostscript can be obtained at http://pages.cs.wisc.edu/~ghost/
* (Tested with 8.6.1)
*
* -- Bootstrap connector jarfile
* The library distributed with this code already contains the bootstrap
* connector. In case it needs to be updated, or if you wish to leave a
* "Thank-you", it was originally obtained at
* http://user.services.openoffice.org/en/forum/viewtopic.php?f=44&t=2520
*
* @author Gregory Edwin Graham
*/
public class PDFConvert {
/**
* Returns true if the string array contains the given string.
*
* @param arr An input array of strings
* @param val A particular string to look for
* @return true if the array contains an instance of the string, or false
*/
public static boolean StringArrayContains(String[] arr, String val) {
boolean retval = false;
if (arr != null && val != null) {
for (int i = 0; i < arr.length; i++) {
if (val.contentEquals(arr[i])) {
retval = true;
break;
}
}
}
return retval;
}
protected String[] writerTypes = null;
/**
* Returns the file extensions that get mapped to the OpenOffice writer filter
*
* @return The file extensions that get mapped to the OpenOffice writer filter
*/
public String[] getWriterTypes() {
return writerTypes;
}
/**
* Sets the file extensions that get mapped to the OpenOffice writer filter
*
* @param types The file extensions that get mapped to the OpenOffice writer filter
*/
public void SetWriterTypes(String[] types) {
writerTypes = types;
}
protected String[] calcTypes = null;
/**
* Returns the file extensions that get mapped to the OpenOffice calc filter
*
* @return The file extensions that get mapped to the OpenOffice calc filter
*/
public String[] getCalcTypes() {
return calcTypes;
}
/**
* Sets the file extensions that get mapped to the OpenOffice calc filter
*
* @param types The file extensions that get mapped to the OpenOffice calc filter
*/
public void SetCalcTypes(String[] types) {
calcTypes = types;
}
protected String[] drawTypes = null;
/**
* Returns the file extensions that get mapped to the OpenOffice draw filter
*
* @return The file extensions that get mapped to the OpenOffice draw filter
*/
public String[] getDrawTypes() {
return drawTypes;
}
/**
* Sets the file extensions that get mapped to the OpenOffice draw filter
*
* @param types The file extensions that get mapped to the OpenOffice draw filter
*/
public void SetDrawTypes(String[] types) {
drawTypes = types;
}
protected String[] nativeTypes = null;
/**
* Returns the file extensions that get processed directly by Ghostscript
*
* @return The file extensions that get processed directly by Ghostscript
*/
public String[] getNativeTypes() {
return nativeTypes;
}
/**
* Sets the file extensions that get processed directly by Ghostscript
*
* @param types The file extensions that get processed directly by Ghostscript
*/
public void SetNativeTypes(String[] types) {
nativeTypes = types;
}
protected String ooLibPath = "";
/**
* Gets the folder containing the Open Office libraries
*
* @return The folder containing the Open Office libraries
*/
public String getOOLibPath() {
return ooLibPath;
}
/**
* Sets the folder containing the Open Office libraries
*
* @param val The folder containing the Open Office libraries
*/
public void setOOLibPath(String val) {
ooLibPath = val;
}
protected String gsExePath = "";
/**
* Gets the folder containing the Ghostscript executable
*
* @return The folder containing the Ghostscript executable
*/
public String getGSExePath() {
return gsExePath;
}
/**
* Sets the folder containing the Ghostscript executable
*
* @param val The folder containing the Ghostscript executable
*/
public void setGSExePath(String val) {
gsExePath = val;
}
protected String gsExeName = "";
/**
* Gets the name of the Ghostscript executable
*
* @return The name of the Ghostscript executable
*/
public String getGSExeName() {
return gsExeName;
}
/**
* Sets the name of the Ghostscript executable
*
* @param val The name of the Ghostscript executable
*/
public void setGSExeName(String val) {
gsExeName = val;
}
protected String shellCommandStyle = null;
/**
* Gets the value of the shellCommandStyle. Can be either "doubleQuoted"
* for Windows-like or "escapeSpaces" for Unix-like.
*
* @return The value of shellCommandStyle
*/
public String getShellCommandStyle() {
return shellCommandStyle;
}
/**
* Sets the value of the shellCommandStyle. Can be either "doubleQuoted"
* for Windows-like or "escapeSpaces" for Unix-like.
*
* @param scs The value of shellCommandStyle
*/
public void setShellCommandStyle(String scs) {
shellCommandStyle = scs;
}
protected boolean deleteOnFinish = false;
/**
* Gets the value of the deleteOnFinish option
*
* @return The value of the deleteOnFinish option
*/
public boolean getDeleteOnFinish() {
return deleteOnFinish;
}
/**
* Sets the value of the deleteOnFinish option
*
* @param val The value of the deleteOnFinish option
*/
public void setDeleteOnFinish(boolean val) {
deleteOnFinish = val;
}
protected boolean doMerge = false;
/**
* Gets the value of the doMerge option
*
* @return The value of the doMerge option
*/
public boolean getDoMerge() {
return doMerge;
}
/**
* Sets the value of the doMerge option
*
* @param val The value of the doMerge option
*/
public void setDoMerge(boolean val) {
doMerge = val;
}
private String outputFilename;
/**
* Gets the value of the output filename for the merge option
*
* @return The value of the output filename for the merge option
*/
public String getOutputFilename() {
return outputFilename;
}
/**
* Sets the value of the output filename for the merge option
*
* @param outputFile The value of the output filename for the merge option
*/
public void setOutputFilename(String outputFile) {
this.outputFilename = outputFile;
}
private String statusText = null;
/**
* Gets status text set during the course of a conversion operation
*
* @return Status text set during the course of a conversion operation
*/
public String getStatusText() {
return statusText;
}
private boolean isError = false;
/**
* Gets error status set during the course of a conversion operation
*
* @return Error status set during the course of a conversion operation
*/
public boolean getIsError() {
return isError;
}
/**
* Clears error status and status text
*/
public void ClearError() {
statusText = null;
isError = false;
}
/**
* PDF Conversion and Merge method
*
* @param inputFiles An array of input filenames to process
* @return true if conversion succeeded
*/
public boolean DoConvert(String[] inputFiles) {
// Reset the errors and status
ClearError();
// Check configuration
if (ooLibPath == null) {
statusText = "Location of Open Office libraries not configured.";
isError = true;
return false;
}
if (gsExePath == null || gsExeName == null) {
statusText = "Location of Ghostscript not configured.";
isError = true;
return false;
}
// Input array should not be null
if (inputFiles == null) {
statusText = "No input files.";
isError = true;
return false;
}
// Zero length array is not an error per se
if (inputFiles.length == 0) {
statusText = "No input files.";
return false;
}
// Lack of output filename is an error
if (outputFilename == null && doMerge) {
statusText = "No output file specified.";
isError = true;
return false;
}
// Check for valid shell command style if -m is involved
if (doMerge) {
if (shellCommandStyle == null) {
statusText = "Shell command style not configured.";
isError = true;
return false;
} else if (!shellCommandStyle.contentEquals("doubleQuoted") &&
!shellCommandStyle.contentEquals("escapeSpaces")) {
statusText = "Unknown shell command style: " + shellCommandStyle;
isError = true;
return false;
}
}
// Declare Open Office components
XComponentContext xContext = null;
XMultiComponentFactory xMCF = null;
XComponentLoader xComponentLoader = null;
XStorable xStorable = null;
XCloseable xCloseable = null;
Object desktop = null;
Object document = null;
// File extension
String ext;
// Keep track of files for deletion
List<String> filesToDelete = new ArrayList<String>();
// Keep track of converted files
List<String> convertedFiles = new ArrayList<String>();
// Try to get reference to an Open Office process
try {
// Should use OO installation lib/programs directory on your system
String ooLibFolder = ooLibPath;
// Load the Open Office context
xContext = BootstrapSocketConnector.bootstrap(ooLibFolder);
// Load the Open Office object factory
xMCF = xContext.getServiceManager();
// Get a desktop instance
desktop = xMCF.createInstanceWithContext(
"com.sun.star.frame.Desktop", xContext);
// Get a reference to the the desktop interface that can load files
xComponentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop);
} catch (Exception ex) {
// Open Office error
statusText = "Could not get usable OpenOffice: " + ex.toString();
isError = true;
return false;
}
// Keep track of status
StringBuffer buf = new StringBuffer();
// Loop through the input files
for (int i = 0; i < inputFiles.length; i++) {
// Check file
if (inputFiles[i] == null) {
buf.append("File " + i + " was null.");
isError = true;
continue; // Skip to the next file
}
// Get the file extension
ext = null;
int lastDot = inputFiles[i].lastIndexOf('.');
if (lastDot > 0) {
ext = inputFiles[i].substring(lastDot).toLowerCase();
}
if (ext == null) {
buf.append("File " + i + " was unrecognized by extension.");
isError = true;
continue; // Skip to the next file
}
try {
// Set the document opener to not display an OO window
PropertyValue[] loaderValues = new PropertyValue[1];
loaderValues[0] = new PropertyValue();
loaderValues[0].Name = "Hidden";
loaderValues[0].Value = new Boolean(true);
// Convert file path to URL name format and escape spaces
String docURL = "file:///" + inputFiles[i].replace(File.separatorChar, '/').replace(" ", "%20");
lastDot = docURL.lastIndexOf('.');
// If it is already PDF, add it to the list of files to "converted" files
if (StringArrayContains(nativeTypes, ext)) {
convertedFiles.add(docURL);
} else {
// Open the document in Open Office
document = xComponentLoader.loadComponentFromURL(
docURL, "_blank", 0, loaderValues);
// Get a reference to the document interface that can store files
xStorable = (XStorable) UnoRuntime.queryInterface(
XStorable.class, document);
// Set the arguments to save to pdf.
PropertyValue[] saveArgs = new PropertyValue[2];
saveArgs[0] = new PropertyValue();
saveArgs[0].Name = "Overwrite";
saveArgs[0].Value = new Boolean(true);
// Choose appropriate output filter
saveArgs[1] = new PropertyValue();
saveArgs[1].Name = "FilterName";
if (StringArrayContains(writerTypes, ext)) {
saveArgs[1].Value = "writer_pdf_Export";
} else if (StringArrayContains(calcTypes, ext)) {
saveArgs[1].Value = "calc_pdf_Export";
} else if (StringArrayContains(drawTypes, ext)) {
saveArgs[1].Value = "draw_pdf_Export";
} else {
buf.append("File " + i + " has unknown extension: " + ext);
isError = true;
continue; // Skip to the next file
}
// The converted file will have the same name with a pdf extension
String sSaveUrl = docURL.substring(0, lastDot) + ".pdf";
// Save the file
xStorable.storeToURL(sSaveUrl, saveArgs);
// On success, add the converted filename to a list
convertedFiles.add(sSaveUrl);
if (deleteOnFinish) {
filesToDelete.add(inputFiles[i]);
}
}
buf.append("Processed file " + i + ". ");
} catch (com.sun.star.io.IOException ooioException) {
buf.append("Caught exception while processing file " + i + ": " +
ooioException.toString() + ". ");
isError = true;
} catch (com.sun.star.lang.IllegalArgumentException ooiaException) {
buf.append("Caught exception while processing file " + i + ": " +
ooiaException.toString() + ". ");
isError = true;
} catch (Exception otherException) {
buf.append("Caught exception while processing file " + i + ": " +
otherException.toString() + ". ");
isError = true;
} finally {
// Make sure the file is closed before going to the next one
if (document != null) {
// Get a reference to the document interface that can close a file
xCloseable = (XCloseable) UnoRuntime.queryInterface(
XCloseable.class, document);
// Try to close it or explicitly dispose it
// See http://doc.services.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Closing_Documents
if (xCloseable != null) {
try {
xCloseable.close(false);
} catch (com.sun.star.util.CloseVetoException ex) {
XComponent xComp = (XComponent) UnoRuntime.queryInterface(
XComponent.class, document);
xComp.dispose();
}
} else {
XComponent xComp = (XComponent) UnoRuntime.queryInterface(
XComponent.class, document);
xComp.dispose();
}
}
document = null; // Javanauts, please pardon my CSharpery
}
}
if (doMerge) {
// configure the shell command build
boolean doQuotes = shellCommandStyle.contentEquals("doubleQuoted");
boolean doEscapes = shellCommandStyle.contentEquals("escapeSpaces");
// Do the merge
StringBuffer cmd = new StringBuffer();
if (doQuotes) {
cmd.append("\"");
}
if (doEscapes) {
cmd.append(gsExePath.replace(" ", "\\ ")).append(File.separatorChar).append(gsExeName);
} else {
cmd.append(gsExePath).append(File.separatorChar).append(gsExeName);
}
if (doQuotes) {
cmd.append("\"");
}
cmd.append(" -q").append(" -dNOPAUSE").append(" -dBATCH").append(" -sDEVICE=pdfwrite").append(" -sOUTPUTFILE=");
if (doQuotes) {
cmd.append("\"");
}
if (doEscapes) {
cmd.append(outputFilename.replace(" ", "\\ "));
} else {
cmd.append(outputFilename);
}
if (doQuotes) {
cmd.append("\"");
}
cmd.append(" ");
// Loop over converted files
for (int i = 0; i < convertedFiles.size(); i++) {
String fileToAdd = convertedFiles.get(i).substring(8).replace("%20", " ").replace('/', File.separatorChar);
if (doQuotes) {
cmd.append("\"");
}
if (doEscapes) {
cmd.append(fileToAdd.replace(" ", "\\ "));
} else {
cmd.append(fileToAdd);
}
if (doQuotes) {
cmd.append("\"");
}
cmd.append(" ");
if (deleteOnFinish) {
filesToDelete.add((fileToAdd));
}
}
// Merge!
if (!isError) {
try {
// Execute the command
Process mProc = Runtime.getRuntime().exec(cmd.toString());
// Voodoo - In order to wait for an external process, you
// have to handle its stdout(getInputStream) and stderr (getErrorStream)
// I'm just going to close them as I'm only interested in if it succeeded or not
InputStream iStr = mProc.getInputStream();
iStr.close();
InputStream eStr = mProc.getErrorStream();
eStr.close();
// Now wait
int exCode = mProc.waitFor();
if (exCode == 0) {
buf.append("Merge succeeded: exit code was zero.");
} else {
isError = true;
buf.append("Merge failed: exit code was " + exCode);
}
} catch (java.io.IOException ex) {
buf.append("Merge failed: " + ex.toString());
isError = true;
statusText = buf.toString();
return false;
} catch (java.lang.InterruptedException ex) {
buf.append("Merge interrupted: " + ex.toString());
isError = true;
statusText = buf.toString();
return false;
}
}
}
// Delete the converted files
if (deleteOnFinish) {
for (int i = 0; i < filesToDelete.size(); i++) {
File dFile = new File(filesToDelete.get(i));
if (dFile.exists()) {
dFile.delete();
}
}
}
statusText = buf.toString();
return !isError;
}
}