2015-06-10 3 views
1

Я не большой поклонник задавать такие вопросы, но хорошо, это было целых три дня, пытаясь решить эту ошибку в моем коде.Проблема PdfBox при смене страницы

Я знаю, что это логическая проблема, и я знаю, как ее решить в моем сознании, но когда дело доходит до перевода моих идей в код, я просто не могу заставить его работать, как я хочу.

Я работаю над соглашением о контракте (модификация контракта), который сравнивает данные из 2 таблиц и, если какой-либо из них изменился, тогда он отображает только эту информацию.

Иногда информация, которая изменяется, например, условия, вырастает или опускается по длине, вот где проблема.

Я разработал алгоритм, который получает минимальную координату Y после того, как закончил рисовать информацию, но когда я меняю страницу, координата Y должна быть сброшена на 700f и начать рисовать снова оттуда.

Код, который я использую, был сначала сделан другим программистом, которого больше нет здесь, я не знаю, как сделать MCVE с PDF-файлами.

Но вот методы, которые, я думаю, помогут вам помочь.

Пример того, как я сравниваю и окрашивать информацию о PDF:

sOffA и sOffE являются объектами класса называемых SubscriptionOffer и A обозначает Agreement пока E для Endorsement. Подтверждение - это копия таблицы Agreement на MySQL, но с измененной информацией. Вероятно, это нерелевантная информация, возможно, нет.

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 на массив (как показано выше) является наименьшим один, то он перезапускает весь массив возвращается к 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;  
} 

Этот метод, где я думаю, что моя логика проблема, и как вы можете видеть, что я пробовал Diferent вещи, оригинальный алгоритм был только 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 объектов и проверить, если они нулевые или пустыми:

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; 
    } 
} 

Это PDF Example выхода с оригиналом (for-each) способ.

Если вы не можете увидеть PDF, дайте мне знать, но здесь также некоторые скриншоты из него:

enter image description here

Это PDF Example на выходе с не комментировал код на getMinY метода.

И от этой модификации вот выход:

enter image description here

Как вы можете видеть, 1-ый выход «перескакивает» в следующую страницу, так как, скажем, текст справа, на «Texto де Poliza» на Y координаты 680, 670 или что-то в этом роде, но слева я написал пустое поле (""), которое закончилось в 90 или 100 кое-что рядом с этими числами.

Тогда это сравнивает 100 < 670? Да, тогда я беру от 50 до 100, и он ниже моего BOTTOM_MARGIN (это 60), поэтому он закрывает фактическую страницу (которая теперь находится там, где текст закончился, но думает, что она находится на странице перед ней) и создает новую.

Я задал аналогичный вопрос почти за год до here, эти классы почти копируются из этих файлов, но эта ошибка в моей логике поступает только с этими файлами, потому что данные обрабатываются немного иначе.

Ну, после этой стены текста я надеюсь, что кто-то сможет ее прочитать и на самом деле дать мне руку, может быть, я пропустил важную роль, но не могу ее найти.

Заранее спасибо.

EDIT

После добавления ответ @ MKL на мои методы я считаю, что, когда никакая информация изменяется в обе стороны, это создает разрыв, и это не выглядит хорошо.

enter image description here

Это, как я отправляю данные в 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); 
    } 

ли вышеуказанная комментируемая валидация правильно или я бы вернуться к прошлым методам, которые возникли ошибки? Должен ли я добавить метод getPreviousBandBase() на PdfRenderingEndorsementAlternative или подумать иначе, чтобы сделать это прямо на методе 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; 
} 
+0

Как я уже прокомментировал ваш прежний вопрос, я сомневаюсь, что это хорошая идея, чтобы проверить * на переключатели страниц * изнутри rtext вообще, * его следует контролировать каким-то способом с глазу на контент, который нужно добавить для текущая запись в ** всех ** столбцах. – mkl

+0

@mkl у вас есть пример, возможно, ссылка на другой вопрос этого метода? Или что-то подобное, что я мог бы проанализировать? И извините за поздний ответ. Благодарю. Я буду читать некоторые документы и попробовать некоторые методы. Я не так разбираюсь в программировании pdf, поэтому я делаю много ошибок (я не знаю, как сделать простой «Hello World» с pdf, я имею в виду не от 0) – Frakcool

+0

Я начал читать, как начать PDF от 0 с помощью PDFBox и Maven, я все еще придерживаюсь Maven Config, но как только у меня будет MCVE, я опубликую его. – Frakcool

ответ

1

Как уже намекают в комментарии (на самом деле уже в комментарии к вашим former question) Я думаю, что вся архитектура вашего класса рендеринга необходим капитальный ремонт.Основываясь на вашем 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)

Как вы видите, абонент не должен заботиться больше о у позиции, все сделано в классе рендеринга. И результат:

the result

Я использовал данные из первого образца PDF в качестве входных данных, и это результат:

result for sample data

Как вы видите, страница не прыгает и не перекрываются тексты.

+0

Я тестирую решение, я взял время на то, чтобы адаптировать его к проекту, не против, если я начну щедрость за 4 часа (не хватает времени, пока я не смогу добавить его), а на выходных примите свой ответ, чтобы получить Баунти? Кстати, большое спасибо, видя метод, я предполагаю, что пытался изобрести колесо (и неправильно). Я буду продолжать настраивать Maven в любом случае, чтобы сделать проект с 0 и узнать, как сделать MCVE для PDF в будущем. – Frakcool

+0

* Не возражаете, если ... * - Я бы не прочь, но, пожалуйста, не чувствуйте себя обязанным. Надеюсь, этот пример кода поможет вам. – mkl

+0

Конечно, это помогает мне. Я не чувствую себя обязанным, но благодарен. Большое спасибо :) – Frakcool

Смежные вопросы