生成离线报告-java将白色背景透明和裁减掉白色背景部分

生成离线报告的一种方式

用puppeteer(node服务)打开网页生成图片,然后将图片替换到PPT的模板中。
有一个问题是生成的图片会有很多空白部分,所以要用java将白色背景透明化, 一种方式是将图片的白色背景透明,另一种方式是将图片的白色背景部分剪裁掉。PPT模板图片事先根据固定尺寸大小建好的,如果替换的图片大小不一致就可能导致图片拉伸变形
最终采用生成离线报告的方案

  1. 创建图片目录
  2. puppeteer打开网页生成图片
  3. (可选)java程序用poi插件不用模板直接将图片输出到PPT中
  4. (可选)制作一个PPT模板,将第3步生成PPT中的图片拷贝过来,保持纵横比调整图片,底部白色部分会超过PPT页的大小,只需要保证有内容的部分都在PPT页中就可以了,注意PPT模板中相似的图片不要直接复制要使用不同的图片
  5. 将puppeteer生成的图片的白色背景变为透明
  6. 将处理过的图片替换到模板PPT的图片中

puppeteer生成图片的关键代码

const puppeteer = require('puppeteer');
const request = require('request');
async function createImage(url, imagePath) {
  console.log(`==================== 开始生成图片:${imagePath} =========================`);
  console.time('生成图片花费时间');
  const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
  const page = await browser.newPage();
  page.setViewport({ width: 1200,  height: 800});
  try {
    await page.goto(url);
    await Promise.race([
      page.waitForNavigation({ waitUntil: "networkidle0", timeout: 0 }),
      // 等待页面元素渲染完成  我们的网页渲染完以后会添加一个chart-download的class属性,这个根据情况定制
      page.waitForSelector('.chart-download')
    ])
    await page.screenshot({path: imagePath, fullPage: true});
  } catch (error) {
    console.log('Error: ', error);
    throw error;
  } finally {
    await browser.close();
    console.timeEnd('生成图片花费时间');
    console.log('当前日期:', (new Date()).toLocaleString());
    console.log(`==================== 结束生成图片:${imagePath} =========================`);
  }
}
module.exports = createImage;

java将图片白色背景透明化
原文java对图片进行透明化处理
原代码对图片处理过一次以后处理第二次就会出现黑色背景,做了一点点改动

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;

import java.awt.*;
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.IOException;  
   
import javax.imageio.ImageIO;  
import javax.swing.ImageIcon;  
import javax.swing.JOptionPane;  

@Slf4j
public class PictureUtil {
   
    public static void removeWhiteBackground(String path) {
        try {  
            BufferedImage image = ImageIO.read(new File(path));  
            ImageIcon imageIcon = new ImageIcon(image);  
            BufferedImage bufferedImage = new BufferedImage(  
                    imageIcon.getIconWidth(), imageIcon.getIconHeight(),  
                    BufferedImage.TYPE_4BYTE_ABGR);  
            Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();  
            g2D.drawImage(imageIcon.getImage(), 0, 0,  
                    imageIcon.getImageObserver());  
            int alpha = 0;  
            for (int j1 = bufferedImage.getMinY(); j1 < bufferedImage  
                    .getHeight(); j1++) {  
                for (int j2 = bufferedImage.getMinX(); j2 < bufferedImage  
                        .getWidth(); j2++) {  
                    int rgb = bufferedImage.getRGB(j2, j1);
                    Color color = new Color(rgb, true);
                    // 如果已经透明了就不再处理
                    if(color.getAlpha() == 0){
                        continue;
                    }
                    if (colorInRange(rgb))  
                        alpha = 0;  
                    else  
                        alpha = 255;  
                    rgb = (alpha << 24) | (rgb & 0x00ffffff);  
                    bufferedImage.setRGB(j2, j1, rgb);  
                }  
            }  
            g2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());  
            // 生成图片为PNG  
            String outFile = path.substring(0, path.lastIndexOf("."));  
            ImageIO.write(bufferedImage, "png", new File(outFile + ".png"));  
        } catch (IOException e) {
           log.error(ExceptionUtils.getFullStackTrace(e));
        }  
    }  
   
    public static boolean colorInRange(int color) {  
        int red = (color & 0xff0000) >> 16;  
        int green = (color & 0x00ff00) >> 8;  
        int blue = (color & 0x0000ff);  
        if (red >= color_range && green >= color_range && blue >= color_range)  
            return true;  
        return false;  
    }  
    // 根据需要自己调整这个阈值,如果只需要去掉纯白色背景就设为255
    public static int color_range = 250;
}

另外,把java去除图片多余白色背景部分的代码粘贴一下,原作者博客地址不记得了

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * Created by liufang on 2019/4/10.
 */
public class PictureTrimWhite {
    private BufferedImage img;
    // 图片右边和底部还需要保留一点白色背景,否则太难看了
    private static final int REMAIN_WIDTH = 20;
    public PictureTrimWhite(File input) {
        try {
            img = ImageIO.read(input);
        } catch (IOException e) {
            throw new RuntimeException( "Problem reading image", e );
        }
    }

    public void trim() {
        int width  = getTrimmedWidth();
        int height = getTrimmedHeight();

        BufferedImage newImg = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics g = newImg.createGraphics();
        g.drawImage( img, 0, 0, null );
        img = newImg;
    }

    public void write(File f) {
        try {
            ImageIO.write(img, "png", f);
        } catch (IOException e) {
            throw new RuntimeException( "Problem writing image", e );
        }
    }

    private int getTrimmedWidth() {
        int height       = this.img.getHeight();
        int width        = this.img.getWidth();
        int trimmedWidth = 0;

        for(int i = 0; i < height; i++) {
            for(int j = width - 1; j >= 0; j--) {
                if(img.getRGB(j, i) != Color.WHITE.getRGB() &&
                        j > trimmedWidth) {
                    trimmedWidth = j;
                    break;
                }
            }
        }
        trimmedWidth += REMAIN_WIDTH;
        if(trimmedWidth>width){
            trimmedWidth = width;
        }
        return trimmedWidth;
    }

    private int getTrimmedHeight() {
        int width         = this.img.getWidth();
        int height        = this.img.getHeight();
        int trimmedHeight = 0;

        for(int i = 0; i < width; i++) {
            for(int j = height - 1; j >= 0; j--) {
                if(img.getRGB(i, j) != Color.WHITE.getRGB() &&
                        j > trimmedHeight) {
                    trimmedHeight = j;
                    break;
                }
            }
        }
        trimmedHeight += REMAIN_WIDTH;
        if(trimmedHeight>height){
            trimmedHeight = height;
        }
        return trimmedHeight;
    }

    public static void main(String[] args) {
        PictureTrimWhite trim = new PictureTrimWhite(new File("C:\\Users\\Administrator\\Desktop\\tmp\\离线图片.png"));
        trim.trim();
        trim.write(new File("E:\\tmp\\tmp.png"));
    }
}

poi将图片替换到PPT模板部分代码也在这里粘贴一下

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.xslf.usermodel.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

@Slf4j
public class PPTUtil {
	
	// 不带模板生成PPT
	public static boolean writePptFile(File pptFile, List<String> picPaths) {
		if (!pptFile.exists()) {
			pptFile.getParentFile().mkdirs();
		}
		try(FileOutputStream out = new FileOutputStream(pptFile)){
			if (picPaths != null && picPaths.size() > 0) {
				// 构建PPT
				XMLSlideShow ppt = new XMLSlideShow();
				for (String picPath : picPaths) {
					// 创建幻灯片
					XSLFSlide blankSlide = ppt.createSlide();
					XSLFPictureData pd = ppt.addPicture(org.apache.commons.io.FileUtils.readFileToByteArray(new File(picPath)), PictureData.PictureType.PNG);
					blankSlide.createPicture(pd);
				}
				// 输出PPT文件
				ppt.write(out);
				return true;
			}
		}catch (IOException e){
			log.error(ExceptionUtils.getFullStackTrace(e));
		}
		return false;
	}
	// 根据PPT模板生成PPT
	public static boolean writePptFile(File pptFile, String motherPpt, String reportDate, List<OnlineReportImage> reports) {
		if (!pptFile.exists()) {
			pptFile.getParentFile().mkdirs();
		}
		try(FileOutputStream out = new FileOutputStream(pptFile);FileInputStream mother = new FileInputStream(motherPpt)){
			if (reports != null && reports.size() > 0) {
				// 从模板页中构建PPT
				XMLSlideShow ppt = new XMLSlideShow(mother);
				// 第一页模板页替换内容
				XSLFSlide slide1 = ppt.getSlides().get(0);
				for (XSLFShape shape : slide1.getShapes()) {
					if (shape instanceof XSLFTextShape) {
						XSLFTextShape txShape = (XSLFTextShape) shape;
						if (txShape.getText().contains("{reportDate}")) {
							// 替换文字内容
							txShape.setText(txShape.getText().replace("{reportDate}", reportDate));
						}
					}
				}
				for (OnlineReportImage report : reports) {
					XSLFSlide slide = ppt.getSlides().get(report.getLocation() - 1);
					for (XSLFShape shape : slide.getShapes()) {
						if (shape instanceof XSLFPictureShape) {
							XSLFPictureShape pShape = (XSLFPictureShape) shape;
							XSLFPictureData pData = pShape.getPictureData();
							pData.setData(org.apache.commons.io.FileUtils.readFileToByteArray(new File(report.getFile())));
						}
					}
				}
				// 输出PPT文件
				ppt.write(out);
				return true;
			}
		}catch (IOException e){
			pptFile.delete();
			log.error(ExceptionUtils.getFullStackTrace(e));
		}
		return false;
	}
}
@Data
public class OnlineReportImage {
    /**
     * 生成的图片路径
     */
    private String file;
    /**
     * 图片在PPT模板中的位置
     */
    private int location;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值