UReport导出PDF添加文字水印和图片水印

一. 概述

在后台管理系统中, 经常会遇到各种报表开发, 其中比较有名开源的报表框架UReport2, 了解UReport2可以访问官网URport2教程, 本文主要介绍拓展ureport2输出pdf添加水印

二. 说明

通过查看官网介绍, 可得知ExportManager.exportPdf() 是输出pdf的接口方法, 那么就进一步看看这个方法的实现, 然后改造


重写源码结构

2.1 覆盖源码实现类PdfProducer

/*******************************************************************************
 * Copyright 2017 Bstek
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/
package com.bstek.ureport.export.pdf;

import com.bstek.ureport.build.paging.Page;
import com.bstek.ureport.chart.ChartData;
import com.bstek.ureport.definition.Alignment;
import com.bstek.ureport.definition.CellStyle;
import com.bstek.ureport.definition.Orientation;
import com.bstek.ureport.definition.Paper;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.export.FullPageData;
import com.bstek.ureport.export.PageBuilder;
import com.bstek.ureport.export.Producer;
import com.bstek.ureport.model.Image;
import com.bstek.ureport.model.*;
import com.bstek.ureport.utils.ImageUtils;
import com.bstek.ureport.utils.UnitUtils;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Jacky.gao
 * @since 2017年3月10日
 */
public class PdfProducer implements Producer {
    @Override
    public void produce(Report report,OutputStream outputStream) {
        Paper paper=report.getPaper();
        int width=paper.getWidth();
        int height=paper.getHeight();
        Rectangle pageSize=new RectangleReadOnly(width,height);
        if(paper.getOrientation().equals(Orientation.landscape)){
            pageSize=pageSize.rotate();         
        }
        int leftMargin=paper.getLeftMargin();
        int rightMargin=paper.getRightMargin();
        int topMargin=paper.getTopMargin();
        int bottomMargin=paper.getBottomMargin();
        Document document=new Document(pageSize,leftMargin,rightMargin,topMargin,bottomMargin);
        try{
            PdfWriter writer=PdfWriter.getInstance(document,outputStream);
            PageHeaderFooterEvent headerFooterEvent=new PageHeaderFooterEvent(report);
            writer.setPageEvent(headerFooterEvent);
            document.open();
            List<Column> columns=report.getColumns();
            List<Integer> columnsWidthList=new ArrayList<Integer>();
            int[] intArr=buildColumnSizeAndTotalWidth(columns,columnsWidthList);
            int colSize=intArr[0],totalWidth=intArr[1];
            int[] columnsWidth=new int[columnsWidthList.size()];
            for(int i=0;i<columnsWidthList.size();i++){
                columnsWidth[i]=columnsWidthList.get(i);
            }
            FullPageData pageData=PageBuilder.buildFullPageData(report);
            List<List<Page>> list=pageData.getPageList();
            if(list.size()>0){
                int columnCount=paper.getColumnCount();
                int w=columnCount*totalWidth+(columnCount-1)*paper.getColumnMargin();
                int size=columnCount+(columnCount-1);
                int[] widths=new int[size];
                for(int i=0;i<size;i++){
                    int mode=(i+1)%2;
                    if(mode==0){
                        widths[i]=paper.getColumnMargin();                      
                    }else{
                        widths[i]=totalWidth;                   
                    }
                }
                float tableHeight=pageSize.getHeight()-paper.getTopMargin()-paper.getBottomMargin();
                Map<Row, Map<Column, Cell>> cellMap=report.getRowColCellMap();
                for(List<Page> pages:list){
                    PdfPTable table=new PdfPTable(size);
                    table.setLockedWidth(true);
                    table.setTotalWidth(w);
                    table.setWidths(widths);
                    table.setHorizontalAlignment(Element.ALIGN_LEFT);
                    int ps=pages.size();
                    for(int i=0;i<ps;i++){
                        if(i>0){
                            PdfPCell pdfMarginCell=new PdfPCell();
                            pdfMarginCell.setBorder(Rectangle.NO_BORDER);
                            table.addCell(pdfMarginCell);
                        }
                        Page page=pages.get(i);
                        
                        PdfPTable childTable=new PdfPTable(colSize);
                        childTable.setLockedWidth(true);
                        childTable.setTotalWidth(totalWidth);
                        childTable.setWidths(columnsWidth);
                        childTable.setHorizontalAlignment(Element.ALIGN_LEFT);
                        List<Row> rows=page.getRows();
                        for(Row row:rows){
                            Map<Column,Cell> colMap=cellMap.get(row);
                            if(colMap==null){
                                continue;
                            }
                            for(Column col:columns){
                                if(col.getWidth()<1){
                                    continue;
                                }
                                Cell cell=colMap.get(col);
                                if(cell==null){
                                    continue;
                                }
                                int cellHeight=buildCellHeight(cell,rows);
                                PdfPCell pdfcell=buildPdfPCell(cell,cellHeight);
                                childTable.addCell(pdfcell);
                            }
                        }
                        float childTableHeight=childTable.calculateHeights();
                        if(tableHeight>childTableHeight){
                            for(int j=0;j<columns.size();j++){
                                PdfPCell lastCell=new PdfPCell();
                                lastCell.setBorder(Rectangle.NO_BORDER);
                                childTable.addCell(lastCell);
                            }
                        }
                        PdfPCell pdfContainerCell=new PdfPCell(childTable);
                        pdfContainerCell.setBorder(Rectangle.NO_BORDER);
                        table.addCell(pdfContainerCell);
                    }
                    if(ps<columnCount){
                        int left=columnCount-ps;
                        for(int i=0;i<left;i++){
                            PdfPCell pdfMarginCell=new PdfPCell();
                            pdfMarginCell.setBorder(Rectangle.NO_BORDER);
                            table.addCell(pdfMarginCell);
                            pdfMarginCell=new PdfPCell();
                            pdfMarginCell.setBorder(Rectangle.NO_BORDER);
                            table.addCell(pdfMarginCell);
                        }
                    }
                    // 加入文字水印
                    Object watermark = report.getContext().getParameters().get("watermark");
                    writer.setPageEvent(new Watermark(watermark));
                    // 加入图片水印
                    writer.setPageEvent(new ImageWatermark());
                    document.add(table);
                    document.newPage();
                }
                
            }else{
                List<Page> pages=report.getPages();
                Map<Row, Map<Column, Cell>> cellMap=report.getRowColCellMap();
                for(Page page:pages){
                    PdfPTable table=new PdfPTable(colSize);
                    table.setLockedWidth(true);
                    table.setTotalWidth(totalWidth);
                    table.setWidths(columnsWidth);
                    table.setHorizontalAlignment(Element.ALIGN_LEFT);
                    List<Row> rows=page.getRows();
                    for(Row row:rows){
                        Map<Column,Cell> colMap=cellMap.get(row);
                        if(colMap==null){
                            continue;
                        }
                        for(Column col:columns){
                            if(col.getWidth()<1){
                                continue;
                            }
                            Cell cell=colMap.get(col);
                            if(cell==null){
                                continue;
                            }
                            int cellHeight=buildCellHeight(cell,rows);
                            PdfPCell pdfcell=buildPdfPCell(cell,cellHeight);
                            table.addCell(pdfcell);
                        }
                    }
                    // 加入文字水印
                    Object watermark = report.getContext().getParameters().get("watermark");
                    writer.setPageEvent(new Watermark(watermark));
                    // 加入图片水印
                    writer.setPageEvent(new ImageWatermark());
                    document.add(table);
                    document.newPage();
                }
            }
            document.close();
        }catch(Exception ex){
            throw new ReportComputeException(ex);
        }
    }

    
    private int buildCellHeight(Cell cell,List<Row> rows){
        int height=cell.getRow().getRealHeight();
        int rowSpan=cell.getPageRowSpan();
        if(rowSpan>0){
            int pos=rows.indexOf(cell.getRow());
            int start=pos+1,end=start+rowSpan-1;
            for(int i=start;i<end;i++){
                height+=rows.get(i).getRealHeight();
            }
        }
        return height;
    }
    
    private PdfPCell buildPdfPCell(Cell cellInfo,int cellHeight) throws Exception{
        CellStyle style=cellInfo.getCellStyle(); 
        CellStyle customStyle=cellInfo.getCustomCellStyle();
        CellStyle rowStyle=cellInfo.getRow().getCustomCellStyle();
        CellStyle colStyle=cellInfo.getColumn().getCustomCellStyle();
        PdfPCell cell=newPdfCell(cellInfo,cellHeight);
        cell.setPadding(0);
        cell.setBorder(PdfPCell.NO_BORDER);
        cell.setCellEvent(new CellBorderEvent(style,customStyle));
        int rowSpan=cellInfo.getPageRowSpan();
        if(rowSpan>0){
            cell.setRowspan(rowSpan);
        }
        int colSpan=cellInfo.getColSpan();
        if(colSpan>0){
            cell.setColspan(colSpan);
        }
        Alignment align=style.getAlign();
        if(customStyle!=null && customStyle.getAlign()!=null){
            align=customStyle.getAlign();
        }
        if(rowStyle!=null && rowStyle.getAlign()!=null){
            align=rowStyle.getAlign();
        }
        if(colStyle!=null && colStyle.getAlign()!=null){
            align=colStyle.getAlign();
        }
        if(align!=null){
            if(align.equals(Alignment.left)){
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
            }else if(align.equals(Alignment.center)){
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            }else if(align.equals(Alignment.right)){
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            }
        }
        Alignment valign=style.getValign();
        if(customStyle!=null && customStyle.getValign()!=null){
            valign=customStyle.getValign();
        }
        if(rowStyle!=null && rowStyle.getValign()!=null){
            valign=rowStyle.getValign();
        }
        if(colStyle!=null && colStyle.getValign()!=null){
            valign=colStyle.getValign();
        }
        if(valign!=null){
            if(valign.equals(Alignment.top)){
                cell.setVerticalAlignment(Element.ALIGN_TOP);
            }else if(valign.equals(Alignment.middle)){
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
            }else if(valign.equals(Alignment.bottom)){
                cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
            }
        }
        String bgcolor=style.getBgcolor();
        if(customStyle!=null && StringUtils.isNotBlank(customStyle.getBgcolor())){
            bgcolor=customStyle.getBgcolor();
        }
        if(rowStyle!=null && StringUtils.isNotBlank(rowStyle.getBgcolor())){
            bgcolor=rowStyle.getBgcolor();
        }
        if(colStyle!=null && StringUtils.isNotBlank(colStyle.getBgcolor())){
            bgcolor=colStyle.getBgcolor();
        }
        if(StringUtils.isNotEmpty(bgcolor)){
            String[] colors=bgcolor.split(",");
            cell.setBackgroundColor(new BaseColor(Integer.valueOf(colors[0]),Integer.valueOf(colors[1]),Integer.valueOf(colors[2])));
        }
        return cell;
    }
    
    private int[] buildColumnSizeAndTotalWidth(List<Column> columns,List<Integer> list){
        int count=0,totalWidth=0;
        for(int i=0;i<columns.size();i++){
            Column col=columns.get(i);
            int width=col.getWidth();
            if(width<1){
                continue;
            }
            count++;
            list.add(width);
            totalWidth+=width;
        }
        return new int[]{count,totalWidth};
    }
    
    private PdfPCell newPdfCell(Cell cellInfo,int cellHeight) throws Exception{
        PdfPCell cell=null;
        Object cellData=cellInfo.getFormatData();
        if(cellData instanceof Image){
            Image img=(Image)cellData;
            cell=new PdfPCell(buildPdfImage(img.getBase64Data(), 0, 0));
        }else if(cellData instanceof ChartData){
            ChartData chartData=(ChartData)cellData;
            String base64Data=chartData.retriveBase64Data();
            if(base64Data!=null){
                Image img=new Image(base64Data,chartData.getWidth(),chartData.getHeight());
                cell=new PdfPCell(buildPdfImage(img.getBase64Data(), 0, 0));
            }else{
                cell=new PdfPCell();
                CellPhrase pargraph=new CellPhrase(cellInfo,"");
                cell.setPhrase(pargraph);
                cell.setFixedHeight(cellHeight);
            }
        }else{
            cell=new PdfPCell();
            CellPhrase pargraph=new CellPhrase(cellInfo,cellData);
            cell.setPhrase(pargraph);
            cell.setFixedHeight(cellHeight);
        }
        CellStyle style=cellInfo.getCellStyle();
        if(style!=null && style.getLineHeight()>0){
            cell.setLeading(style.getLineHeight(), style.getLineHeight());          
        }
        return cell;
    }
    private com.itextpdf.text.Image buildPdfImage(String base64Data, int width,int height) throws Exception{
        com.itextpdf.text.Image pdfImg=null;
        InputStream input=ImageUtils.base64DataToInputStream(base64Data);
        try{
            byte[] bytes=IOUtils.toByteArray(input);
            pdfImg=com.itextpdf.text.Image.getInstance(bytes);
            float imgWidth=pdfImg.getWidth();
            float imgHeight=pdfImg.getHeight();
            if(width==0){
                width=Float.valueOf(imgWidth).intValue();
            }
            if(height==0){
                height=Float.valueOf(imgHeight).intValue();
            }
            width=UnitUtils.pixelToPoint(width-2);
            height=UnitUtils.pixelToPoint(height-2);
            pdfImg.scaleToFit(width,height);
        }finally{
            IOUtils.closeQuietly(input);
        }
        return pdfImg;
    }
}

说明: 源码就添加了一行

2.2 编写文字水印实现类继承PdfPageEventHelper

package com.bstek.ureport.export.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

public class Watermark extends PdfPageEventHelper {

    Font FONT = new Font(Font.FontFamily.HELVETICA, 50, Font.BOLD, BaseColor.RED);
    private String waterCont;//水印内容
    public Watermark() {

    }
    public Watermark(Object waterCont) {
        if (null != waterCont) {
            this.waterCont = waterCont.toString();
        }
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        PdfContentByte pdfContentByte = writer.getDirectContentUnder();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置填充字体不透明度为0.2f
        gs.setFillOpacity(0.2f);
        pdfContentByte.setGState(gs);
        for(int i=0 ; i<5; i++) {
            for(int j=0; j<5; j++) {
                ColumnText.showTextAligned(pdfContentByte,
                        Element.ALIGN_CENTER,
                        new Phrase(this.waterCont == null ? "HELLO" : this.waterCont, FONT),
                        (60.5f+i*250),
                        (40.0f+j*150),
                        writer.getPageNumber() % 2 == 1 ? 45 : -45);
            }
        }
    }
}

2.3 编写图片水印实现类继承PdfPageEventHelper

package com.bstek.ureport.export.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

public class ImageWatermark extends PdfPageEventHelper {
    public ImageWatermark () {

    }
    public ImageWatermark (Object waterCont) {
        if (null != waterCont) {
            this.waterCont = waterCont.toString();
        }
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        PdfContentByte pdfContentByte = writer.getDirectContentUnder();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置填充字体不透明度为0.3f
        gs.setFillOpacity(0.5f);
        pdfContentByte.setGState(gs);

        try {
            // 获取图片
            InputStream inputStream = this.getClass().getResourceAsStream("/image/水印.png");
            byte[] bytes = toByteArray(inputStream);
            com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(bytes);// 插入水印
            //设置图片水印的位置。
            img.setAbsolutePosition(0, 0);
            img.scaleToFit(864,612);
            pdfContentByte.addImage(img);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
    // 输入流转字节数组
    public byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024*4];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }
}

2.3 测试

三. 不覆盖源码

如果不覆盖源码加水印, 那就要新增一套导出逻辑, 只需要模仿原逻辑, 加一种导出的方法就行

3.1 增加访问入口

  • 继承类: com.bstek.ureport.console.pdf.ExportPdfServletAction
  • 新增一个url入口


3.2 加一个生成pdf处理逻辑


com.bstek.ureport.console.pdf.ExportPdfServletAction#buildPdf中可以看到com.bstek.ureport.export.ExportManager#exportPdf是生成pdf的逻辑, 所以要重写这个逻辑

  • 继承类com.bstek.ureport.export.ExportManagerImpl, 模仿com.bstek.ureport.export.ExportManagerImpl#exportPdf重写一个方法exportPdf
  • 继承com.bstek.ureport.export.pdf.PdfProducer模仿com.midea.cloud.ureport.extension.ExtPdfProducer#produce重写方法produce
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。