PDFBOX 2.0:如何将大页面尺寸缩放为字母?

kaf*_*fhe 5 java printing scaling pdfbox

我正在使用 pdfbox 2.0.21(物理上)打印可能具有混合页面尺寸的 PDF 文件,包括非标准尺寸,例如 8.7"x11.3",它将打印在合法尺寸或更大的纸张上而无需缩放。这些 pdf 文件由许多不同的员工以不同的方式创建(Acrobat DC、从 Word 保存、打印到 pdf、由我们的文档系统生成...),然后发送给我的团队进行打印和邮寄。该卷不允许我们单独检查它们,最终我们将应用程序指向一个文件夹,它会打印那里的所有内容。我更愿意创建一个 PrinterJob 或 PDFPageable 来根据需要自动缩放所有页面,但无法让它工作。

public class PDPrn {
  public static void main(String[] args) {
    try (PDDocument pdf = PDDocument.load(new File("foo.pdf"))) {
      PrinterJob job = PrinterJob.getPrinterJob();
      Paper paper = new Paper();
      Paper.setSize(612, 792); // letter size
      paper.setImageableArea(36, 36, paper.getWidth() - 72, paper.getHeight() - 72); // 0.5in margins
      PageFormat format = new PageFormat();
      format.setPaper(paper);
      PDFPageable pageable = new PDFPageable(pdf);

      //doesn't scale down pages
      //printer will ask for legal and cutoff bottom when forced to use letter
      pageable.append(new PDFPrintable(pdf, Scaling.SCALE_TO_FIT), format);

      job.setPageable(pageable);
      try {
        job.print();
      } catch (PrinterException pe) {
      }
      pdf.close();
    } catch (IOException ioe) {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果失败,我尝试遍历每个页面并直接缩小大于字母的任何内容,但这以令人困惑的方式在页面上移动内容。

public class PDPrn {
  public static void main(String[] args) {
    try (PDDocument pdf = PDDocument.load(new File("foo.pdf"))) {
      PrinterJob job = PrinterJob.getPrinterJob();
      PDFPageable pageable = new PDFPageable(pdf);
      PDPageTree tree = pdf.getDocumentCatalog().getPages();
      Iterator<PDPage> iterator = tree.iterator();
      while (iterator.hasNext()) {
        PDPage page = iterator.next();
        if (page.getMediaBox().getWidth() !=612 || page.getMediaBox().getHeight() != 792) {
          PDPageContentStream contentStream = new PDPageContentStream(pdf, page,
            PDPageContentStream.AppendMode.PREPEND, false);

          //these are the wrong scaling factors but they do shrink oversized pages
          //however the shrunk content is moved far down the page and runs off the bottom
          //printer still asks for legal and cuts off bottom when forced to use letter
          //edit: these floats should probably be smaller
          //to account for margins, but the result is still
          //offset significantly below the upper left
          contentStream.transform(Matrix.getScaleInstance(612f / page.getMediaBox().getWidth(),
            792f / page.getMediaBox().getHeight()));

          //round figures, a large positive Y moves the content upward
          //but not cleanly to the upper left
          //whereas a large negative Y moves the content down and cuts off the bottom
          //but does print on letter without the printer complaining about size
          contentStream.transform(Matrix.getTransformInstance(0f, 250f);
          contentStream.close();
        }
      }
      job.setPageable(pageable);
      try {
        job.print();
      } catch (PrinterException pe) {
      }
      pdf.close();
    } catch (IOException ioe) {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用具有 MediaName、MediaSizeName 和 MediaTray 常量的各种组合的属性集也不会导致减少,打印机会停止并要求使用合法纸张,并在强制打印时切断底部。

如何使用 pdfbox 2.0 在打印时将单个超大页面正确缩小为字母大小?

编辑:通过将页面的 MediaBox 设置为 PDRectangle.LETTER,我能够确保打印机不会要求使用合法纸张,并且左下角内容流的来源可见。现在只需使用正确的数学方法来获取缩放因子,并可能影响边距,使用 ImageableArea 或 CropBox?

public class PDPrn {
  public static void main(String[] args) {
    try (PDDocument pdf = PDDocument.load(new File("foo.pdf"))) {
      PrinterJob job = PrinterJob.getPrinterJob();
      PDFPageable pageable = new PDFPageable(pdf);
      PDPageTree tree = pdf.getDocumentCatalog().getPages();
      Iterator<PDPage> iterator = tree.iterator();
      while (iterator.hasNext()) {
        PDPage page = iterator.next();
        if (page.getMediaBox().getWidth() !=612 || page.getMediaBox().getHeight() != 792) {
          PDPageContentStream contentStream = new PDPageContentStream(pdf, page,
            PDPageContentStream.AppendMode.PREPEND, false);

          //these are the wrong scaling factors but they do shrink oversized pages
          contentStream.transform(Matrix.getScaleInstance(0.5f,0.5f));
          page.setMediaBox(PDRectangle.LETTER); // make the page letter size with shrunk content origin in lower left
          contentStream.close();
        }
      }
      job.setPageable(pageable);
      try {
        job.print();
      } catch (PrinterException pe) {
      }
      pdf.close();
    } catch (IOException ioe) {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

kaf*_*fhe 6

设置新的 MediaBox 大小确实足以将缩放后的内容流推送到较小的页面内。比较源宽度/高度和目标宽度/高度的红利使我能够找到一个合适的缩放因子应用于两侧,保持纵横比。页面本身的边距看起来对于我们的使用来说是可以接受的,所以我现在不担心精细控制,只需将纸张设置为 0 页边距并放开即可。PDFPrintable 构造函数中的 SHRINK_TO_FIT 似乎没有执行任何操作,我不确定它在什么情况下起作用。

public class PDPrn {
  public static void main(String[] args) {
    try (PDDocument pdf = PDDocument.load(new File("foo.pdf"))) {
      PrinterJob job = PrinterJob.getPrinterJob();
      PDPageTree tree = pdf.getDocumentCatalog().getPages();
      Iterator<PDPage> iterator = tree.iterator();
      while (iterator.hasNext()) {
        PDPage page = iterator.next();
        if (page.getMediaBox().getWidth() > 612 || page.getMediaBox().getHeight() > 792) {
          float fWidth = 612f / page.getMediaBox().getWidth();
          float fHeight = 792f / page.getMediaBox().getHeight();
          float factor = 0f;
          if (fWidth > fHeight) {
            factor = fHeight;
          } else {
            factor = fWidth;
          }
          PDPageContentStream contentStream = new PDPageContentStream(pdf, page,
            PDPageContentStream.AppendMode.PREPEND, false);
          contentStream.transform(Matrix.getScaleInstance(factor, factor));
          contentStream.close();
          page.setMediaBox(PDRectangle.LETTER);
        }
      }
      Paper paper = new Paper();
      paper.setSize(612, 792);
      paper.setImageableArea(0, 0, 612, 792);
      PageFormat pageFormat = new PageFormat();
      pageFormat.setPaper(paper);
      Book book = new Book();
      book.append(new PDFPrintable(pdf, Scaling.SHRINK_TO_FIT), pageFormat, pdf.getNumberOfPages());
      job.setPageable(book);
      try {
        job.print();
      } catch (PrinterException pe) {
      }
      pdf.close();
    } catch (IOException ioe) {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)