java POI在excel中插入等比例缩放的图片

这个缩放的比例不是很准确,但还凑合能用,目前本人找不到其它方法,就先用这个。

先看一个关键的API方法:void org.apache.poi.ss.usermodel.Picture.resize(double scaleX, double scaleY),一定要清楚这个方法中的参数 scaleX 和 scaleY 的比例是最终图片的宽高与单元格宽高的比例,不是与原图片宽高的比例。(而且当scaleX=1时,按道理应该占满单元格,但我测试后一直占不满不知道为什么,这可能也是最后比例不准确的原因之一)

测试代码在下面,大体说明一下这个代码:根据旧的excel,生成新的excel,新的excel需要在原有基础上插入一个图片,插入图片的位置是批注为“img”的单元格,生成的图片宽是70PX(可以根据参数调整),高度是根据最终图片宽度与原图的比例调整的,如果原图的宽度小于70PX,则直接插入原图。引入需要的依赖后,创建新类复制代码,可直接测试,缩放图片的关键部分都有注释,这是写好的业务代码,不是demo,所以有些冗长,可根据自身需要删除不必要的部分。

package com.buptnu.excel;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;

import javax.imageio.ImageIO;

import org.apache.poi.POIXMLDocument;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelUtils {
	
	/**
	 * 生成Excel
	 * @param targetPath 原excel文件地址
	 * @param imgPath 图片地址
	 * @param newFilePath 生成的新excel文件地址
	 * @param width 生成的新的图片宽度,单位是像素
	 */
	public static void dataExportExcel(String targetPath, String imgPath, String newFilePath, double width) {
		InputStream input = null;
		OutputStream output = null;
		Workbook workbook = null;
		try {
			input = new FileInputStream(targetPath);
			if (!input.markSupported()) {
				input = new PushbackInputStream(input, 8);
			}
			if (POIFSFileSystem.hasPOIFSHeader(input)) {
				workbook= new HSSFWorkbook(input);// excel 2003
		    } else if (POIXMLDocument.hasOOXMLHeader(input)) {
		    	workbook = new XSSFWorkbook(OPCPackage.open(input));// excel 2007
		    }
			Sheet sheet = workbook.getSheetAt(0);
			for (int i = 0; i < sheet.getLastRowNum() + 1; i++) {
				Row row = sheet.getRow(i);
				if (row == null) {
					continue;
				}
				for (int j = 0; j < row.getLastCellNum(); j++) {
					Cell cell = row.getCell(j);
					if (cell == null) {
						continue;
					}
					Comment comment = cell.getCellComment();
					if (comment == null) {
						continue;
					}
					String commentValue = comment.getString().getString().trim();
					if (commentValue.equals("img")) {
						ExcelUtils.replaceImage(workbook, sheet, cell, imgPath, j, i, width);
					}
					cell.removeCellComment();
				}
			}
			File file = new File(newFilePath);
			if (!file.exists()) {
				file.createNewFile();
			}
			output = new FileOutputStream(newFilePath);
			workbook.write(output);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) { }
			}
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) { }
			}
		}
	}
	
	/**
	 * 替换图片
	 * @param book
	 * @param sheet
	 * @param cell
	 * @param jdImagePath
	 * @param jdcol
	 * @param jdrow
	 * @param width
	 * @return
	 * @throws Exception
	 */
	public static Workbook replaceImage(Workbook book, Sheet sheet, Cell cell, String jdImagePath, int jdcol, int jdrow, double width) throws Exception {
    	InputStream jdis;
    	byte[] jdbytes = null;
		try {
			jdis = new FileInputStream(jdImagePath);
			jdbytes = IOUtils.toByteArray(jdis);
		} catch (Exception e) {
			e.printStackTrace();
		}
    	CreationHelper helper = book.getCreationHelper();  
    	Drawing drawing  = null;
    	if (sheet instanceof XSSFSheet) {
    		XSSFSheet xSSFSheet = (XSSFSheet)sheet;
    		drawing = xSSFSheet.getDrawingPatriarch();
    	} else if (sheet instanceof HSSFSheet) {
    		HSSFSheet hSSFSheet = (HSSFSheet)sheet;
    		drawing = hSSFSheet.getDrawingPatriarch();
    	}
    	if (drawing == null) {
    		drawing = sheet.createDrawingPatriarch(); 
    	}
    	// 图片插入坐标  
    	if (-1 != jdcol && -1 != jdrow) {
    		int jdpictureIdx = book.addPicture(jdbytes, Workbook.PICTURE_TYPE_JPEG);// 根据需要调整参数,如果是PNG,就改为 Workbook.PICTURE_TYPE_PNG
    		ClientAnchor jdanchor = helper.createClientAnchor();  
	    	jdanchor.setCol1(jdcol);
	    	jdanchor.setRow1(jdrow);
	    	// 获取原图片的宽度和高度,单位都是像素
	    	File image = new File(jdImagePath);
	    	BufferedImage sourceImg = ImageIO.read(image);
	    	double imageWidth = sourceImg.getWidth();
	    	double imageHeight = sourceImg.getHeight();
	    	// 获取单元格宽度和高度,单位都是像素
	    	double cellWidth = sheet.getColumnWidthInPixels(cell.getColumnIndex());
	    	double cellHeight = cell.getRow().getHeightInPoints() / 72 * 96;// getHeightInPoints()方法获取的是点(磅),就是excel设置的行高,1英寸有72磅,一般显示屏一英寸是96个像素
	    	// 插入图片,如果原图宽度大于最终要求的图片宽度,就按比例缩小,否则展示原图
	    	Picture pict = drawing.createPicture(jdanchor, jdpictureIdx);
	    	if (imageWidth > width) {
	    		double scaleX = width / cellWidth;// 最终图片大小与单元格宽度的比例
	    		// 最终图片大小与单元格高度的比例
	    		// 说一下这个比例的计算方式吧:( imageHeight / imageWidth ) 是原图高于宽的比值,则 ( width * ( imageHeight / imageWidth ) ) 就是最终图片高的比值,
	    		// 那 ( width * ( imageHeight / imageWidth ) ) / cellHeight 就是所需比例了
		    	double scaleY = ( width * ( imageHeight / imageWidth ) ) / cellHeight;
	    		pict.resize(scaleX, scaleY);
	    	} else {
	    		pict.resize();
	    	}
    	}
    	return book;
    }
	
	public static void main(String[] args) {
		ExcelUtils.dataExportExcel("F:\\test.xlsx", "F:\\test1.jpg", "F:\\test2.xlsx", 70);
	}
	
}

maven的POI依赖:

        
          org.jxls 
          jxls-poi 
          1.0.9 
        

        
            org.apache.poi
            poi
            3.12
        

 

你可能感兴趣的:(java,后端,poi,excel插入等比例图片)