iQuarK / 73 entradas / 32 comentarios / feed / comentarios feed Buscar:

Conversión de un powerpoint o un impress a imágenes y luego a pdf

Puedes necesitar pasar un fichero de PowerPoint (MSOffice) o Impress (OpenOffice) a formatos EPUB o FB2 para libros electrónicos, puesto que por lo general este tipo de documentos tienen muchas imágenes, no se suele conseguir una conversión muy buena que digamos, cualquier imagen y cuadro de texto sale mal y fuera de lugar.  Bueno, sin mas preámbulos paso a describir cómo convertir un documento de este tipo a un PDF con imágenes:

Bueno, esto funciona con una macro de OpenOffice, por lo que, tras ejecutarlo hay que ir a Herramientas->Organizar Macros->OpenOffice.org Basic, en Mis macros->Standard->Module1 le damos a Editar, pegamos el siguiente código a continuación de lo que haya, (si ya tienes la función MakePropertyValue del post en el que muestro cómo pasar un documento a pdf, no la vuelvas a poner):

SUB SplitSlides( cImpressDocToSplit )
 
   ' Open the document to find out how many pages it has.
   oDoc = StarDesktop.LoadComponentFromURL( ConvertToURL( cImpressDocToSplit ), "_blank", 0, Array() )
 
   nNumPages = oDoc.getDrawPages().getCount()
 
   ' Now that we know how many pages it has, close it.
   oDoc.CLOSE( True )
 
   ' Get the name of the document, but without a filename suffix.
   cImpressDocToSplitNoSuffix = Left( cImpressDocToSplit, LEN( cImpressDocToSplit ) - 4 )
   MKDIR (cImpressDocToSplitNoSuffix)
 
   ' Now loop once for each page.
   nHighestPageNumber = nNumPages-1
'   nPageToSave = 2
   FOR nPageToSave = 0 TO nHighestPageNumber
 
      ' Open the document.
      oDoc = StarDesktop.LoadComponentFromURL( ConvertToURL( cImpressDocToSplit ), "_blank", 0, Array() )
 
      ' Delete all pages except the one we're interested in keeping
      '  on this loop.
      DeleteAllPagesExcept( oDoc, nPageToSave )
 
      ' Prepare to save the document in multiple forms.
      ' First get the new filename to save it under.
      cNewName = cImpressDocToSplitNoSuffix + "\page " + CSTR( nPageToSave + 1 )
 
      ' Save it as a PNG.
      oDoc.storeToUrl( ConvertToURL( cNewName + ".jpg" ), _
         Array( MakePropertyValue( "FilterName", "impress_jpg_Export" ) ) )
 
      ' Close the document without saving it.
      oDoc.CLOSE( True )
   NEXT
 
END SUB
 
' Delete all pages of an Impress or Draw document,
'  EXCEPT for a certian page that we want to keep.
FUNCTION DeleteAllPagesExcept( oDoc, nPageToKeep )
   nNumPages = oDoc.getDrawPages().getCount()
   nHighestPageNumber = nNumPages-1
 
   ' Delete the last page, then the page before that,
   '  then the page before that, until we get to the
   '  page to keep.
   ' This deletes all pages AFTER the page to keep.
   nPageToDelete = nHighestPageNumber
   DO WHILE nPageToDelete > nPageToKeep
      ' Get the page.
      oPage = oDoc.getDrawPages().getByIndex( nPageToDelete )
      ' Tell the document to remove it.
      oDoc.getDrawPages().remove( oPage )
 
      nPageToDelete = nPageToDelete - 1
   LOOP
 
   ' Delete all the pages before the page to keep.
   FOR i = 0 TO nPageToKeep - 1
      ' Delete the first page.
      nPageToDelete = 0
      ' Get the page.
      oPage = oDoc.getDrawPages().getByIndex( nPageToDelete )
      ' Tell the document to remove it.
      oDoc.getDrawPages().remove( oPage )
   NEXT
END FUNCTION
FUNCTION MakePropertyValue( Optional cName AS STRING, Optional uValue ) AS COM.sun.star.beans.PropertyValue
	DIM oPropertyValue AS New COM.sun.star.beans.PropertyValue
	IF NOT IsMissing( cName ) THEN
		oPropertyValue.NAME = cName
	EndIf
	IF NOT IsMissing( uValue ) THEN
		oPropertyValue.Value = uValue
	EndIf
	MakePropertyValue() = oPropertyValue
END FUNCTION

SplitSlides sirve para extraer capturas de todas las diapositivas, cada una en una imagen.

Guardamos y ahora se podría probar en la línea de comandos, la macro con el ejecutable del OpenOffice, en mi caso:

"c:\Archivos de programa\OpenOffice.org 3\program\soffice" "macro:///Standard.Module1.SplitSlides(c:\fichero.ppt)"

Esto creará una carpeta del mismo nombre que el fichero, en la que estarán todas las imágenes de las diapositivas.  Bueno, ahora toca juntarlo todo, para esto he creado un código con iText que lo que hace es recorrer un directorio, si hay imágenes en él las junta en un documento en formato PDF, los parámetros son el directorio donde están las imágenes y el fichero de salida:

public void createPdfFromImages(String directoryIN, String filenameOUT)
        throws IOException, DocumentException, SQLException {
        File file = new File(directoryIN);
        System.out.println("listfiles: "+file.listFiles().length);
        if(file.listFiles().length>0) {
            Image image = null;
            // search the first image on directory
            for(int fidx=0; fidx<file.listFiles().length; fidx++) {
                System.out.println("mime "+new MimetypesFileTypeMap().getContentType(file.listFiles()[fidx]));
                if(new MimetypesFileTypeMap().getContentType(file.listFiles()[fidx]).split("/")[0].equals("image")) {
                    image = Image.getInstance(file.listFiles()[fidx].getAbsolutePath());
                    break;
                }
            }
            // if exists some image, we create a document with the first image
            // dimensions (they are slides, they must have the same size)
            if(image!=null) {
                float height=image.getHeight();
                float width=image.getWidth();
                System.out.println("tamaño "+width+"x"+height);
                Document document = new Document(new Rectangle(width,height));
                PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filenameOUT));
                document.open();
                for (int fidx=0; fidx<file.listFiles().length; fidx++) {
                    if(new MimetypesFileTypeMap().getContentType(file.listFiles()[fidx]).split("/")[0].equals("image")) {
                        document.newPage();
                        image = Image.getInstance (file.listFiles()[fidx].getAbsolutePath());
                        PdfContentByte cbu = writer.getDirectContentUnder();
                        cbu.beginText();
                        image.setAbsolutePosition(0f, 0f);
                        cbu.addImage(image);
                        cbu.endText();
                    }
                }
                document.close();
            }
        }
    }

Recuerda que debes usar la ruta absoluta, o dará una excepción por no estar bien construida.

Bueno, ya que se usa tanto línea de comandos como código en java, habría que poder ejecutar el comando desde el mismo programa donde reside la función de iText, para ello usamos el método getRuntime del objeto Runtime, un main para probar todo eso sería:

String rutaFichero = "c:/proyectos/pptimg/pruebas.ppt";
String sinExtension = rutaFichero.substring(0, rutaFichero.length()-4);
// Creamos las imágenes
System.out.println(rutaFichero.split("/").length);
// el lugar donde tengas el ejecutable del office quizá cambie en tu máquina
Process p=Runtime.getRuntime().exec ("\"c:\\Archivos de programa\\OpenOffice.org 3\\program\\soffice\" \"macro:///Standard.Module1.SplitSlides("+rutaFichero+")\"");
int exitValue = -1;  // lugar donde almacenaremos el valor de salida del programa
// <esperamos a que termine el proceso>
boolean terminaProceso=false;
while(!terminaProceso) {
    try{
        exitValue = p.exitValue();
        terminaProceso=true;
    } catch (java.lang.IllegalThreadStateException itse) {
        terminaProceso=false;
    }
}
// </esperamos a que termine el proceso>
// si ha ido bien, creamos el pdf
if(exitValue==0) {
    textLib.createPdfFromImages(sinExtension, sinExtension+".pdf");
} else {
     System.out.println("No se realizó la conversión a imágenes correctamente.");
}

Tras esto, si pensamos pasarlo a EPUB o FB2 o algún otro formato de libro electrónico, habría que usar una aplicación tal como Calibre, esta por ejemplo ofrece la posibilidad de realizar la conversión desde fuera del GUI por línea de comandos.

Post to Twitter Post to Delicious Post to Facebook