3
\$\begingroup\$

I’m new to Java programming and uncertain if I used the right approach to solve my job.

This little program uses the iText library to split one big PDF into smaller documents. The trigger for this is a text on every page in a specific region (found with a RegionTextRenderFilter).

In all the smaller documents I also have to insert a signature field (whenever the text “{{singbarfield}}” is found, done with a RenderListener) and some text to mark the signfields.

I had to save all the found text positions in one document. This was done in the RenderListener, so I had to implement additional methods in the RenderLister to save the state and to return theses information to the calling class.

So far my program works well. But for sure there is space for improvements.

package splitenhanceejobcard;

import java.io.ByteArrayOutputStream;
.... imports removed

public class SplitEnhancePdf {

    /** Text file to hold debug information */
    public static final String DEBUGLOG = "parsePdf.log";

    public static ArrayList<Vector> cloneSignBoxPos(List<Vector> list){
        ArrayList<Vector> clone = new ArrayList<Vector>(list.size());
        for (Vector item : list) {
            clone.add(item);
        }
        return clone;
    }

    public static TreeMap<Float, String> cloneSubtaskPos(Hashtable<String, Vector> hash){
        Hashtable<Float, String> clone = new Hashtable<Float, String>();
        TreeMap<Float, String> clonemap = new TreeMap<Float, String>();
        Set<String> keys = hash.keySet();
        for (String key: keys){
            Vector tempVect = hash.get(key);
            clone.put(tempVect.get(Vector.I2), key);
            clonemap.put(hash.get(key).get(Vector.I2), key);
        }
        return clonemap;        
    }

    public void stampPdf(ByteArrayOutputStream baos, String dest, PrintWriter out) throws IOException, DocumentException {
        PdfReader reader = new PdfReader(baos.toByteArray());
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        RenderListener listener = new MyTextRenderListener(out);
        PdfReaderContentParser parser = new PdfReaderContentParser(reader);
        Hashtable<Integer, TreeMap<Float, String>> subtaskPosList = 
                new Hashtable<Integer, TreeMap<Float, String>>();
        Hashtable<Integer, ArrayList<Vector>> docSignBoxList = 
                new Hashtable<Integer, ArrayList<Vector>>();

        // collect signbox position and subtaskkey position
        for (int i = 1; i <= reader.getNumberOfPages(); i++){
            parser.processContent(i, listener);
            if (((MyTextRenderListener) listener).getSignBoxPos().size() > 0){
                docSignBoxList.put(i, cloneSignBoxPos(((MyTextRenderListener) listener).getSignBoxPos()));
            }
            if (((MyTextRenderListener) listener).getSubtaskPos().size() > 0){
                subtaskPosList.put(i, cloneSubtaskPos(((MyTextRenderListener) listener).getSubtaskPos()));
            }
            ((MyTextRenderListener) listener).clearSignBoxPos();
            ((MyTextRenderListener) listener).clearSubtaskPos();
        }

        for (int i = 1; i <= reader.getNumberOfPages(); i++){
            ArrayList<Vector> pageSignBoxList = new ArrayList<Vector>();
            pageSignBoxList = docSignBoxList.get(i);
            if (pageSignBoxList != null){
                for (int a = 0; a < pageSignBoxList.size(); a++){
                    Vector signBoxPos = pageSignBoxList.get(a);
                    String subtaskId = new String();

                    // find previous Subtask Key (I2 Vector)
                    if (subtaskPosList.get(i) != null){
                        Set<Float> keys = subtaskPosList.get(i).keySet();
                        for (Float key: keys){
                            if (signBoxPos.get(Vector.I2) < key){
                                subtaskId = subtaskPosList.get(i).get(key);
                                break;
                            }
                        }
                    }
                    if (subtaskId.isEmpty()) {
                        for (int b = i - 1; b > 0; b--){
                            if (subtaskPosList.get(b) != null){
                                subtaskId = subtaskPosList.get(b).firstEntry().getValue();
                                break;
                            }
                        }
                    }

                    PdfFormField field = PdfFormField.createSignature(stamper.getWriter());
                    field.setFieldName("SIGNAME" + i + a);
                    field.setWidget(new Rectangle(
                            signBoxPos.get(Vector.I1) + 65, 
                            signBoxPos.get(Vector.I2) - 10 , 
                            signBoxPos.get(Vector.I1), 
                            signBoxPos.get(Vector.I2) - 35), 
                            PdfAnnotation.HIGHLIGHT_OUTLINE);

                    field.setFlags(PdfAnnotation.FLAGS_PRINT);
                    stamper.addAnnotation(field, i);

                    PdfContentByte canvas = stamper.getOverContent(i);
                    ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, 
                            new Phrase("Sign " + i + "_" + a,  FontFactory.getFont(FontFactory.HELVETICA, 10, BaseColor.RED)), 
                            signBoxPos.get(Vector.I1) + 3, 
                            signBoxPos.get(Vector.I2) - 22, 0);
                    ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, 
                            new Phrase(subtaskId,  FontFactory.getFont(FontFactory.HELVETICA, 6, BaseColor.BLACK)), 
                            signBoxPos.get(Vector.I1) + 3, 
                            signBoxPos.get(Vector.I2) - 30, 0);
                }
            }
        }
        stamper.close();                
    }

    public void splitPdf(String src, String debuglog) throws IOException, DocumentException{
        System.out.println("Filename: " + src);
        PrintWriter out = new PrintWriter(new FileOutputStream(debuglog));
        Document pdfdoc = null;
        PdfCopy copy = null;
        int lastJc = -1;
        int newJc = 0;
        String eventId = "";
        pdfdoc = new Document();
        PdfReader reader = new PdfReader(src);
        Rectangle jcIdArea  = new Rectangle(450, 750, 595, 841);
        RenderFilter[] jcIdfilter = {new RegionTextRenderFilter(jcIdArea)};
        TextExtractionStrategy strategy;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        if (src.contains(".")){
            eventId = src.substring(0, src.lastIndexOf('.'));
        }
        else {
            eventId = src;
        }

        for (int i = 1; i <= reader.getNumberOfPages(); i++){
            // Get JC ID via LocationTextExtractionStrategy
            strategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), jcIdfilter);
            String regionText = PdfTextExtractor.getTextFromPage(reader, i, strategy);
            String jcId = regionText.substring(regionText.indexOf("JC ID:")+ 7);
            jcId = jcId.substring(0, jcId.indexOf("\n"));
            try{
                newJc = Integer.parseInt(jcId);
            } catch (NumberFormatException  e){
                newJc = 0;
            }
            if (newJc > lastJc){
                if (pdfdoc != null && pdfdoc.isOpen()){
                    pdfdoc.close();
                    copy.close();
                    copy.freeReader(reader);
                    stampPdf(baos, "output//" + eventId + "_sign_" + lastJc + ".pdf", out);
                }
                pdfdoc = new Document();
                copy = new PdfCopy(pdfdoc, baos);
                pdfdoc.open();
                lastJc = newJc;
            }
            copy.addPage(copy.getImportedPage(reader, i));
        }

        pdfdoc.close();
        stampPdf(baos, "output//" + eventId + "_sign_" + lastJc + ".pdf", out);
        out.flush();
        out.close();
    }

    public static void main(String[] args) throws IOException, DocumentException {
        if (args.length <= 0){
            System.out.println("No filename specified.");
            System.exit(0);
        }
        String inPDF = args[0];
        File pdfFileIn = null;
        pdfFileIn = new File(inPDF);
        if (pdfFileIn.exists() && !pdfFileIn.isDirectory()){
            SplitEnhancePdf parsePdf = new SplitEnhancePdf();
            parsePdf.splitPdf(inPDF, DEBUGLOG);
        }
        else{
            System.out.println("No valid filename specified: " + inPDF);
        }

    }

}

Here the RenderListener implementation.

package splitenhanceejobcard;

import java.io.PrintWriter;
...imports removed

public class MyTextRenderListener implements RenderListener{

    protected PrintWriter out;
    String prevTextSegment;
    Vector signStartPoint;
    List<Vector> signStartPointList;
    Hashtable<String, List<Vector>> signFieldList;
    Hashtable<String, Vector> subtaskPos;
    String subtaskKey;

    public MyTextRenderListener(PrintWriter out) {
        this.out = out;
        prevTextSegment = "";
        signStartPointList = new ArrayList<Vector>();
        signFieldList = new Hashtable<String, List<Vector>>();
        subtaskPos = new Hashtable<String, Vector>();
        subtaskKey = "";
    }

    @Override
    public void beginTextBlock() {
    }

    @Override
    public void endTextBlock() {
    }

    @Override
    public void renderImage(ImageRenderInfo renderInfo) {
    }

    @Override
    public void renderText(TextRenderInfo renderInfo) {
        String signFieldMarker = "{{signbarfield}}";
        if ( renderInfo.getText().contains(signFieldMarker) ){
            signStartPoint = renderInfo.getBaseline().getStartPoint();
            signStartPointList.add(signStartPoint);
            signFieldList.put(subtaskKey, signStartPointList);

            prevTextSegment = renderInfo.getText();
        } 

        if (renderInfo.getText().contains("Subtask:") && renderInfo.getText().contains("---  Key:")){
            subtaskKey = renderInfo.getText().substring(renderInfo.getText().indexOf("---  Key:") + 10);
            subtaskPos.put(subtaskKey, renderInfo.getBaseline().getStartPoint());
        }
    }

    public Hashtable<String, Vector> getSubtaskPos(){
        return subtaskPos;
    }

    public void clearSubtaskPos(){
        subtaskPos.clear();
    }

    public ArrayList<Vector> getSignBoxPos(){
        return (ArrayList<Vector>) signStartPointList;
    }

    public void clearSignBoxPos(){
        signStartPointList.clear();
    }

}
\$\endgroup\$
1
\$\begingroup\$
public static ArrayList<Vector> cloneSignBoxPos(List<Vector> list){
    ArrayList<Vector> clone = new ArrayList<Vector>(list.size());
    for (Vector item : list) {
        clone.add(item);
    }
    return clone;
}

Why does this method exist? new ArrayList<Vector>(originalVectorList) will give you a copied list.


public static TreeMap<Float, String> cloneSubtaskPos(Hashtable<String, Vector> hash){
    Hashtable<Float, String> clone = new Hashtable<Float, String>();
    TreeMap<Float, String> clonemap = new TreeMap<Float, String>();
    Set<String> keys = hash.keySet();
    for (String key: keys){
        Vector tempVect = hash.get(key);
        clone.put(tempVect.get(Vector.I2), key);
        clonemap.put(hash.get(key).get(Vector.I2), key);
    }
    return clonemap;        
}

clone is only written to, never read. Get rid of it.


    RenderListener listener = new MyTextRenderListener(out);
    ...
    for (int i = 1; i <= reader.getNumberOfPages(); i++){
        parser.processContent(i, listener);
        if (((MyTextRenderListener) listener).getSignBoxPos().size() > 0){
            docSignBoxList.put(i, cloneSignBoxPos(((MyTextRenderListener) listener).getSignBoxPos()));
        }
        if (((MyTextRenderListener) listener).getSubtaskPos().size() > 0){
            subtaskPosList.put(i, cloneSubtaskPos(((MyTextRenderListener) listener).getSubtaskPos()));
        }
        ((MyTextRenderListener) listener).clearSignBoxPos();
        ((MyTextRenderListener) listener).clearSubtaskPos();
    }

Defining the listener here as RenderListener is causing you some issues with casting. Either define it as a MyTextRenderListener and get rid of the casts, or (I don't know where the RenderListener is defined because you removed the imports) alter the interface of RenderListener to include the methods you need.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.