簡體   English   中英

更改頁面時的PdfBox問題

[英]PdfBox issue while changing page

我不是問這類問題的忠實擁護者,但是,嘗試解決我的代碼中的這個錯誤已經整整三天了。

我知道這是一個邏輯問題,我知道如何解決這個問題,但是當涉及到將我的想法轉化為代碼時,我只是無法使其按需工作。

我正在研究合同背書(合同的修改),該書將比較2個表中的數據,如果其中任何一個已更改,則僅繪制該信息。

有時,諸如條件之類的變化信息的長度會增加或減少,這就是問題所在。

我制定了一種算法,一旦完成繪制信息,它將獲得最小的Y坐標,但是當我更改頁面Y坐標時,必須將其重置為700f並從此處重新開始繪制。

我使用的代碼最初是由另一個不在這里的程序員制作的,我不知道如何用PDF編寫MCVE

但是以下是我認為可以幫助您的方法。

我如何比較和繪制PDF上的信息的示例:

sOffAsOffE是從一個名為Class對象SubscriptionOfferA代表AgreementEEndorsement 認可是MySQL上的表Agreement的副本,但信息已修改。 可能這是無關的信息,也許不是。

if (!nullOrEmpty(sOffA.getGeneralConditions()) &&
    !nullOrEmpty(sOffE.getGeneralConditions())) {
    if (!getStringValue(sOffA.getGeneralConditions()).
    equals(getStringValue(sOffE.getGeneralConditions()))) {
    minYs[0] = pdf.rText(LEFT_MARGIN, y, 10, 
                 constants.generalConditions(),
                 getStringValue(sOffA.
                        getGeneralConditions()));

    minYs[1] = pdf.rText(HALF_PAGE, y, 10, 
                 constants.generalConditions(),
                 getStringValue(sOffE.
                        getGeneralConditions()));

    y = checkY(pdf, minYs);
    }
} else if (nullOrEmpty(sOffA.getGeneralConditions()) &&
       !nullOrEmpty(sOffE.getGeneralConditions())) {
    minYs[0] = pdf.rText(LEFT_MARGIN, y, 10, "", "");

    minYs[1] = pdf.rText(HALF_PAGE, y, 10, 
             constants.generalConditions(),
             getStringValue(sOffE.
                    getGeneralConditions()));

    y = checkY(pdf, minYs);
} else if (!nullOrEmpty(sOffA.getGeneralConditions()) &&
       nullOrEmpty(sOffE.getGeneralConditions())) {
    minYs[0] = pdf.rText(LEFT_MARGIN, y, 10, 
             constants.generalConditions(),
             getStringValue(sOffA.
                    getGeneralConditions()));

    minYs[1] = pdf.rText(HALF_PAGE, y, 10, "", "");

    y = checkY(pdf, minYs);
}

我使用的數組是這個數組:

private float[] minYs = new float[] {700, 700, 700, 700, 700, 700, 700,
                                     700, 700};

這是方法checkY ,它檢查數組中的哪個Y(如上所示)是最小的Y,然后針對所有元素將整個數組重新啟動回700f。 然后檢查最低Y坐標下方的空間是否足以繪制下一個項目。

private float checkY(PdfRenderingEndorsement pdf, float... ys) throws Exception {
    float y2 = getMinY(pdf, ys);
    for (int i = 0; i < ys.length; i++) {
        ys[i] = 700;
    }
    y2 = pdf.checkContentStream(y2, 5, 10);
    return y2;      
}

這種方法是我猜想我的邏輯問題所在的地方,並且您可以看到我嘗試了不同的事情,原始算法只是for-each部分,然后我嘗試了沒有成功的其他事情。

private float getMinY(PdfRenderingEndorsement pdf, float... ys) {
    float result = 700f;
    float lowest1 = 0, lowest2 = 0;
    for (int i = 0; i < ys.length; i++) {
        for (int j = 0; j < ys.length; j++) {
        if (ys[j] > ys[i]) {
            float aux = ys[i];
            ys[i] = ys[j];
            ys[j] = aux;
            //lowest1 = ys[i];
            //lowest2 = ys[j];
        }
        }
    }
    if (ys.length > 1) {
        lowest1 = ys[0];
        lowest2 = ys[1];
    }
    LOGGER.trace("lowest1: " + lowest1);
    LOGGER.trace("lowest2: " + lowest2);
    LOGGER.trace("newPage " + pdf.getNewPage());
    /*if(pdf.getNewPage()) {
        return lowest1 > lowest2 ? lowest2 : lowest1;
      }
    */
    /*for (float y : ys) {
        if (y < result) {
        result = y;
        }
        }*/
    return lowest1 > lowest2 && pdf.getNewPage() ? lowest1 : lowest2;
    //return lowest1;
}

我獲取對象的String值並檢查它們是否為null或為空的方法:

private boolean nullOrEmpty(String s) {
    return s == null || s.isEmpty();
}

private String getStringValue(Object o) {
    if (o == null) {
        return "";
    }
    return getStringValue(o, null);
}

private String getStringValue(Object o, Class< ? extends Unit> clazz) {
    if (o instanceof Boolean) {
        Boolean bd = (Boolean) o;
        if (bd) {
        return constants.getString("dbeditorYes");
        } else {
        return constants.getString("dbeditorNo");
        }
    } else if (o instanceof Date) {
        Date date = (Date) o;
        DateFormat df = new SimpleDateFormat(DateConstants.DATE_FORMAT);
        return df.format(date);
    } else if (o instanceof Enum) {
        Enum en = (Enum) o;
        return constants.enumMap().get(en.toString());
    } else if (o instanceof Integer) {
        Integer integer = (Integer) o;
        if (clazz == null) {
        return String.valueOf(integer);
        } else {
        Unit entry = unitSvc.get(clazz, integer);
        String[] params = entry.toString().split("\\|");
        String label = params.length == 1 ? params[0] : params[1];
        return label;
        }
    } else if (o instanceof BigDecimal) {
        BigDecimal bd = (BigDecimal) o;
        DecimalFormat df = new DecimalFormat("#,##0");
        df = new DecimalFormat("#,##0.00");
        return df.format(bd);
    } else if (o instanceof Float) {
        Float bd = (Float) o;
        DecimalFormat df = new DecimalFormat("#,##0");
        df = new DecimalFormat("#,##0.00");
        return df.format(bd);
    } else if (o instanceof String) {
        String td = (String) o;
        return td;
    }
    return "";
}

以上所有方法均對應於PdfEndorsement類。

這是PdfRenderingEndorsement類,它是實際繪制數據的類(由於使用了所有方法,因此是完整的類):

public class PdfRenderingEndorsement {

    private static final Logger LOGGER = Logger.
    getLogger(PdfRenderingEndorsement.class);

    private static final float BOTTOM_MARGIN = 60;

    private static final int DESC_WIDTH = 269; //For description fields

    private static final int FIELD_WIDTH = 70;

    private static final int FIELD_WIDTH2 = 60;

    private static final int FIELD_WIDTH3 = 60;

    private static final int FIELD1 = 112;

    private static final int VALUE1 = 112;

    private static final int FIELD2 = 80;

    private static final int VALUE2 = 80;

    private static final int VALUE_WIDTH = 80;

    private static final int VALUE_WIDTH2 = 60;

    private static final int VALUE_WIDTH3 = 80;

    private static final int HALF_WIDTH = 325;

    private static final int TEXT_WIDTH = 410; //For text fields

    private final RwaConstants constants = ConstantsGetter.getInstance();

    private final PDDocument doc;

    private final String logoPath;

    private final String[] header;

    private int count = 0;

    private boolean newPage;

    private PDPageContentStream content;

    /**
     * Empty constructor. Used only to initialize the rendering class and call
     * it's methods.
     */
    public PdfRenderingEndorsement(PDDocument doc, String logoPath, 
                   String[] header) {
    this.doc = doc;
    this.logoPath = logoPath;
    this.header = header;
    }

    public float checkContentStream2(float y, int lines, int space) 
    throws Exception {
    float newY = checkYCoord2(y, lines, space);
    if (newY == 700) {
        if (content != null) {
        content.close();
        }

        File file = new File(logoPath);
        PDJpeg logoImg = new PDJpeg(doc, new FileInputStream(file));
        PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
        doc.addPage(page);
        content = new PDPageContentStream(doc, page);
        content.drawImage(logoImg, 50, 720);
        rHeader();
    }
    return newY;
    }

    private float checkYCoord2(float y, int lines, int space) {
    float newY = y;
    for (int i = 0; i < lines; i++) {
        if ((newY - space) <= BOTTOM_MARGIN) {
        newY = 700f;
        return newY;
        } else {
        newY = newY - space;
        }
    }
    return y;
    }

    public boolean getNewPage() {
    return newPage;
    }

    public float checkContentStream(float y) throws Exception {
    float newY = checkYCoord(y, 1, 10);
    if (newY == 700) {
        if (content != null) {
        content.close();
        }
        File file = new File(logoPath);
        PDJpeg logoImg = new PDJpeg(doc, new FileInputStream(file));
        PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
        doc.addPage(page);
        content = new PDPageContentStream(doc, page);
        content.drawImage(logoImg, 50, 720);
        rHeader();
    }
    return newY;
    }

    public float checkYCoord(float y, int lines, int space) {
    float newY = y;
    for (int i = 0; i < lines; i++) {
        if ((newY - space) <= BOTTOM_MARGIN) {
        newY = 700f;
        return newY;
        } else {
        newY = newY - space;
        }
    }
    return y;
    }

    public float checkContentStream(float y, int lines, int space) 
    throws Exception {
    float newY = checkYCoord(y, lines, space);
    if (newY == 700) {
        if (content != null) {
        content.close();
        }
        File file = new File(logoPath);
        PDJpeg logoImg = new PDJpeg(doc, new FileInputStream(file));
        PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
        doc.addPage(page);
        content = new PDPageContentStream(doc, page);
        content.drawImage(logoImg, 50, 720);
        rHeader();
    }
    return newY;
    }

    public void closeContentStream() throws Exception {
    if (content != null) {
        content.close();
    }
    }

    /**
     * Renders the header for slip documents.
     */
    public void rHeader() throws Exception {
    float y = 760f;
    content.setLineWidth(.5f);
    content.setFont(PDType1Font.TIMES_ROMAN, 9);
    content.setNonStrokingColor(Color.GRAY);
    content.drawLine(50, 710, 562, 710);

    y = rText(150, y + 19, 10, constants.endorsement(), null,
          TEXT_WIDTH, 0);
    y = rText(150, y + 9, 10, header[0], null, TEXT_WIDTH, 0);
    y = rText(150, y + 9, 10, header[1], null, TEXT_WIDTH, 0);
    y = rText(150, y + 9, 10, header[2], null, TEXT_WIDTH, 0);
    y = rText(150, y + 9, 10, header[3], null, TEXT_WIDTH, 0);
    content.setNonStrokingColor(Color.BLACK);
    content.setFont(PDType1Font.TIMES_ROMAN, 9);
    }

    public float rText(float x, float y, int space, String labelField,
               String value) 
    throws Exception {
    return rText(x, y, space, labelField, value, FIELD_WIDTH, 
             HALF_WIDTH - 2 * FIELD_WIDTH - 10);    
    }

    public float rTextLR(float x, float y, int space, String labelField,
               String value) 
    throws Exception {
    return rText(x, y, space, labelField, value, 0, 
             HALF_WIDTH - 2 * FIELD_WIDTH - 10);    
    }

    public float rText(float x, float y, int space, String labelField,
               String value, int fieldWidth) 
    throws Exception {
    if (fieldWidth == 0) {
        return rText(x, y, space, labelField, value, FIELD_WIDTH2, 
             VALUE_WIDTH2);
    } else if (fieldWidth == 1) {
        return rText(x, y, space, labelField, value, FIELD_WIDTH3,
             VALUE_WIDTH3);
    } else if (fieldWidth == 2) {
        return rText(x, y, space, labelField, value, TEXT_WIDTH,
             TEXT_WIDTH);
    }
    return y;
    }


    public float getFieldSize(int fs) {
    switch(fs) {
    case 1:
        return (FIELD_WIDTH + VALUE_WIDTH);
    case 2:
        return (FIELD_WIDTH + DESC_WIDTH);
    case 3:
        return (FIELD_WIDTH + TEXT_WIDTH);
    case 4:
        return (HALF_WIDTH - FIELD_WIDTH);
    case 5:
        return (FIELD_WIDTH + TEXT_WIDTH);
    case 6:
        return (FIELD_WIDTH + TEXT_WIDTH);
    case 7:
        return (FIELD1 + 19) / 2;
    case 8:
        return (FIELD2 + 19) / 2;
    default:
        return 0;
    }
    }

    public void paintLinesH(float y) throws Exception {
    content.drawLine(49, y - 6, 327, y - 6);
    content.drawLine(335, y - 6, 563, y - 6);
    }

    public void paintLinesV(float x, float yMax, float yMin)
    throws Exception {
    content.drawLine(x - 1, yMax - 6, x - 1, yMin - 6);
    }

    public float rText(float x, float y, int space, String labelField,
               String value, int fieldWidth, int valueWidth) 
    throws Exception {
    PDFont font = PDType1Font.TIMES_BOLD;
    content.setFont(font, 9);
    float y1 = 0f;
    float y2 = 0f;
    if (value == null) {
        return rText(labelField, fieldWidth, x, y - 19, space, font, false);
    } else {
        if (labelField == null) {
        font = PDType1Font.TIMES_ROMAN;
        content.setFont(font, 9);
        return rText(value, valueWidth, x, y - 19, space, font, true);
        } else {
        y1 = rText(labelField, fieldWidth, x, y - 30, space, font, 
               false);
        font = PDType1Font.TIMES_ROMAN;
        content.setFont(font, 9);
        float y3 = y;
        y2 = rText(value, valueWidth, x + fieldWidth + 10, y - 30,
               space, font, true);
        if (y3 < y2) {
            return y2;
        } else {
            if (y1 >= y2) {
            return y2;
            } else {
            return y1;
            }
        }
        }
    }
    }

    private ArrayList<String> getRows(String text, int width, PDFont font)
    throws Exception {
    float textWidth = font.getStringWidth(text) / 1000f * 9f;
    ArrayList<String> result = Lists.newArrayList();
    if (textWidth < width) {
        result.add(text);
        return result;
    }

    float spaceWidth = font.getStringWidth(" ") / 1000f * 9f;
    String[] paragraphs = text.split("\n|\r\n|\r");
    for (String paragraph : paragraphs) {
        float pWidth = font.getStringWidth(paragraph) / 1000f * 9f;
        if (pWidth < width) {
        result.add(paragraph);
        continue;
        }

        float widthCount = 0f;
        String[] words = paragraph.trim().split(" ");
        StringBuilder sb = new StringBuilder();
        for (int j = 0; j < words.length; j++) {
        if (words[j].trim().length() == 0) {
            continue;
        }

        float wWidth = font.getStringWidth(words[j]) / 1000f * 9f;
        float totalWidth = widthCount + wWidth + spaceWidth;
        if (totalWidth < width + spaceWidth) {
            sb.append(words[j]);
            sb.append(" ");
            widthCount = totalWidth;
        } else {
            result.add(sb.toString().trim());
            sb = new StringBuilder();
            sb.append(words[j]);
            sb.append(" ");
            widthCount = totalWidth - widthCount;
        }
        }
        result.add(sb.toString().trim());
    }
    return result;
    }

    private float rText(String text, int width, float x, float y, int space,
            PDFont font, boolean isValue) throws Exception {
    float newY = y;
    int rowHeight = 0;
    newPage = false;
    ArrayList<String> rowList = getRows(text, width, font);
    if (isValue) {
        for (String row : rowList) {
        if (rowHeight >= 10) {
            newY = checkContentStream(newY - 10);
            newY = newY == 700 ? 680 : newY;
            if (newY <= 700 && !newPage) {
            newPage = true;
            }
            rowHeight = newY == 680 ? 0 : rowHeight;
        }
        content.beginText();
        content.moveTextPositionByAmount(x, newY);
        content.drawString(row);
        content.endText();
        rowHeight = rowHeight + 10;
        }
    } else {
        for (String row : rowList) {
        content.beginText();
        content.moveTextPositionByAmount(x, newY - rowHeight);
        content.drawString(row);
        content.endText();
        rowHeight = rowHeight + 10;
        }
        newY -= (rowHeight - 10);
    }
    return newY;
    }
}

這是原始( for-each )方法輸出的PDF示例

如果您看不到PDF,請告訴我,但是這里還有一些屏幕截圖:

在此處輸入圖片說明

這是帶有getMinY方法上未注釋代碼的輸出的PDF示例

通過此修改,這里是輸出:

在此處輸入圖片說明

如您所見,第一個輸出“跳轉”到下一頁,因為假設“ Texto de Poliza”右側的文本在Y坐標680、670或類似位置處結束,但是在左側我畫了一個空白字段("") ,其結尾數接近這些數字的90或100。

然后比較100 <670? 是的,然后我取了50到100,它比我的BOTTOM_MARGIN (它是60)低,因此它關閉了實際頁面(現在是文本結尾的位置,但認為它在它之前的頁面上)並創建了一個新頁面。

我問過類似的問題差不多一年之前這里 ,這些類是幾乎從這些文件的副本,但因為數據處理方式稍有不同在我的邏輯這個bug與這些文件只配備。

好在那堵文字牆之后,我希望有人能讀懂它並實際上幫我忙,也許我錯過了重要的一部分,但找不到自動取款機。

提前致謝。

編輯

在將@mkl的答案添加到我的方法中后,我發現,如果雙方的信息均未更改,則會造成差距,而且效果也不佳。

在此處輸入圖片說明

這就是我將數據發送到PdfRenderingEndorsementAlternative

for (String[] data: sOppData) {
        //float y = renderer.getPreviousBandBase;
        for (int i = 0; i < data.length - 2; i += 3) {
            if (!nullOrEmpty(data[i + 1]) &&
                !nullOrEmpty(data[i + 2])) {
                if (!data[i + 1].equals(data[i + 2])) {
                renderer.
                    render(new BandColumn(leftHalfPageField,
                              data[i], data[i + 1]),
                       new BandColumn(rightHalfPageField,
                              data[i], data[i + 2])
                       );
                }
            } else if (nullOrEmpty(data[i + 1]) &&
                   !nullOrEmpty(data[i + 2])) {
                renderer.
                render(new BandColumn(leftHalfPageField, 
                              "", ""),
                       new BandColumn(rightHalfPageField,
                              data[i], data[i + 2])
                       );
            } else if (!nullOrEmpty(data[i + 1]) &&
                   nullOrEmpty(data[i + 2])) {
                renderer.
                render(new BandColumn(leftHalfPageField,
                              data[i], data[i + 1]),
                       new BandColumn(rightHalfPageField,
                              "", "")
                       );
            }
        }
        //float y2 = renderer.getPreviousBandBase();
        /*if (y2 < y) 
            renderer.gap(20);
        */
        renderer.gap(20); 
  }

以上評論的驗證是否正確,還是我將回到過去引發錯誤的方法? 我應該在PdfRenderingEndorsementAlternative上添加getPreviousBandBase()方法還是以其他方式直接在render()方法上進行操作?

這就是我如何獲取雙方當前具有相同信息的數據。

例如:

sOppA.getContractName()sOppE.getContractName()都是"Hello World" ,並且兩者相等,因此會留出間隙,如屏幕截圖所示。

private ArrayList<String []> renderSubscriptionOpportunity(
               SubscriptionOpp sOppA, SubscriptionOpp sOppE, 
               ArrayList<Location> lcA, ArrayList<Location> lcE) 
    throws Exception {
    ArrayList <String[]> sOppData = new ArrayList<String[]>();

    sOppData.add(new String[] {constants.currencyId(),
                   getStringValue(sOppA.getCurrencyId(), 
                          Currency.class),
                   getStringValue(sOppE.getCurrencyId(),
                          Currency.class)});

    sOppData.add(new String[] {constants.contractName(),
                   getStringValue(sOppA.getContractName()),
                   getStringValue(sOppE.getContractName())});

    sOppData.add(new String[] {constants.mainActivityId(),
                   getStringValue(sOppA.getMainActivityId(),
                          MainActivity.class),
                   getStringValue(sOppE.getMainActivityId(),
                          MainActivity.class)});

    //here add location table

    if (lcA.size() > 1 && lcE.size() > 1) {
        int lastIdA = 0;
        int lastIdE = 0;
        int size = lcA.size() >= lcE.size() ? lcA.size() : lcE.size();

        LOGGER.trace("size: " + size + " lcA.size(): " + lcA.size() +
             " lcE.size(): " + lcE.size());
        for (int pos = 1; pos < lcA.size(); pos++) {
        StringBuilder aSb = new StringBuilder();
        StringBuilder eSb = new StringBuilder();
        String valueA = "";
        String valueE = "";
        if (pos < lcA.size()) {
            Country countryA = unitSvc.get(Country.class, 
                           lcA.get(pos).getCountryId());
            LOGGER.trace("Entro1");
            if (countryA.getId() != lastIdA) {
            aSb.append(countryA.getName());
            lastIdA = countryA.getId();
            } else {
            aSb.append("");
            }
        } else {
            aSb.append("");
        }       
        if (pos < lcE.size()) {
            Country countryE = unitSvc.get(Country.class, 
                           lcE.get(pos).getCountryId());
            LOGGER.trace("Entro2");
            if (countryE.getId() != lastIdE) {
            eSb.append(countryE.getName());
            lastIdE = countryE.getId();
            } else {
            eSb.append("");
            }
        } else {
            eSb.append("");
        }
        valueA = aSb.toString();
        valueE = eSb.toString();
        sOppData.add(new String[] {pos == 1 ? constants.countryId() : 
                       "", valueA, valueE});
        }
    }
    return sOppData;
}

正如評論中已經暗示的那樣(實際上已經在對您先前的問題的評論中),我認為您的渲染類的整個體系結構都需要進行大修。 基於您的PdfRenderingEndorsement我創建了以下類PdfRenderingEndorsementAlternative ,它表示該渲染的另一種方法:

public class PdfRenderingEndorsementAlternative implements AutoCloseable
{
    //
    // misc constants
    //
    static final int FIELD_WIDTH = 70;
    static final int HALF_WIDTH = 325;
    static final int TEXT_WIDTH = 410;

    static final float BOTTOM_MARGIN = 70;
    static final int LEFT_MARGIN = 50;

    //
    // rendering
    //
    public void gap(int size)
    {
        previousBandBase-=size;
    }

    public void render(BandColumn... columns) throws IOException
    {
        if (content == null)
            newPage();

        final List<Chunk> chunks = new ArrayList<Chunk>();
        for (BandColumn column : columns)
        {
            chunks.addAll(column.toChunks());
        }

        float offset = 0;
        while (!chunks.isEmpty())
        {
            float lowestAddedY = previousBandBase;
            float highestBaseBeforeNonAdded = Float.NEGATIVE_INFINITY;
            List<Chunk> added = new ArrayList<Chunk>();
            for (Chunk chunk: chunks)
            {
                float y = previousBandBase + chunk.y + offset; 
                if (y >= BOTTOM_MARGIN)
                {
                    content.beginText();
                    content.setFont(chunk.font, 9);
                    content.moveTextPositionByAmount(chunk.x, y);
                    content.drawString(chunk.text);
                    content.endText();
                    // draw
                    if (y < lowestAddedY)
                        lowestAddedY = y;
                    added.add(chunk);
                }
                else
                {
                    float baseBefore = chunk.y + chunk.space;
                    if (baseBefore > highestBaseBeforeNonAdded)
                        highestBaseBeforeNonAdded = baseBefore;
                }
            }
            chunks.removeAll(added);
            if (!chunks.isEmpty())
            {
                newPage();
                offset = -highestBaseBeforeNonAdded;
            }
            else
            {
                previousBandBase = lowestAddedY;
            }
        }
    }

    static public class BandColumn
    {
        public enum Layout
        {
            headerText(150, TEXT_WIDTH, 0, 10),
            leftHalfPageField(LEFT_MARGIN, FIELD_WIDTH, HALF_WIDTH - 2 * FIELD_WIDTH - 10, 10),
            rightHalfPageField(HALF_WIDTH, FIELD_WIDTH, HALF_WIDTH - 2 * FIELD_WIDTH - 10, 10);

            Layout(float x, int fieldWidth, int valueWidth, int space)
            {
                this.x = x;
                this.fieldWidth = fieldWidth;
                this.valueWidth = valueWidth;
                this.space = space;
            }

            final float x;
            final int fieldWidth, valueWidth, space;
        }

        public BandColumn(Layout layout, String labelField, String value)
        {
            this(layout.x, layout.space, labelField, value, layout.fieldWidth, layout.valueWidth);
        }

        public BandColumn(float x, int space, String labelField, String value, int fieldWidth, int valueWidth)
        {
            this.x = x;
            this.space = space;
            this.labelField = labelField;
            this.value = value;
            this.fieldWidth = fieldWidth;
            this.valueWidth = valueWidth;
        }

        List<Chunk> toChunks() throws IOException
        {
            final List<Chunk> result = new ArrayList<Chunk>();
            result.addAll(toChunks(0, fieldWidth, PDType1Font.TIMES_BOLD, labelField));
            result.addAll(toChunks(10 + fieldWidth, valueWidth, PDType1Font.TIMES_ROMAN, value));
            return result;
        }

        List<Chunk> toChunks(int offset, int width, PDFont font, String text) throws IOException
        {
            if (text == null || text.length() == 0)
                return Collections.emptyList();

            final List<Chunk> result = new ArrayList<Chunk>();
            float y = -space;
            List<String> rows = getRows(text, width, font);
            for (String row: rows)
            {
                result.add(new Chunk(x+offset, y, space, font, row));
                y-= space;
            }
            return result;
        }

        final float x;
        final int space, fieldWidth, valueWidth;
        final String labelField, value;
    }

    //
    // constructor
    //
    public PdfRenderingEndorsementAlternative(PDDocument doc, InputStream logo, 
            String[] header) throws IOException
    {
        this.doc = doc;
        this.header = header;
        logoImg = new PDJpeg(doc, logo);
    }

    //
    // AutoCloseable implementation
    //
    @Override
    public void close() throws IOException
    {
        if (content != null)
        {
            content.close();
            content = null;
        }
    }

    //
    // helper methods
    //
    void newPage() throws IOException
    {
        close();

        PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
        doc.addPage(page);
        content = new PDPageContentStream(doc, page);
        content.drawImage(logoImg, 50, 720);
        content.setLineWidth(.5f);
        content.setNonStrokingColor(Color.GRAY);
        content.drawLine(50, 710, 562, 710);

        previousBandBase = 770;
        render(new BandColumn(BandColumn.Layout.headerText, "ENDOSO", null));
        for (String head: header)
            render(new BandColumn(BandColumn.Layout.headerText, head, null));

        content.setNonStrokingColor(Color.BLACK);
        previousBandBase = 680;
    }

    // original method
    static List<String> getRows(String text, int width, PDFont font) throws IOException
    {
        float textWidth = font.getStringWidth(text) / 1000f * 9f;
        ArrayList<String> result = new ArrayList<String>();// Lists.newArrayList();
        if (textWidth < width)
        {
            result.add(text);
            return result;
        }

        float spaceWidth = font.getStringWidth(" ") / 1000f * 9f;
        String[] paragraphs = text.split("\n|\r\n|\r");
        for (String paragraph : paragraphs)
        {
            float pWidth = font.getStringWidth(paragraph) / 1000f * 9f;
            if (pWidth < width)
            {
                result.add(paragraph);
                continue;
            }

            float widthCount = 0f;
            String[] words = paragraph.trim().split(" ");
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < words.length; j++)
            {
                if (words[j].trim().length() == 0)
                {
                    continue;
                }

                float wWidth = font.getStringWidth(words[j]) / 1000f * 9f;
                float totalWidth = widthCount + wWidth + spaceWidth;
                if (totalWidth < width + spaceWidth)
                {
                    sb.append(words[j]);
                    sb.append(" ");
                    widthCount = totalWidth;
                }
                else
                {
                    result.add(sb.toString().trim());
                    sb = new StringBuilder();
                    sb.append(words[j]);
                    sb.append(" ");
                    widthCount = totalWidth - widthCount;
                }
            }
            result.add(sb.toString().trim());
        }
        return result;
    }

    //
    // helper classes
    //
    static class Chunk
    {
        Chunk(float x, float y, int space, PDFont font, String text)
        {
            this.x = x;
            this.y = y;
            this.space = space;
            this.font = font;
            this.text = text;
        }

        final float x, y;
        final int space;
        final PDFont font;
        final String text;
    }

    //
    // members
    //
    private final PDDocument doc;
    private final PDJpeg logoImg;
    private final String[] header;

    private PDPageContentStream content = null;
    private float previousBandBase = 0;
}

PdfRenderingEndorsementAlternative.java

此類基於帶的概念,即內容的水平條紋,具有包含字段名稱和/或字段值的任意數量的列。

可以這樣使用:

PDDocument document = new PDDocument();
PdfRenderingEndorsementAlternative renderer = new PdfRenderingEndorsementAlternative(document, logoStream, header);

renderer.render(
        new BandColumn(leftHalfPageField, "Nombre del contrato/asegurado:", "Prueba Jesus Fac No Prop"),
        new BandColumn(rightHalfPageField, "Nombre del contrato/asegurado:", "Prueba Jesus Fac No Prop con Endoso")
        );

renderer.gap(20);

renderer.render(
        new BandColumn(leftHalfPageField, "País:", "México"),
        new BandColumn(rightHalfPageField, "País:", "México")
        );

renderer.close();
document.save(new File(RESULT_FOLDER, "Endorsement.pdf"));

RenderEndorsement.java

如您所見,調用者不必再關心y位置了,所有事情都在renderer類中完成。 結果:

結果

我將您的第一個樣本PDF中的數據用作輸入,結果如下:

樣本數據的結果

如您所見,也沒有頁面跳轉,也沒有重疊的文本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM