0
votes

I need to create a pdf file from plain text files. I supposed that the simplest method would be read these files and print them to a PDF printer. My problem is that if I print to a pdf printer, the result will be an empty pdf file. If I print to Microsoft XPS Document Writer, the file is created in plain text format, not in oxps format. I would be satisfied with a two or three step solution. (Eg. converting to xps first then to pdf using ghostscript, or something similar). I have tried a couple of pdf printers such as: CutePDF, Microsoft PDF writer, Bullzip PDF. The result is the same for each one.

The environment is Java 1.7/1.8 Win10

private void print() {

    try {
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;

        PrintRequestAttributeSet patts = new HashPrintRequestAttributeSet();                   
        PrintService[] ps = PrintServiceLookup.lookupPrintServices(flavor, patts);
        if (ps.length == 0) {
            throw new IllegalStateException("No Printer found");
        }
        System.out.println("Available printers: " + Arrays.asList(ps));
        PrintService myService = null;
        for (PrintService printService : ps) {
            if (printService.getName().equals("Microsoft XPS Document Writer")) { // 
                myService = printService;
                break;
            }
        }
        if (myService == null) {
            throw new IllegalStateException("Printer not found");
        }

        myService.getSupportedDocFlavors();
        DocPrintJob job = myService.createPrintJob();


   FileInputStream fis1 = new FileInputStream("o:\\k\\t1.txt");

        Doc pdfDoc = new SimpleDoc(fis1, DocFlavor.INPUT_STREAM.AUTOSENSE, null);

        HashPrintRequestAttributeSet pr = new HashPrintRequestAttributeSet();
        pr.add(OrientationRequested.PORTRAIT);
        pr.add(new Copies(1));
        pr.add(MediaSizeName.ISO_A4);
        PrintJobWatcher pjw = new PrintJobWatcher(job);
        job.print(pdfDoc, pr);
        pjw.waitForDone();
        fis1.close();

    } catch (PrintException ex) {
        Logger.getLogger(Docparser.class.getName()).log(Level.SEVERE, null, ex);
    } catch (Exception ex) {
        Logger.getLogger(Docparser.class.getName()).log(Level.SEVERE, null, ex);
    }
}


class PrintJobWatcher {

    boolean done = false;

    PrintJobWatcher(DocPrintJob job) {
        job.addPrintJobListener(new PrintJobAdapter() {
            public void printJobCanceled(PrintJobEvent pje) {
                allDone();
            }

            public void printJobCompleted(PrintJobEvent pje) {
                allDone();
            }

            public void printJobFailed(PrintJobEvent pje) {
                allDone();
            }

            public void printJobNoMoreEvents(PrintJobEvent pje) {
                allDone();
            }

            void allDone() {
                synchronized (PrintJobWatcher.this) {
                    done = true;
                    System.out.println("Printing done ...");
                    PrintJobWatcher.this.notify();
                }
            }
        });
    }

    public synchronized void waitForDone() {
        try {
            while (!done) {
                wait();
            }
        } catch (InterruptedException e) {
        }
    }
}
2
Is installing Libre Office an option for your task? There are some command line and Java API options available if so. - Paul Jowett
Yes I know that but I try to avoid using it in this project. - sfeher

2 Answers

0
votes

If you can install LibreOffice, it is possible to use the Java UNO API to do this.

There is a similar example here which will load and save a file: Java Convert Word to PDF with UNO. This could be used to convert your text file to PDF.

Alternatively, you could take the text file and send it directly to the printer using the same API.

The following JARs give access to the UNO API. Ensure these are in your class path:

[Libre Office Dir]/URE/java/juh.jar
[Libre Office Dir]/URE/java/jurt.jar
[Libre Office Dir]/URE/java/ridl.jar
[Libre Office Dir]/program/classes/unoil.jar
[Libre Office Dir]/program

The following code will then take your sourceFile and print to the printer named "Local Printer 1".

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.sun.star.beans.PropertyValue;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.view.XPrintable;

public class DirectPrintTest
{
    public static void main(String args[])
    {
        // set to the correct name of your printers
        String printer = "Local Printer 1";// "Microsoft Print to PDF";
        File sourceFile = new File("c:/projects/WelcomeTemplate.doc");

        if (!sourceFile.canRead()) {
            throw new RuntimeException("Can't read:" + sourceFile.getPath());
        }

        com.sun.star.uno.XComponentContext xContext = null;

        try {
            // get the remote office component context
            xContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
            System.out.println("Connected to a running office ...");

            // get the remote office service manager
            com.sun.star.lang.XMultiComponentFactory xMCF = xContext
                    .getServiceManager();

            Object oDesktop = xMCF.createInstanceWithContext(
                    "com.sun.star.frame.Desktop", xContext);

            com.sun.star.frame.XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime
                    .queryInterface(com.sun.star.frame.XComponentLoader.class,
                            oDesktop);

            StringBuffer sUrl = new StringBuffer("file:///");
            sUrl.append(sourceFile.getCanonicalPath().replace('\\', '/'));

            List<PropertyValue> loadPropsList = new ArrayList<PropertyValue>();
            PropertyValue pv = new PropertyValue();
            pv.Name = "Hidden";
            pv.Value = Boolean.TRUE;
            loadPropsList.add(pv);

            PropertyValue[] loadProps = new PropertyValue[loadPropsList.size()];
            loadPropsList.toArray(loadProps);

            // Load a Writer document, which will be automatically displayed
            com.sun.star.lang.XComponent xComp = xCompLoader
                    .loadComponentFromURL(sUrl.toString(), "_blank", 0,
                            loadProps);

            // Querying for the interface XPrintable on the loaded document
            com.sun.star.view.XPrintable xPrintable = (XPrintable) UnoRuntime
                    .queryInterface(com.sun.star.view.XPrintable.class, xComp);

            // Setting the property "Name" for the favoured printer (name of
            // IP address)
            com.sun.star.beans.PropertyValue propertyValue[] = new com.sun.star.beans.PropertyValue[2];
            propertyValue[0] = new com.sun.star.beans.PropertyValue();
            propertyValue[0].Name = "Name";
            propertyValue[0].Value = printer;

            // Setting the name of the printer
            xPrintable.setPrinter(propertyValue);

            propertyValue[0] = new com.sun.star.beans.PropertyValue();
            propertyValue[0].Name = "Wait";
            propertyValue[0].Value = Boolean.TRUE;

            // Printing the loaded document
            System.out.println("sending print");
            xPrintable.print(propertyValue);

            System.out.println("closing doc");
            ((com.sun.star.util.XCloseable) UnoRuntime.queryInterface(
                    com.sun.star.util.XCloseable.class, xPrintable))
                    .close(true);

            System.out.println("closed");

            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace(System.err);
            System.exit(1);
        }
    }

}
0
votes

Thank you for all. After two days struggling with various type of printers (I gave a chance to CUPS PDF printer too but I could not make it to print in landscape mode) I ended up using the Apache PDFbox.

It's only a POC solution but works and fits to my needs. I hope it will be useful for somebody. ( cleanTextContent() method removes some ESC control characters from the line to be printed. )

    public void txt2pdf() {
    float POINTS_PER_INCH = 72;
    float POINTS_PER_MM = 1 / (10 * 2.54f) * POINTS_PER_INCH;
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:m.ss");

    PDDocument doc = null;
    try {
        doc = new PDDocument();

        PDPage page = new PDPage(new PDRectangle(297 * POINTS_PER_MM, 210 * POINTS_PER_MM));
        doc.addPage(page);
        PDPageContentStream content = new PDPageContentStream(doc, page);

        //PDFont pdfFont = PDType1Font.HELVETICA;
        PDFont pdfFont = PDTrueTypeFont.loadTTF(doc, new File("c:\\Windows\\Fonts\\lucon.ttf"));
        float fontSize = 10;
        float leading = 1.1f * fontSize;

        PDRectangle mediabox = page.getMediaBox();
        float margin = 20;
        float startX = mediabox.getLowerLeftX() + margin;
        float startY = mediabox.getUpperRightY() - margin;

        content.setFont(pdfFont, fontSize);
        content.beginText();
        content.setLeading(leading);
        content.newLineAtOffset(startX, startY);
        BufferedReader fis1 = new BufferedReader(new InputStreamReader(new FileInputStream("o:\\k\\t1.txt"), "cp852"));
        String inString;
        //content.setRenderingMode(RenderingMode.FILL_STROKE);
        float currentY = startY + 60;
        float hitOsszesenOffset = 0;
        int pageNumber = 1;
        while ((inString = fis1.readLine()) != null) {
            currentY -= leading;
            if (currentY <= margin) {
                content.newLineAtOffset(0, (mediabox.getLowerLeftX()-35));
                content.showText("Date Generated: " + dateFormat.format(new Date()));
                content.newLineAtOffset((mediabox.getUpperRightX() / 2), (mediabox.getLowerLeftX()));

                content.showText(String.valueOf(pageNumber++)+" lap");
                content.endText();
                float yCordinate = currentY+30;
                float sX = mediabox.getLowerLeftY()+ 35;
                float endX = mediabox.getUpperRightX() - 35;                     
                content.moveTo(sX, yCordinate);                    
                content.lineTo(endX, yCordinate);
                content.stroke();
                content.close();
                PDPage new_Page = new PDPage(new PDRectangle(297 * POINTS_PER_MM, 210 * POINTS_PER_MM));
                doc.addPage(new_Page);
                content = new PDPageContentStream(doc, new_Page);
                content.beginText();
                content.setFont(pdfFont, fontSize);
                content.newLineAtOffset(startX, startY);
                currentY = startY;
            }

            String ss = new String(inString.getBytes(), "UTF8");
            ss = cleanTextContent(ss);

            if (!ss.isEmpty()) {
                if (ss.contains("JAN") || ss.contains("SUMMARY")) {                        
                    content.setRenderingMode(RenderingMode.FILL_STROKE);
                }
                content.newLineAtOffset(0, -leading);
                content.showText(ss);
            }

            content.setRenderingMode(RenderingMode.FILL);
        }
        content.newLineAtOffset((mediabox.getUpperRightX() / 2), (mediabox.getLowerLeftY()));
        content.showText(String.valueOf(pageNumber++));
        content.endText();
        fis1.close();
        content.close();
        doc.save("o:\\k\\t1.pdf");
    } catch (IOException ex) {
        Logger.getLogger(Document_Creation.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        if (doc != null) {
            try {
                doc.close();
            } catch (IOException ex) {
                Logger.getLogger(Document_Creation.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}