복붙노트

[SPRING] apache POI Excel 통합 문서에 워터 마크 추가

SPRING

apache POI Excel 통합 문서에 워터 마크 추가

저는 아파치 POI 자바 개발에 익숙합니다. 아래 코드를 사용하여 워터 마크를 추가하려고합니다. 그러나 워터 마크가 뒤에 숨겨진 내용을 무시합니다. 배경에 워터 마크를 추가하고 싶습니다.

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 통합 문서) 어떻게 Excel 헤더에 그림을 추가 할 수 있는지 알려주세요.

고마워. 무다 시르

해결법

  1. ==============================

    1.Microsoft Excel에는 기본 제공 워터 마크 기능이 없습니다. 그러나 워터 마크의 모양을 시뮬레이트 할 수있는 몇 가지 방법이 있습니다.하지만 불행히도 그 중 누구도 아파치 포이 (apache poi)가 직접 지원하지 않습니다.

    Microsoft Excel에는 기본 제공 워터 마크 기능이 없습니다. 그러나 워터 마크의 모양을 시뮬레이트 할 수있는 몇 가지 방법이 있습니다.하지만 불행히도 그 중 누구도 아파치 포이 (apache poi)가 직접 지원하지 않습니다.

    요구 사항이 XSSF 일 경우에만 XSSF의 하위 레벨 오브젝트를 사용하여 헤더의 그림을 프로그래밍 할 수 있습니다.

    A * .xlsx 파일은 단순히 ZIP 아카이브입니다. 그래서 우리는 압축을 풀고 내부를 살펴볼 수 있습니다. 헤더에 그림이있는 * .xlsx 파일을 만든 다음 * .xlsx ZIP 아카이브를 살펴보십시오.

    시트 XML 인 /xl/worksheets/sheet1.xml에는 다음과 같은 내용이 있습니다.

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

    그래서 우리는 그래픽 & 센터 헤더를 가리키는 & G를 가지고 있습니다. 그리고 우리는 레거시 드로잉을 가리키는 관계 Id를 가지고 있습니다.

    이 레거시 드로잉은 /xl/drawings/vmlDrawing1.vml에서 찾을 수 있습니다. 이 * .vml 파일에는 / xl / media /의 이미지와의 관계도 있습니다.

    그럼 우리가해야 할 일은

    다음의 코드는 원리를 보여주는 초안 작업입니다. 그림과 같이 링크 된 Microsoft 지원 페이지에서 AF101880439_en-us_draft.png를 다운로드했습니다.

    코드가 완성되어 작동하며 첫 번째 시트의 가운데 머리글에 DRAFT 그림이있는 결과 * .xlsx 파일을 만듭니다.

    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*/);
    
      workbook.write(new FileOutputStream("CreateExcelPictureInHeaderAKAWatermark.xlsx"));
      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();
       }
      }
    
     }
    
    }
    

    현재 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;
    ...
    
  2. from https://stackoverflow.com/questions/51077404/apache-poi-adding-watermark-in-excel-workbook by cc-by-sa and MIT license