org.socialbiz.cog.util.PDFUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.socialbiz.cog.util.PDFUtil.java

Source

/*
 * Copyright 2013 Keith D Swenson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors Include: Shamim Quader, Sameer Pradhan, Kumar Raja, Jim Farris,
 * Sandia Yang, CY Chen, Rajiv Onat, Neal Wang, Dennis Tam, Shikha Srivastava,
 * Anamika Chaudhari, Ajay Kakkar, Rajeev Rastogi
 */

package org.socialbiz.cog.util;

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDGamma;
import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;

import org.socialbiz.cog.AuthDummy;
import org.socialbiz.cog.AuthRequest;
import org.socialbiz.cog.IdGenerator;
import org.socialbiz.cog.NoteRecord;
import org.socialbiz.cog.LineIterator;
import org.socialbiz.cog.MimeTypes;
import org.socialbiz.cog.NGBook;
import org.socialbiz.cog.NGPage;
import org.socialbiz.cog.NGPageIndex;
import org.socialbiz.cog.SectionUtil;
import org.socialbiz.cog.SectionWiki;
import org.socialbiz.cog.UserProfile;

public class PDFUtil {

    boolean startWithBullet = false;
    float xPos = 200f;
    float yPos = 800f;
    float xShift = 0f;
    float yShift = 0f;

    float previousSubLineWidth = 0.0f;
    int notesIndex = 0;

    PDFont nbfont = PDType1Font.HELVETICA_BOLD;
    PDFont font = PDType1Font.TIMES_ROMAN;
    PDFont bfont = PDType1Font.TIMES_BOLD;
    PDDocument document;
    PDPage page;
    PDPageContentStream contentStream;

    int font_size = 10;
    int h1_font_size = 14;
    int h2_font_size = 12;
    int h3_font_size = 10;

    PDActionURI uri = new PDActionURI();
    PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();

    List<String> wrappedListOfLink = new ArrayList<String>();
    int wIndex = 0;

    AuthRequest ar = null;
    int restLineWidth = 120;
    boolean isNewPage = false;

    public PDFUtil() {
        document = null;
    }

    void initializeWrappedListOfLink() {
        wrappedListOfLink = new ArrayList<String>();
    }

    private void setCusrosrPosition(float nxShift, float nyShift) throws Exception {
        xShift = nxShift;
        yShift = nyShift;
        xPos = xPos + xShift;
        yPos = yPos + yShift;
        if (xPos >= 590) {
            xPos = 40;
        }
        setPage();
    }

    private void setPage() throws Exception {
        if (document == null) { //Initialize
            document = new PDDocument();
            page = new PDPage();
            page.setMediaBox(PDPage.PAGE_SIZE_A4);
            document.addPage(page);
            contentStream = new PDPageContentStream(document, page, false, false);
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(xPos, yPos);
            isNewPage = true;
        } else {
            if (yPos <= 40) { //Close the old page create new
                contentStream.endText();
                contentStream.close();
                page = new PDPage();
                page.setMediaBox(PDPage.PAGE_SIZE_A4);
                document.addPage(page);
                contentStream = new PDPageContentStream(document, page, false, false);
                yPos = 800;
                xShift = 0;
                yShift = 0;
                contentStream.beginText();
                contentStream.setFont(font, font_size);
                contentStream.moveTextPositionByAmount(xPos, yPos);
                isNewPage = true;
            } else {
                contentStream.moveTextPositionByAmount(xShift, yShift);
            }
        }
    }

    /**
     * TODO: This appears to be a duplicate method, eliminate this or the other
     */
    public void serveUpFile(AuthRequest ar, String pageId) throws Exception {
        NGPage ngp = NGPageIndex.getProjectByKeyOrFail(pageId);
        ar.setPageAccessLevels(ngp);

        Vector<NoteRecord> publicNotes = new Vector<NoteRecord>();
        Vector<NoteRecord> memberNotes = new Vector<NoteRecord>();

        List<String> publicNoteList = null;
        if (ar.req.getParameterValues("publicNotes") != null) {
            publicNoteList = Arrays.asList(ar.req.getParameterValues("publicNotes"));
            for (String noteId : publicNoteList) {
                publicNotes.add(ngp.getNote(noteId));
            }
        }

        List<String> memberNoteList = null;
        if (ar.isLoggedIn() && ar.req.getParameterValues("memberNotes") != null) {
            memberNoteList = Arrays.asList(ar.req.getParameterValues("memberNotes"));
            for (String noteId : memberNoteList) {
                memberNotes.add(ngp.getNote(noteId));
            }
        }

        this.ar = ar;
        setPage(); //Initialize
        String projectName = ngp.getFullName();
        contentStream.setFont(nbfont, h1_font_size);

        contentStream.drawString(projectName);
        setCusrosrPosition(-160, -40);

        if (publicNoteList != null && publicNoteList.size() > 0) {
            contentStream.setFont(nbfont, h1_font_size);
            contentStream.drawString("Public Notes : ");
            setCusrosrPosition(0, -30);
            writeInPDF(ar, publicNotes);
        }

        if (memberNoteList != null && memberNoteList.size() > 0) {
            notesIndex = 0;
            if (!isNewPage) {
                yPos = 0;
                setPage();
            }
            contentStream.setFont(nbfont, h1_font_size);
            contentStream.drawString("Member Notes : ");
            setCusrosrPosition(0, -30);
            writeInPDF(ar, memberNotes);
        }

        contentStream.endText();
        contentStream.close();
        String fileName = IdGenerator.generateKey() + ".pdf";
        String mimeType = MimeTypes.getMimeType(fileName);
        ar.resp.setContentType(mimeType);
        //set expiration to about 1 year from now
        //ar.resp.setDateHeader("Expires", System.currentTimeMillis()+3000000);
        ar.resp.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        OutputStream out = ar.resp.getOutputStream();
        document.save(out);
        document.close();
        out.flush();
    }

    private void writeInPDF(AuthRequest ar, Vector<NoteRecord> notes) throws Exception, IOException {

        for (NoteRecord lr : notes) {
            String data = lr.getData();

            String subject = lr.getSubject();
            if (subject == null || subject.length() == 0) {
                subject = "Untitled Note";
            }

            if (subject.length() > 45) {
                subject = subject.substring(0, 45) + "...";
            }
            String lastEditor = lr.getLastEditedBy();
            String editTime = SectionUtil.getNicePrintTime(lr.getLastEdited(), ar.nowTime).trim();
            setCusrosrPosition(10, -5);
            contentStream.setFont(nbfont, h2_font_size);
            String noteHeader = String.valueOf(notesIndex + 1) + ".  " + subject;
            contentStream.drawString(noteHeader);

            contentStream.setFont(font, font_size);

            addUserLinkAnnotation(xPos, yPos, 11, lastEditor, editTime);

            setCusrosrPosition(20, -25);
            contentStream.endText();
            contentStream.drawLine(xPos - 20, yPos + 20, 590, yPos + 20);
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(xPos, yPos);
            LineIterator li = new LineIterator(data);
            while (li.moreLines()) {
                String thisLine = li.nextLine();
                if (thisLine.length() > 0) {
                    isNewPage = false;
                    restLineWidth = 120;
                    previousSubLineWidth = 0;
                    parseAndWriteLine(thisLine);
                    startWithBullet = false;
                    setCusrosrPosition(0, -14);
                }
            }
            setCusrosrPosition(-30, -20);
            notesIndex++;
        }
    }

    private void parseAndWriteLine(String line) throws Exception {
        line = line.trim();
        if (line.length() == 0) {
            return;
        } else if (line.equals("{{{")) {
            return;
        } else if (line.startsWith("}}}")) {
            if (line.length() > 3) {
                line = line.substring(3).trim();
                writeRest(line);
            }
            return;
        } else if (line.startsWith("!!!")) {
            if (line.length() > 3) {
                line = line.substring(3).trim();
                contentStream.setFont(bfont, h1_font_size);
                setCusrosrPosition(0, -2);
                writeRest(line);
                contentStream.setFont(font, font_size);
                return;
            }
        } else if (line.startsWith("!!")) {
            if (line.length() > 2) {
                line = line.substring(2).trim();
                contentStream.setFont(bfont, h2_font_size);
                setCusrosrPosition(0, -2);
                writeRest(line);
                contentStream.setFont(font, font_size);
                return;
            }
        } else if (line.startsWith("!")) {
            if (line.length() > 1) {
                line = line.substring(1).trim();
                contentStream.setFont(bfont, h3_font_size);
                setCusrosrPosition(0, -2);
                writeRest(line);
                contentStream.setFont(font, font_size);
                return;
            }
        } else if (line.startsWith("***")) {
            if (line.length() > 3) {
                setCusrosrPosition(60, 0);

                contentStream.setFont(nbfont, h1_font_size);
                writeString(".");
                contentStream.setFont(font, font_size);
                line = line.substring(3).trim();
                writeRest(line);
                setCusrosrPosition(-60, 0);
                return;
            }
        } else if (line.startsWith("**")) {
            if (line.length() > 2) {
                setCusrosrPosition(40, 0);
                contentStream.setFont(nbfont, h1_font_size);
                writeString(". ");
                contentStream.setFont(font, font_size);
                line = line.substring(2).trim();
                writeRest(line);
                setCusrosrPosition(-40, 0);
                return;
            }
        } else if (line.startsWith("*")) {
            if (line.length() > 1) {
                setCusrosrPosition(20, 0);
                startWithBullet = true;
                /*contentStream.endText();
                    
                PDListAttributeObject attributeObject = new PDListAttributeObject();
                PDListAttributeObject.LIST_NUMBERING_CIRCLE
                //System.out.println("bullet-->"+ar.req.getRealPath(("assets/images/images.jpg")));
                PDXObjectImage image = new PDJpeg(document, new FileInputStream(ar.req.getRealPath(("assets/images/bulletLevel1.gif"))));
                    
                PDResources temp = new PDResources();
                //                temp.getXObjects().put("form1", image);
                temp.getXObjects().put("Im0", image);
                page.setResources(temp);
                //                contentStream.drawImage(image, xPos, yPos);
                contentStream.drawXObject(image, xPos, yPos, 1, 1);
                    
                contentStream.beginText();
                setCusrosrPosition(xPos, yPos);
                */
                contentStream.setFont(nbfont, h1_font_size);
                if (previousSubLineWidth > 0) {
                    previousSubLineWidth += font.getStringWidth(". ") / 1000 * 10f;
                } else {
                    previousSubLineWidth += font.getStringWidth(".") / 1000 * 10f;
                }

                writeString(". ");
                contentStream.setFont(font, font_size);
                line = line.substring(1);
                writeRest(line);
                setCusrosrPosition(-20, 0);
                return;
            }
        } else if (line.startsWith(":")) {
            if (line.length() > 1) {
                line = line.substring(1).trim();
                writeRest(line);
            }
        } else if (line.startsWith("----")) {
            contentStream.endText();
            contentStream.fillRect(xPos, yPos, 500, 0.5f);
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(xPos, yPos);
            contentStream.setStrokingColor(Color.black);
            setCusrosrPosition(0, -15);
        } else {
            writeRest(line);
        }
    }

    private String checkForWiki(String line, int i) {
        if ((line.charAt(i) == '_' && line.startsWith("__''", i) && line.substring(i + 4).contains("''__"))) {
            return "bold_italic";
        } else if ((line.charAt(i) == '\'' && line.startsWith("''__", i)
                && line.substring(i + 4).contains("__''"))) {
            return "italic_bold";
        } else if (line.charAt(i) == '_' && (line.length() >= i + 1) && line.charAt(i + 1) == '_'
                && line.substring(2).contains("__")) {
            return "bold";
        } else if (line.charAt(i) == '\'' && (line.length() >= i + 1) && line.charAt(i + 1) == '\'') {
            return "italic";
        } else if (line.charAt(i) == '[' && line.contains("]")) {
            return "hyperlink";
        } else {
            return "";
        }
    }

    private boolean checkMoreToken(String line) {
        if (line.contains("__") || line.contains("''") || (line.contains("'__")) || line.contains("__'")
                || (line.contains("[") && line.contains("]"))) {
            return true;
        } else {
            return false;
        }
    }

    private int getNextIndexOfChars(String line, String findText) {
        if (line.contains(findText)) {
            return line.indexOf(findText);
        } else {
            return -1;
        }
    }

    private void writeRest(String line) throws IOException, Exception {

        while (line.length() > 0) {
            if (checkMoreToken(line)) {
                for (int i = 0; i < line.length(); i++) {
                    String wikiToken = checkForWiki(line, i);
                    if ("bold".equals(wikiToken)) {
                        line = formatAndWrite(line, i, PDType1Font.TIMES_BOLD, "__");
                        break;
                    } else if ("italic".equals(wikiToken)) {
                        line = formatAndWrite(line, i, PDType1Font.TIMES_ITALIC, "''");
                        break;
                    } else if ("bold_italic".equals(wikiToken)) {
                        line = formatAndWrite(line, i, PDType1Font.TIMES_BOLD_ITALIC, "''__");
                        break;
                    } else if ("italic_bold".equals(wikiToken)) {
                        line = formatAndWrite(line, i, PDType1Font.TIMES_BOLD_ITALIC, "__''");
                        break;
                    } else if ("hyperlink".equals(wikiToken)) {
                        wIndex = 0;
                        initializeWrappedListOfLink();
                        String preLink = line.substring(0, i);
                        if (preLink.length() > 0) {
                            writeRest(preLink + " ");
                        }
                        float preLinkWidth = previousSubLineWidth
                                + font.getStringWidth(preLink.substring(wIndex)) / 1000 * 10f;
                        addLinkAnnotation(yPos - 3, 22, line, preLinkWidth, i);
                        contentStream.setNonStrokingColor(Color.black);
                        line = line.substring(line.indexOf("]") + 1);
                        break;
                    }
                }
            } else {
                wrappedAndWriteString(line);
                break;
            }
        }
    }

    private String formatAndWrite(String line, int i, PDType1Font formattedFont, String endFormatText)
            throws Exception, IOException {

        String preLine = line.substring(0, i);
        previousSubLineWidth += font.getStringWidth(preLine) / 1000 * 10f;
        wrappedAndWriteString(preLine);
        if (endFormatText.equals("''__") || endFormatText.equals("__''")) {
            line = line.substring(i + 4);
        } else {
            line = line.substring(i + 2);
        }
        int tillIndex = getNextIndexOfChars(line, endFormatText);
        String formattedWords = line.substring(0, tillIndex).trim() + " ";

        contentStream.setFont(formattedFont, 10);
        wIndex = 0;
        writeRest(formattedWords);
        float fontSize = 10f;
        if (startWithBullet) {
            fontSize = 10.8f;
        }
        if (wrappedListOfLink.size() > 0) {
            previousSubLineWidth += font.getStringWidth(wrappedListOfLink.get(wrappedListOfLink.size() - 1)) / 1000
                    * fontSize;
        }
        contentStream.setFont(PDType1Font.TIMES_ROMAN, 10);

        if (endFormatText.equals("''__") || endFormatText.equals("__''")) {
            line = line.substring(tillIndex + 4);
        } else {
            line = line.substring(tillIndex + 2);
        }
        return line;
    }

    private String wrappedAndWriteString(String line) throws Exception {
        if (line.trim().length() == 0) {
            return line;
        }
        String nLine = line;
        if (nLine.length() <= restLineWidth) {
            contentStream.drawString(line);
            restLineWidth -= line.length();
            wrappedListOfLink.add(line);
            return line;
        } else {
            String trancatedText = line.substring(0, restLineWidth);
            int wrappedIndex = trancatedText.lastIndexOf(" ");
            String wrappedText = trancatedText;
            if (wrappedIndex >= 0) {
                wIndex = wrappedIndex;
                wrappedText = trancatedText.substring(0, wrappedIndex);
                nLine = line.substring(wrappedIndex);
            } else {
                nLine = line.substring(wrappedText.length());
                wIndex = line.indexOf(nLine);
            }
            contentStream.drawString(wrappedText);
            wrappedListOfLink.add(wrappedText);

            setCusrosrPosition(0, -14);
            restLineWidth = 120;
            previousSubLineWidth = 0;
            return wrappedAndWriteString(nLine);
        }

    }

    private void writeString(String line) throws Exception {
        if (line.trim().length() == 0) {
            return;
        }
        String nLine = line;
        if (nLine.length() <= 120) {
            contentStream.drawString(line);
        } else {
            String trancatedText = line.substring(0, 120);
            int wrappedIndex = trancatedText.lastIndexOf(" ");
            String wrappedText = trancatedText.substring(0, wrappedIndex);
            contentStream.drawString(wrappedText);
            nLine = line.substring(wrappedIndex);
            setCusrosrPosition(0, -12);
            writeString(nLine);
        }
    }

    private void addLinkAnnotation(float y, float hieght, String line, float preLinkWidth, int i) throws Exception {

        String link = line.substring(i + 1, line.indexOf("]"));
        String linkName = outputLink(link);
        contentStream.setNonStrokingColor(Color.blue);
        wIndex = 0;
        initializeWrappedListOfLink();
        writeRest(linkName);

        float fontSize = 10f;
        float textWidth = (font.getStringWidth(linkName) / 1000) * fontSize;
        if (startWithBullet) {
            textWidth = (font.getStringWidth(linkName + " ") / 1000) * fontSize;
        }
        if (previousSubLineWidth > 0) {
            preLinkWidth += (font.getStringWidth(" ") / 1000) * fontSize;
        }

        borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
        borderULine.setWidth(0.5f);
        float drawLinkStartingPoint = 0;
        int index = 0;
        for (String text_element : wrappedListOfLink) {
            textWidth = (font.getStringWidth(text_element) / 1000) * fontSize;
            if (index == 0) {
                drawLinkStartingPoint = xPos + preLinkWidth + 2;
                if (wrappedListOfLink.size() > 1) {
                    previousSubLineWidth = 0;
                } else {
                    previousSubLineWidth = ((font.getStringWidth(text_element) / 1000) * 10f) + preLinkWidth;
                }
            } else if (index == wrappedListOfLink.size() - 1) {
                drawLinkStartingPoint = xPos;
                previousSubLineWidth = (font.getStringWidth(text_element) / 1000) * fontSize;
            } else {
                drawLinkStartingPoint = xPos;
                previousSubLineWidth = 0;
            }
            createLink(drawLinkStartingPoint, y + 1, textWidth, 10, link);

            preLinkWidth = 0;
            index++;
            if (wrappedListOfLink.size() > 1) {
                y -= 15;
            }
        }
    }

    private void addUserLinkAnnotation(float x, float y, float hieght, String userId, String editTime)
            throws Exception {

        StringWriter writer = new StringWriter();
        AuthRequest clone = new AuthDummy(ar.getUserProfile(), writer);
        clone.setNewUI(true);
        clone.retPath = ar.baseURL;
        UserProfile.writeLink(clone, userId);

        Map<String, String> userInfoMap = parseStringForUserInfo(writer.toString());
        String cleanName = "";
        if (userInfoMap.containsKey("cleanName")) {
            cleanName = userInfoMap.get("cleanName");
        }

        String editedBy = "    Last edited by " + cleanName + " " + editTime;
        float rightMargin = 55f;
        if (editedBy.length() > 60) {
            rightMargin = 20f;
        } else if (editedBy.length() < 30) {
            rightMargin = 50f;
        }

        int alignFromRight = (int) ((595 - (((font.getStringWidth(editedBy) / 1000) * 10f) + rightMargin)));

        if (userId.length() == 0) {
            alignFromRight -= 80;
        }
        setCusrosrPosition(alignFromRight, 0);

        writeRest("    Last edited by ");
        contentStream.setNonStrokingColor(Color.blue);
        writeRest(cleanName);
        contentStream.setNonStrokingColor(Color.black);
        writeRest("  " + editTime);

        String link = "";
        if (userInfoMap.containsKey("link")) {
            link = userInfoMap.get("link");
        }

        float textWidth = (font.getStringWidth(cleanName) / 1000) * 10f;

        createLink(x + alignFromRight + ((font.getStringWidth("    Last edited by ") / 1000) * 10f), yPos - 2,
                textWidth, 11, link);

        setCusrosrPosition(-alignFromRight, 0);

    }

    private void createLink(float x, float y, float textWidth, float height, String link) throws IOException {
        PDRectangle position = new PDRectangle();
        position.setLowerLeftX(x);
        position.setLowerLeftY(y); // down a couple of points
        position.setUpperRightX(x + textWidth);
        position.setUpperRightY(y + height);

        uri = new PDActionURI();
        uri.setURI(link);

        PDAnnotationLink txtLink = new PDAnnotationLink();
        txtLink.setRectangle(position);
        txtLink.setAction(uri);
        txtLink.setBorderStyle(borderULine);
        PDGamma gamma = new PDGamma();
        gamma.setB(1);
        txtLink.setColour(gamma);
        @SuppressWarnings("unchecked")
        List<PDAnnotationLink> annotations = page.getAnnotations();
        annotations.add(txtLink);

    }

    private Map<String, String> parseStringForUserInfo(String writer) {
        Map<String, String> userInfoMap = new HashMap<String, String>();
        if (writer.contains("<a")) {
            int beginIndex = writer.indexOf("href=\"") + 6;
            String tmp = writer.substring(beginIndex);

            int endIndex = tmp.indexOf("\"");

            String link = writer.substring(beginIndex, beginIndex + endIndex);

            beginIndex = writer.indexOf("red\">") + 5;
            endIndex = writer.indexOf("</span>");

            String cleanName = writer.substring(beginIndex, endIndex);

            userInfoMap.put("link", link);
            userInfoMap.put("cleanName", cleanName);
        } else {
            userInfoMap.put("cleanName", writer);
        }
        return userInfoMap;
    }

    private String outputLink(String linkURL) throws Exception {
        boolean isImage = linkURL.startsWith("IMG:");

        int barPos = linkURL.indexOf("|");
        String linkName = linkURL.trim();
        String linkAddr = linkName;
        boolean userSpecifiedName = false;

        if (barPos >= 0) {
            linkName = linkURL.substring(0, barPos).trim();
            linkAddr = linkURL.substring(barPos + 1).trim();
            userSpecifiedName = true;
        }

        // We treat any address that has forward slashes in it as an external
        // address which is included literally into the href.
        boolean isExternal = (linkAddr.startsWith("http") && linkAddr.indexOf("/") >= 0);
        boolean pageExists = true;

        //if the link is missing, then just write the name out
        //might also include an indicator of the problem ....
        if (linkAddr.length() == 0) {
            return linkName;
        }

        if (!isExternal) {
            //if the sanitized version of the link is empty, which might happen if
            //the link was all punctuation, then just write the name out
            //might also include an indicator of the problem ....
            String sanitizedName = SectionWiki.sanitize(linkAddr);
            if (sanitizedName.length() == 0) {
                return linkName;
            }

            Vector<NGPageIndex> foundPages = NGPageIndex.getPageIndexByName(linkAddr);
            if (foundPages.size() == 1) {
                NGPageIndex foundPI = foundPages.firstElement();
                linkAddr = ar.retPath + ar.getResourceURL(foundPI, "public.htm");
                if (!userSpecifiedName) {
                    linkName = foundPI.containerName; //use the best name for page
                }
                pageExists = !foundPI.isDeleted;
            } else if (foundPages.size() == 0) {
                pageExists = false;
                NGPage sourcePage = (NGPage) ar.ngp;
                String bookName = "mainbook";
                String sourceName = "main";
                if (sourcePage != null) {
                    sourceName = sourcePage.getFullName();
                    NGBook ngb = sourcePage.getSite();
                    if (ngb != null) {
                        bookName = ngb.getKey();
                    }
                }

                if (ar.isNewUI() && ar.isLoggedIn()) {
                    UserProfile up = ar.getUserProfile();
                    linkAddr = ar.retPath + "v/" + up.getKey() + "/watchedProjects.htm?projectName="
                            + SectionUtil.encodeURLData(linkURL) + "&bookKey="
                            + SectionUtil.encodeURLData(bookName);
                } else {
                    linkAddr = ar.retPath + "CreatePage.jsp?pt=" + SectionUtil.encodeURLData(linkAddr) + "&b="
                            + SectionUtil.encodeURLData(bookName) + "&s=" + SectionUtil.encodeURLData(sourceName);
                }
            } else {
                //this is the case where there is more than one page
                linkAddr = ar.retPath + "Disambiguate.jsp?n=" + SectionUtil.encodeURLData(linkAddr);

            }
        }
        if (isImage) {
            linkName = linkName.substring(4);
            if (pageExists) {
                uri = new PDActionURI();
                uri.setURI(linkAddr);
                /*ar.write("\n<a href=\"");
                ar.writeHtml(linkAddr);
                ar.write("\" title=\"");
                ar.writeHtml(titleValue);
                ar.write("\">");
                ar.write("<img src=\"");
                ar.writeHtml(linkName);
                ar.write("\"/>");
                ar.write("</a>\n");
                */
            } else {
                /*
                ar.write("<img src=\"");
                ar.writeHtml(linkName);
                ar.write("\"/>");
                */
            }
        } else //not an image
        {
            if (pageExists) {
                uri = new PDActionURI();
                uri.setURI(linkAddr);
                /*
                ar.write("\n<a href=\"");
                ar.writeHtml(linkAddr);
                ar.write("\" title=\"");
                ar.writeHtml(titleValue);
                ar.write("\">");
                ar.writeHtml(linkName);
                ar.write("</a>\n");
                */
            } else if (!ar.isLoggedIn() || ar.isStaticSite()) {
                //if page does not exist, and you are not linked in, then simply display
                //the name without making it a link.  Anonymous people will only see
                //links (within the wiki) that work.

                //ar.writeHtml(linkName);
                return linkName;

            } else {
                uri = new PDActionURI();
                uri.setURI(linkAddr);
                /*
                ar.write("<a href=\"");
                ar.writeHtml(linkAddr);
                ar.write("\" title=\"");
                ar.writeHtml(titleValue);
                ar.write("\">");
                ar.writeHtml(linkName);
                //the icon indicates condition of page
                ar.write("<img src=\"");
                ar.write(ar.retPath);
                ar.write(specialGraphic);
                ar.write("\"/>");
                ar.write("</a>");
                */
            }
        }
        return linkName;
    }

    public static void main(String[] args) { //For test
        try {
            String path = args[0];
            PDDocument document = new PDDocument();
            PDPage page = new PDPage();
            page.setMediaBox(PDPage.PAGE_SIZE_A4);
            document.addPage(page);
            PDFont font = PDType1Font.HELVETICA;

            PDPageContentStream contentStream = new PDPageContentStream(document, page, false, false);
            contentStream.beginText();
            contentStream.setFont(font, 12);
            contentStream.moveTextPositionByAmount(100, 800);
            String x = "hello world";
            contentStream.drawString(x);
            contentStream.moveTextPositionByAmount(-90, -15);
            contentStream.setFont(font, 12);
            contentStream.drawString("Hello World3");
            contentStream.endText();
            contentStream.close();
            document.save(path);
            document.close();
            System.out.println("DONE..");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}