Apache poi:如何设置“双面打印”和“双面打印”?

时间:2020-05-22 05:20:49

标签: java excel apache-poi

克隆新纸时出现问题。

第1张设置“双面打印” ,但是在workbook.cloneSheet(0)之后,新页丢失了“双面打印” 并属于 “单面打印” 。我无法为新工作表设置“两种尺寸都打印” ,因为找不到设置此方法的方法。

poi-apache printSetup()是否支持设置“双面打印” “双面打印”

如果没有该设置的话?

1 个答案:

答案 0 :(得分:1)

打印机是否能够进行双面打印取决于打印机硬件。因此,这不是PrintSetup之类的打印设置,而是打印机设置。 Excel能够在其文件中存储打印机设置。这是通过二进制DEVMODEA结构(Where is the definition of the XLSX printerSettings.bin file format?)完成的。在Office Open XML中,它存储在/xl/printerSettings/printerSettings[N].bin中。

Apache POI到目前为止无法正确克隆该结构。而且我怀疑应该完全克隆它,因为当用户打开的Excel文件与创建者所使用的打印机不完全相同时,它经常会导致出现问题。但是,当然,这只是我的观点,至少对于Office Open XML是可以做到的。

Workbook.cloneSheet直到现在都没有克隆PrintSetup(当前版本apache poi 4.1.2)。因此,我们首先需要克隆PrintSetup。以下代码提供了将PrintSetupSheet source克隆到Sheet clone的方法。它使用java.beans.*java.lang.reflect.Method使用sourcePrintSetup中的getter获取所有值,并使用适当的setter将这些值设置为clonePrintSetup。它仅适用于不带参数的吸气剂和具有精确一个参数的设置器。但这对于PrintSetup就足够了。

克隆了PrintSetup后,我们可以将克隆的引用从XSSFSheet纠正为/xl/printerSettings/printerSettings[N].binWorkbook.cloneSheet只需将关系复制到旧的/xl/printerSettings/printerSettings[N].bin包部分。错了/xl/printerSettings/printerSettings[N].bin软件包的一部分也需要被克隆,并且克隆的表单需要引用该新的/xl/printerSettings/printerSettings[N].bin软件包的一部分。这是通过以下代码中的方法repairCloningPrinterSettings完成的。使用当前的apache poi 4.1.2可以使用。当Workbook.cloneSheet在更高版本中更改时,必须对其进行更改。

以下代码还提供了一种二进制克隆PackagePart的方法。它仅适用于以Idx结尾,后跟点号和扩展名的零件名,例如name1.xmlname1.pngprinterSettings1.bin。克隆时它会计算Idx的数量。

完整示例:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;

import java.io.*;

import java.beans.*;
import java.lang.reflect.Method;

class ExcelCloneSheet {

 //method to transfer InputStream to OutputStream
 //to work using Java 8 since InputStream.transferTo needs at least Java 9
 static void transferInputStreamToOutputStream(InputStream in, OutputStream out) throws Exception {
  byte[] buffer = new byte[1024];
  int bytesRead;
  while ((bytesRead = in.read(buffer)) != -1) {
   out.write(buffer, 0, bytesRead);
  }
 }

 //method for binary cloning a PackagePart
 //works only for part names which ends with Idx followed by dot followed by extension
 //throws Exception when not successful
 static PackagePart clonePackagePart(PackagePart sourcePart, String contentType) throws Exception {
  OPCPackage oPCPackage = sourcePart.getPackage();
  String sourcePartName = sourcePart.getPartName().getName();
  String destinationPartName = sourcePartName;
  String[] sourcePartNameSplitExtension = sourcePartName.split("\\.");
  if (sourcePartNameSplitExtension.length == 2) {
   sourcePartName = sourcePartNameSplitExtension[0];
   String sourcePartNameExtension = sourcePartNameSplitExtension[1];
   int i = sourcePartName.length();
   while (i > 0 && Character.isDigit(sourcePartName.charAt(i - 1))) {
    i--;
   }
   int idx = Integer.valueOf(sourcePartName.substring(i));
   idx++;
   destinationPartName = sourcePartName.substring(0, i) + idx + "." + sourcePartNameExtension;
  }
  PackagePartName partName = PackagingURIHelper.createPartName(destinationPartName);
  PackagePart destinationPart = oPCPackage.createPart(partName, contentType);
  InputStream in = sourcePart.getInputStream();
  OutputStream out = destinationPart.getOutputStream();
  //in.transferTo(out); // at least Java 9 needed
  transferInputStreamToOutputStream(in, out);
  out.close();
  return destinationPart;
 }

 //method for repairing the relation from sheet to "/xl/printerSettings/printerSettings[N].bin" package part
 //clones "/xl/printerSettings/printerSettings[N].bin" package part
 //repairs the wrong cloned relation to the old "/xl/printerSettings/printerSettings[N].bin" package part
 //works using apache poi 4.1.2
 //must be changed when Workbook.cloneSheet changes in later versions
 static void repairCloningPrinterSettings(XSSFSheet sheet) throws Exception {
  for (POIXMLDocumentPart.RelationPart relationPart : sheet.getRelationParts()) {
   String contentType = relationPart.getDocumentPart().getPackagePart().getContentType();
   if ("application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings".equals(contentType)) {
System.out.println(relationPart.getRelationship());
    //clone the "/xl/printerSettings/printerSettings[N].bin" package part
    PackagePart sourcePart = relationPart.getDocumentPart().getPackagePart(); 
    PackagePart destinationPart = clonePackagePart(sourcePart, contentType);
    //remove the wrong cloned relation to the old "/xl/printerSettings/printerSettings[N].bin" package part
    relationPart.getRelationship().getSource().removeRelationship(relationPart.getRelationship().getId());
    //add the relation to the new "/xl/printerSettings/printerSettings[N].bin" package part
    PackageRelationship relationship = sheet.getPackagePart().addRelationship(
     destinationPart.getPartName(), 
     TargetMode.INTERNAL, 
     XSSFRelation.PRINTER_SETTINGS.getRelation());
    //set Id of relation to the new "/xl/printerSettings/printerSettings[N].bin" package part 
    //in sheet's page setup
    if (sheet.getCTWorksheet().getPageSetup() == null) sheet.getCTWorksheet().addNewPageSetup();
    sheet.getCTWorksheet().getPageSetup().setId(relationship.getId());
   }
  }
 }

 //method for cloning the PrintSetup from Sheet source to Sheet clone
 //uses java.beans.* and java.lang.reflect.Method to get all values using getters from sourcePrintSetup
 //and set those values to clonePrintSetup using the appropriate setters
 //works only for getters without parameters and setters having exact one parameter
 //throws Exception when not successful
 static void clonePrintSetup(Sheet source, Sheet clone) throws Exception {
  PrintSetup sourcePrintSetup = source.getPrintSetup();
  PrintSetup clonePrintSetup = clone.getPrintSetup();
  for(PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(PrintSetup.class).getPropertyDescriptors()) {
   Method getMethod = propertyDescriptor.getReadMethod();
   Object value = null;
   if (getMethod != null && getMethod.getParameterTypes().length == 0) {
    value = getMethod.invoke(sourcePrintSetup);
    Method setMethod = propertyDescriptor.getWriteMethod();
    if (setMethod != null && setMethod.getParameterTypes().length == 1) {
     setMethod.invoke(clonePrintSetup, value);
System.out.println(setMethod + ": " + value);
    }
   }
  }
 }

 public static void main(String[] args) throws Exception {
  Workbook workbook  = WorkbookFactory.create(new FileInputStream("Excel.xlsx"));

  Sheet sheet = workbook.getSheetAt(0);
  Sheet clone = workbook.cloneSheet(0);

  //Workbook.cloneSheet does not clone the PrintSetup. So we do it now.
  clonePrintSetup(sheet, clone);

  if (clone instanceof XSSFSheet) {
   XSSFSheet xssfSheet = (XSSFSheet)clone;
   //After cloning the cloned sheet has relation to the same 
   //"/xl/printerSettings/printerSettings[N].bin" package part as the source sheet had.
   //This is wrong. So we need to repair.
   repairCloningPrinterSettings(xssfSheet);
  }  

  FileOutputStream out = new FileOutputStream("ExcelNew.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();
 }
}

在此代码之后,ExcelNew.xlsx中的克隆工作表应与源工作表具有相同的PrintSetup以及printerSettings

相关问题