본문으로 바로가기

728x90

Java ImageWriter사용하기

필자는 마우스입력기의 보안솔루션을 개발하면서 일부 고객사에서 이미지IO와 관련하여 응답시간이 오래 걸린다는 보고가 되었습니다. 딱히 오류 결과만 보면 문제될 만한 부분이 없는데 문제가 발생하니 방안도 적절하지 못하였습니다. Java를 이용하여 이미지 결과물을 만들어 낼 때 ImageIO.write()를 사용하면 속도가 저하되는 문제가 발생하였습니다. 또한 ImageIO.write()는 Thread Safe하지 않다고 검색된 내용도 있었습니다.

// 이미지 합성
OutputStream os = null;
try {
	BufferedImage bi = keypad.getImage();
	out.clear();								// Response값을 초기화합니다.
	response.setContentType("image/png");		// 마임타입을 지정합니다.
	os = response.getOutputStream();			// HttpServletResponse의 Stream객체를 얻습니다.
	ImageIO.write( bi , "png" , os );			// PNG 이미지를 생성합니다.
	os.flush();									// Stream에 값을 모두 내보냅니다.
} catch (Exception e) {
	e.printStackTrace();
} finally {
	if(os != null) try{os.close();}catch(Exception e){}
}

이에 아래와 같이 이미지 IO를 ImageWriter를 사용하는 방법으로 변경하였습니다. 얼마 되지는 않았지만 아직 같은 오류보고가 되지는 않고 있습니다. 이번 오류를 수정하면서 HttpServletResponse에 직접 write하지 않고 byte배열을 통해 이미지 바이어리를 생성하고 그 byte 배열을 Response에 쓰는 방식으로 변경하였습니다.

 

// 이미지 합성
OutputStream os = null;
try {
	BufferedImage bi = keypad.getImage();
	out.clear();								// Response값을 초기화합니다.
	response.setContentType("image/png");		// 마임타입을 지정합니다.
    
	// Byte Array Stream 을 생성합니다.
	ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	MemoryCacheImageOutputStream outputStream = new MemoryCacheImageOutputStream(byteArrayOutputStream);

	// ImageWriter를 png포맷으로 생성합니다.
	Iterator iter = ImageIO.getImageWritersByFormatName("png");
	ImageWriter writer = (ImageWriter) iter.next();
	ImageWriteParam iwp = writer.getDefaultWriteParam();
	//iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
	//iwp.setCompressionQuality(IMAGE_QUALITY);
    
    // 출력될 Stream을 지정합니다.
	writer.setOutput(outputStream);
	
    // ImageWriter를 통해 이미지를 생성합니다.
	IIOImage image = new IIOImage(bi, null, null);
	writer.write(null, image, iwp);
	writer.dispose();
    
	// byte[] 배열로 변환합니다.
	byte[] result = byteArrayOutputStream.toByteArray();
	byteArrayOutputStream.close();
	outputStream.close();
	
	os = response.getOutputStream();			// HttpServletResponse의 Stream객체를 얻습니다.
	os.write(result);							// byte[]을 Stream에 write합니다.
	os.flush();									// Stream에 값을 모두 내보냅니다.
} catch (Exception e) {
	e.printStackTrace();
} finally {
	if(os != null) try{os.close();}catch(Exception e){}
}

 

붙임글

개발하고 있는 솔루션에서 이미지합성 라이브러리를 추가적으로 고민하였습니다. 하지만 단일한 jar을 제공하기 위해서 일단 이미지 합성을 위한 다른 라이브러리는 고려하지 않았습니다. Apache Imaging 라이브러리JDeli Image 라이브러리를 사용하는 것도 다른 방법 중 하나로 생각됩니다.

 

참고자료

stackoverrun.com/ko/q/4155340

stackoverrun.com/ko/q/2899148

www.programcreek.com/java-api-examples/?api=javax.imageio.ImageWriter

www.programcreek.com/java-api-examples/?api=javax.imageio.stream.MemoryCacheImageOutputStream

blog.idrsolutions.com/2014/10/imageio-write-executorservice-io-bound-applications-java/

 

 

728x90