Apache POI добавление водяного знака в книгу Excel

Я новичок в разработке java apache 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) или добавить изображение в заголовок exel

Спасибо Мудассир

Microsoft Excel не имеет встроенной функции водяных знаков. Однако есть несколько способов имитировать внешний вид водяного знака.. Но, к сожалению, ни один из них напрямую не поддерживается apache poi. Их можно было программировать, используя нижележащие низкоуровневые объекты XSSF. Но тогда вопрос будет либо "Как вставить картинку в шапку?" или "Как поставить фоновое изображение на лист?" Какие из этих вопросов у вас есть?

Axel Richter 28.06.2018 11:18

Да, Аксель, у меня вопрос, как вставить картинку в заголовок Excel. Я не нашел способа поместить изображение в заголовок, строка, которую я могу вставить в заголовок, но не изображение

Shaikh Mudassir 28.06.2018 11:25

Смотрите мой ответ. Это заняло некоторое время, потому что мне пришлось сократить свой продуктивный код, который, конечно, стал намного больше и более модульным, до минимального рабочего примера снова. Как-то мой рабочий черновик затерялся. К счастью - спасибо stackoverflow; -) - теперь он у меня вернулся.

Axel Richter 29.06.2018 16:24

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

meadlai 10.12.2019 04:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
3 164
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Microsoft Excel не имеет встроенной функции водяных знаков. Однако есть несколько способов имитировать внешний вид водяного знака. .. Но, к сожалению, ни один из них напрямую не поддерживается apache poi.

Если бы требовалось только XSSF, тогда можно было бы программировать изображение в заголовке, используя нижележащие низкоуровневые объекты XSSF.

Файл *.xlsx - это просто архив ZIP. Так что мы можем разархивировать его и взглянуть на внутреннее устройство. Так что создайте файл *.xlsx с изображением в заголовке, а затем посмотрите архив *.xlsxZIP.

Там, в /xl/worksheets/sheet1.xml, то есть в листах XML, мы находим что-то вроде:

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

Итак, у нас есть &G, который указывает на графику в заголовке &Center. И у нас есть идентификатор отношения, который указывает на устаревший рисунок.

Этот устаревший рисунок мы находим в /xl/drawings/vmlDrawing1.vml. В этом файле *.vml также есть отношение к образу в /xl/media/.

Итак, что мы должны сделать, это

  1. Добавление изображения в рабочую книгу. Фактически это уже предусмотрено apache poi.
  2. Помещение "& G" в центральный заголовок. Это также фактически уже обеспечивается apache poi.

  3. Создание /xl/drawings/vmlDrawing1.vml как PackagePart и создание POIXMLDocumentPart, который предоставляет метод commit() для сохранения его XML в пакет при записи файла.

  4. Создание всех необходимых отношений.

Следующий код - это рабочий проект, который показывает принцип. Как изображение, я загрузил AF101880439_en-us_draft.png со связанной страницы поддержки Microsoft.

Код завершен, работает и создает файл результата *.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();
   }
  }

 }

}

Требуются изменения в импорте, чтобы заставить эту работу работать с текущим 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;
...

Большое спасибо, Аксель, за то, что поделился этими ценными знаниями. Попробую реализовать то же самое. Спасибо

Shaikh Mudassir 01.07.2018 09:17

Спасибо, ваше решение работает для меня, но мне нужно было всегда просматривать это изображение прямо сейчас, его можно просматривать только тогда, когда я выбираю опцию view-> paglayout. Подскажите, как я могу всегда видеть изображение как водяной знак. @ Аксель Рихтер

Priyanka Mehta 08.06.2020 13:07

Другие вопросы по теме