본문 바로가기
java

[Java] POI 라이브러리로 엑셀에 이미지 삽입하기

by moonsiri 2021. 5. 7.
728x90
반응형

canvas로 이루어져 있는 차트 이미지를 엑셀 파일에 삽입해보겠습니다.

 

 

toDataURL()을 사용하여 원하는 영역을 base64 문자열로 읽어 back단에 데이터를 전달합니다.

const imageData = $("#load-graph").find("canvas")[0].toDataURL("image/png", 0.5);

 

만약 canvas로 그려지지 않은 영역을 이미지로 저장하고 싶다면, html2canvas.js 라이브러리를 사용하여 html 영역을 canvas로 변경하면 됩니다.

html2canvas($("#chart")[0]).then(function(canvas) {
    const imageData = canvas.toDataURL("image/png");
    ...

 

엑셀에 이미지 삽입하는 부분입니다.

@Slf4j
@Service
public class ExcelServiceImpl implements ExcelService {

	@Value("${download.dir}")
	private String fileCommonPath;

	//png 파일 base64 인코딩 pre fix 제거를 위한 변수 선언
	private static final String BASE64_PNG_PRE_FIX = "data:image/png;base64,";

	private int rowCount;
	private int cellCount;
    
	// (...생략...)
    
	private void setChart(SXSSFWorkbook workBook, SXSSFSheet sheet, String imageData) {
		InputStream in = null;
		FileOutputStream fos = null;
		File imageFile = null;
		try {

			String encodingStr = imageData.replace(BASE64_PNG_PRE_FIX, "");
			byte[] decodeImg = Base64.decodeBase64(encodingStr);

			FileUtils.forceMkdir(new File(fileCommonPath)); //디렉토리 미 존재시 생성
			imageFile = new File(fileCommonPath + "/chartImg.png");
			fos = new FileOutputStream(imageFile);
			fos.write(decodeImg);

			in = new FileInputStream(imageFile);
			byte[] bytes = IOUtils.toByteArray(in);
			int pictureIdx = workBook.addPicture(bytes, SXSSFWorkbook.PICTURE_TYPE_PNG);

			final CreationHelper helper = workBook.getCreationHelper();
			final Drawing drawing = sheet.createDrawingPatriarch();
			final ClientAnchor anchor = helper.createClientAnchor();

			// 이미지를 출력할 CELL 위치 선정
			cellCount = 0;
			anchor.setCol1(cellCount++);
			anchor.setRow1(rowCount++);

			// 이미지 그리기
			final Picture pict = drawing.createPicture(anchor, pictureIdx);

			// 이미지 사이즈 비율 설정
			pict.resize();

			rowCount = rowCount + 20; // FIXME 이미지 높이만큼 rowCount 추가필요
		} catch(Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
		} finally {
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(fos);
			imageFile.delete();
		}
	}
    
}
더보기
@Slf4j
@Service
public class ExcelServiceImpl implements ExcelService {

	@Value("${download.dir}")
	private String fileCommonPath;

	//png 파일 base64 인코딩 pre fix 제거를 위한 변수 선언
	private static final String BASE64_PNG_PRE_FIX = "data:image/png;base64,";

	private int rowCount;
	private int cellCount;

	@Override
	public void downloadExcel(ExcelReq param, HttpServletResponse response) throws Exception {
		// init
		SXSSFWorkbook workBook = new SXSSFWorkbook();
		workBook.setCompressTempFiles(true);
		SXSSFSheet sheet = workBook.createSheet(param.getFileName());
		sheet.setRandomAccessWindowSize(100);
		rowCount = 0;
		cellCount = 0;

		// data setting
		this.setTitle(workBook, sheet, param);
		this.setChart(workBook, sheet, param.getImageData());
		this.setData(workBook, sheet, param);

		// file download
		String fullpath = this.getFilePath(param.getFileName());
		this.write(workBook, fullpath);
		this.downloadExcelFileToWeb(new File(fullpath), response);
	}
    
	// (...생략...)


	private void setChart(SXSSFWorkbook workBook, SXSSFSheet sheet, String imageData) {
		InputStream in = null;
		FileOutputStream fos = null;
		File imageFile = null;
		try {

			String encodingStr = imageData.replace(BASE64_PNG_PRE_FIX, "");
			byte[] decodeImg = Base64.decodeBase64(encodingStr);

			FileUtils.forceMkdir(new File(fileCommonPath)); //디렉토리 미 존재시 생성
			imageFile = new File(fileCommonPath + "/chartImg.png");
			fos = new FileOutputStream(imageFile);
			fos.write(decodeImg);

			in = new FileInputStream(imageFile);
			byte[] bytes = IOUtils.toByteArray(in);
			int pictureIdx = workBook.addPicture(bytes, SXSSFWorkbook.PICTURE_TYPE_PNG);

			final CreationHelper helper = workBook.getCreationHelper();
			final Drawing drawing = sheet.createDrawingPatriarch();
			final ClientAnchor anchor = helper.createClientAnchor();

			// 이미지를 출력할 CELL 위치 선정
			cellCount = 0;
			anchor.setCol1(cellCount++);
			anchor.setRow1(rowCount++);

			// 이미지 그리기
			final Picture pict = drawing.createPicture(anchor, pictureIdx);

			// 이미지 사이즈 비율 설정
			pict.resize();

			rowCount = rowCount + 20; // FIXME 이미지 높이만큼 rowCount 추가필요
		} catch(Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
		} finally {
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(fos);
			imageFile.delete();
		}
	}

	private void write(SXSSFWorkbook workBook, String fullPath) throws Exception {

		// file write
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(fullPath);
			workBook.write(fos);
		} finally {
			IOUtils.closeQuietly(fos);
			IOUtils.closeQuietly(workBook);
		}
	}

	private void downloadExcelFileToWeb(File excelFile, HttpServletResponse res) {

		if (excelFile == null || excelFile.exists() == false) {
			throw new IllegalArgumentException("invalid excelFile path");
		}

		String fileNm = FilenameUtils.getName(excelFile.getAbsolutePath());

		res.setContentType("applicaiton/vnd.ms-excel;charset=utf-8");
		res.setHeader("Content-Disposition", "attachment;filename=\"" + fileNm + "\";");

		OutputStream out = null;
		FileInputStream fis = null;

		try {

			out = res.getOutputStream();
			fis = new FileInputStream(excelFile);
			FileCopyUtils.copy(fis, out); //buffer copy
			out.flush();

		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			IOUtils.closeQuietly(fis);
			IOUtils.closeQuietly(out);
            excelFile.delete();
		}

	}
}

 

아래는 결과물입니다.

 

 

+)

	private void setCellStyle(SXSSFWorkbook workBook, CellStyle cell, int fontSize) {

		Font fontStyle = workBook.createFont();
		fontStyle.setBold(true);	// 굵은 글씨
		fontStyle.setFontHeight((short)(fontSize*20));	// 폰트 크기
        
		CellStyle style = workBook.createCellStyle();
		style.setFont(fontStyle);	// font style setting
        
		// cell에 테두리
		style.setBorderTop(BorderStyle.THIN);
		style.setBorderBottom(BorderStyle.THIN);
		style.setBorderLeft(BorderStyle.THIN);
		style.setBorderRight(BorderStyle.THIN);
        
		// 가운데 정렬
		style.setAlignment(HorizontalAlignment.CENTER);
        
		// 배경색 설정
		style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
		style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
 
 		// cell에 style 설정
		cell.setCellStyle(style);
	}

 

728x90
반응형

댓글