当前位置: 首页 > 面试题库 >

apache POI在Excel工作簿中添加水印

谷博艺
2023-03-14
问题内容

我是Apache POI Java开发的新手,我正在尝试使用以下代码在Excel中添加水印。但是水印标识会覆盖其后面的内容。我想在背景中添加水印。

public class xlWatermark {
    public static void main(String[] args) {
        HSSFWorkbook wb = new HSSFWorkbook();
        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream("Test.xls");
            HSSFSheet ws = wb.createSheet("testSheet");
            HSSFPatriarch dp = ws.createDrawingPatriarch();
            HSSFClientAnchor anchor = new HSSFClientAnchor
                (0, 0, 1023, 255, (short) 2, 4, (short) 13, 26);
            HSSFTextbox txtbox = dp.createTextbox(anchor);
            HSSFRichTextString rtxt = new HSSFRichTextString("test");
            HSSFFont font = wb.createFont();
            font.setColor((short) 27);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
            font.setFontHeightInPoints((short) 192);
            font.setFontName("Verdana");
            rtxt.applyFont(font);
            txtbox.setString(rtxt);
            txtbox.setLineStyle(HSSFShape.LINESTYLE_NONE);
            txtbox.setNoFill(true);
            wb.write(fileOut);
            fileOut.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

您能帮我告诉我如何在excel中添加水印(在XSSF或HSSF工作簿中)或在exel标头中添加图片吗?

感谢Mudassir


问题答案:

Microsoft Excel没有内置的水印功能。但是,有两种方法可以模拟水印的外观
..不幸的是,apache poi没有直接支持这些方法

如果XSSF仅是要求,则可以使用底层底层对象来在标题中编程图片XSSF

一个*.xlsx文件只是一个ZIP存档。因此,我们可以将其解压缩并查看内部结构。因此,创建一个*.xlsx在标题中具有图片的文件,然后查看*.xlsx
ZIP存档。

/xl/worksheets/sheet1.xml其中XML找到工作表,我们发现类似:

...
<headerFooter>
 <oddHeader>&C&G</oddHeader>
</headerFooter>
<legacyDrawingHF r:id="rId1"/>
...

因此,我们&G&Center标头中具有指向Graphic的点。并且我们有一个关系ID指向一个旧图纸。

我们在中找到的这张旧图/xl/drawings/vmlDrawing1.vml。在此*.vml文件中,还与中的图像有关/xl/media/

所以我们要做的是

  1. 将图像添加到工作簿。这实际上apache poi已经由提供。
  2. 将“&G”放入中心标题。这实际上也是已经提供的apache poi

  3. 创建/xl/drawings/vmlDrawing1.vmlPackagePart和创建POIXMLDocumentPart提供了commit()一种XML在写出文件时将其保存到包中的方法。

  4. 创建所有需要的关系。

以下代码是显示原理的工作草案。如图所示,我从链接的Microsoft支持页面下载了AF101880439_zh-
cn_draft.png

该代码已完成并且可以正常工作,并创建一个*.xlsx在第一张纸的中心标题中具有DRAFT图片的结果文件

import java.io.*;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

import org.apache.poi.util.IOUtils;
import org.apache.poi.ss.util.ImageUtils;

import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.POIXMLDocumentPart;

import org.apache.xmlbeans.XmlObject;

import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;

public class CreateExcelPictureInHeaderAKAWatermark {

 static void createPictureForHeader(XSSFSheet sheet, int pictureIdx, String pictureTitle, int vmlIdx, String headerPos) throws Exception {
  OPCPackage opcpackage = sheet.getWorkbook().getPackage();

  //creating /xl/drawings/vmlDrawing1.vml
  PackagePartName partname = PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing" + vmlIdx+ ".vml");
  PackagePart part = opcpackage.createPart(partname, "application/vnd.openxmlformats-officedocument.vmlDrawing");
  //creating new VmlDrawing
  VmlDrawing vmldrawing = new VmlDrawing(part);

  //creating the relation to the picture in /xl/drawings/_rels/vmlDrawing1.vml.rels
  XSSFPictureData picData = sheet.getWorkbook().getAllPictures().get(pictureIdx);
  String rIdPic = vmldrawing.addRelation(null, XSSFRelation.IMAGES, picData).getRelationship().getId();

  //get image dimension
  ByteArrayInputStream is = new ByteArrayInputStream(picData.getData());
  java.awt.Dimension imageDimension = ImageUtils.getImageDimension(is, picData.getPictureType());
  is.close();

  //updating the VmlDrawing
  vmldrawing.setRIdPic(rIdPic);
  vmldrawing.setPictureTitle(pictureTitle);
  vmldrawing.setImageDimension(imageDimension);
  vmldrawing.setHeaderPos(headerPos);

  //creating the relation to /xl/drawings/vmlDrawing1.xml in /xl/worksheets/_rels/sheet1.xml.rels
  String rIdExtLink = sheet.addRelation(null, XSSFRelation.VML_DRAWINGS, vmldrawing).getRelationship().getId();

  //creating the <legacyDrawingHF r:id="..."/> in /xl/worksheets/sheetN.xml
  sheet.getCTWorksheet().addNewLegacyDrawingHF().setId(rIdExtLink);

 }

 public static void main(String[] args) throws Exception {

  Workbook workbook = new XSSFWorkbook();

  Sheet sheet;
  Header header;
  InputStream is;
  byte[] bytes;

  int pictureIdx; //we need it later

  sheet = workbook.createSheet();

  header = sheet.getHeader();
  header.setCenter("&G"); // &G means Graphic

  //add picture data to this workbook
  is = new FileInputStream("AF101880439_en-us_draft.png");
  bytes = IOUtils.toByteArray(is);
  pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
  is.close();

  //create header picture from picture data of this workbook
  createPictureForHeader((XSSFSheet)sheet, pictureIdx, "AF101880439_en-us_draft", 1, "CH"/*CenterHeader*/);

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

 //class for VmlDrawing
 static class VmlDrawing extends POIXMLDocumentPart {

  String rIdPic = "";
  String pictureTitle = "";
  java.awt.Dimension imageDimension = null;
  String headerPos = "";

  VmlDrawing(PackagePart part) {
   super(part);
  }

  void setRIdPic(String rIdPic) {
   this.rIdPic = rIdPic;
  }

  void setPictureTitle(String pictureTitle) {
   this.pictureTitle = pictureTitle;
  }

  void setHeaderPos(String headerPos) {
   this.headerPos = headerPos;
  }

  void setImageDimension(java.awt.Dimension imageDimension) {
   this.imageDimension = imageDimension;
  }

  @Override
  protected void commit() throws IOException {
   PackagePart part = getPackagePart();
   OutputStream out = part.getOutputStream();
   try {
    XmlObject doc = XmlObject.Factory.parse(

      "<xml xmlns:v=\"urn:schemas-microsoft-com:vml\""
     +" xmlns:o=\"urn:schemas-microsoft-com:office:office\""
     +" xmlns:x=\"urn:schemas-microsoft-com:office:excel\">"
     +" <o:shapelayout v:ext=\"edit\">"
     +"  <o:idmap v:ext=\"edit\" data=\"1\"/>"
     +" </o:shapelayout><v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\""
     +"  o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">"
     +"  <v:stroke joinstyle=\"miter\"/>"
     +"  <v:formulas>"
     +"   <v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>"
     +"   <v:f eqn=\"sum @0 1 0\"/>"
     +"   <v:f eqn=\"sum 0 0 @1\"/>"
     +"   <v:f eqn=\"prod @2 1 2\"/>"
     +"   <v:f eqn=\"prod @3 21600 pixelWidth\"/>"
     +"   <v:f eqn=\"prod @3 21600 pixelHeight\"/>"
     +"   <v:f eqn=\"sum @0 0 1\"/>"
     +"   <v:f eqn=\"prod @6 1 2\"/>"
     +"   <v:f eqn=\"prod @7 21600 pixelWidth\"/>"
     +"   <v:f eqn=\"sum @8 21600 0\"/>"
     +"   <v:f eqn=\"prod @7 21600 pixelHeight\"/>"
     +"   <v:f eqn=\"sum @10 21600 0\"/>"
     +"  </v:formulas>"
     +"  <v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>"
     +"  <o:lock v:ext=\"edit\" aspectratio=\"t\"/>"
     +" </v:shapetype><v:shape id=\"" + headerPos + "\" o:spid=\"_x0000_s1025\" type=\"#_x0000_t75\""
     +"  style='position:absolute;margin-left:0;margin-top:0;"
     +"width:" + (int)imageDimension.getWidth() + "px;height:" + (int)imageDimension.getHeight() + "px;"
     +"z-index:1'>"
     +"  <v:imagedata o:relid=\""+ rIdPic + "\" o:title=\"" + pictureTitle + "\"/>"
     +"  <o:lock v:ext=\"edit\" rotation=\"t\"/>"
     +" </v:shape></xml>"

    );
    doc.save(out, DEFAULT_XML_OPTIONS);
    out.close();
   } catch (Exception ex) {
    ex.printStackTrace();
   }
  }

 }

}

需要更改进口商品才能使用current进行工作apache poi 4.0.1

...
//import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.ooxml.POIXMLDocumentPart;

import org.apache.xmlbeans.XmlObject;

//import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
...


 类似资料:
  • 所以在问这个之前,我搜索并发现了一些与我在这里想要做的相似的事情。 基本上我有工作簿AlphaMaster。这个工作簿是一个模板,我想用它来创建每周的新工作簿。 在本工作簿中,有名为“周一至周六”的工作表,以及带有相应日期的周一、周二等其他工作表。 我创建了一个在打开工作簿时加载的表单。我想要的是当我单击表单运行时,它将: > 将代码保存模板作为新工作簿运行 根据userform1的输入重命名工作

  • 问题内容: 我已经浏览了几乎所有以前的线程,但是仍然无法正常工作。我正在尝试向现有工作簿中添加新工作表。我的代码有效,但是它继续添加更多(实际上很多)工作表。我不知道解决方案。下面是我的代码 问题答案: 如果要向现有电子表格中添加工作表,只需继续并将新工作表添加到文件中,而不是复制对象并尝试向其中添加新工作表。

  • 然后另一个问题是工作簿的名称都不同,所有300个。是否有一个宏可以复制我打开的工作簿,而不是每次都输入实际的名称?

  • 我试图将列表数据写入一个工作簿中的多个excel表格。与第一个列表一样,代码将创建新工作簿并为列表[1]创建新工作表,对于第二个列表,它将在现有工作簿中创建新工作表,依此类推。所以我写了下面的代码。但是它不起作用,我只能看到列表[1]的第一页。有人能帮我提供任何替代解决方案吗? 下面我写的代码 谢谢,Priyank Shah

  • 我试图使用apache POI、使用primefaces和java在现有的excel工作簿中创建一个新的工作表,但是到目前为止还没有成功。谁能告诉我这是怎么做的吗?我可以做单张 下面的代码是我为在一个xls文件中创建多个工作表而编写的,我给出的条件是它没有大于65535的of行创建新工作表并迭代它,但它显示错误 警告:允许范围(0..65535)之外的无效行号(65536)java.lang.Il

  • 我尝试了各种方式添加Excel电子表格。但问题总是相同的。 我尝试了这里提出的代码, 将工作表添加到现有excel文件 使用Apache POI for Java在现有Excel工作簿中创建新工作表 问题是: