java

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

moonsiri 2021. 5. 7. 20:09
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) 

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

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

			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();

			ClientAnchor preferredSize = pict.getPreferredSize();
			cellCount = preferredSize.getCol2() + 1;
			rowCount = preferredSize.getRow2() + 1;
		} catch(Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
		} finally {
			FileUtils.deleteQuietly(imageFile);
		}
	}
    
}
더보기
@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) 

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

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

			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();

			ClientAnchor preferredSize = pict.getPreferredSize();
			cellCount = preferredSize.getCol2() + 1;
			rowCount = preferredSize.getRow2() + 1;
		} catch(Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
		} finally {
			FileUtils.deleteQuietly(imageFile);
		}
	}

	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
반응형