adsense



javax - BufferedImage를 사용한 이미지의 확대, 축소, 회전



참조 :
http://stackoverflow.com/questions/4787066/how-to-resize-and-rotate-an-image


확대/축소 함수. 가로와 세로를 각각 따로 지정 가능.

  1.         //확대 축소된 BufferedImage 얻기
  2.         BufferedImage getScaledImage(BufferedImage image, int width, int height){
  3.                
  4.                 GraphicsConfiguration gc = frame.getGraphicsConfiguration();
  5.                 BufferedImage result = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
  6.                 Graphics2D g = result.createGraphics();
  7.                
  8.                 double w = image.getWidth();
  9.                 double h = image.getHeight();
  10.                 g.scale((double)width/w, (double)height/h);
  11.                 g.drawRenderedImage(image, null);
  12.                 g.dispose();
  13.                
  14.                 return result;
  15.         }
  16.  

회전 함수. 0~360도 사이의 degree값을 지정합니다.
  1.         //회전시킨 BufferedImage 얻기
  2.         BufferedImage getRotateImage(BufferedImage image, double angle){//angle : degree
  3.                
  4.                 double _angle = Math.toRadians(angle);
  5.                 double sin = Math.abs(Math.sin(_angle));
  6.                 double cos = Math.abs(Math.cos(_angle));
  7.                 double w = image.getWidth();
  8.                 double h = image.getHeight();
  9.                 int newW = (int)Math.floor(w*cos + h*sin);
  10.                 int newH = (int)Math.floor(w*sin + h*cos);
  11.                
  12.                 GraphicsConfiguration gc = frame.getGraphicsConfiguration();
  13.                 BufferedImage result = gc.createCompatibleImage(newW, newH, Transparency.TRANSLUCENT);
  14.                 Graphics2D g = result.createGraphics();
  15.                
  16.                 g.translate((newW-w)/2, (newH-h)/2);
  17.                 g.rotate(_angle, w/2, h/2);
  18.                 g.drawRenderedImage(image, null);
  19.                 g.dispose();
  20.                
  21.                 return result;
  22.         }
  23.  

위 링크에 있는 내용을 따서 게임용도의 범용 함수로 사용할 수 있도록 정리했습니다.


3D엔진에 기반한 확대축소회전과의 차이


- 비트맵 이미지를 실시간 연산하여 확대/축소/회전된 이미지를 새로 생성, 받아서 출력하는 방식입니다.
- 그때문에 CPU 부하가 상당히 걸립니다. 메모리도 제법 많이 사용하고요. 특히 회전은 내부적으로 삼각함수 연산 덩어리이므로 커다란 이미지를 회전시키기 시작하면 치솟는 CPU 사용률을 볼 수 있습니다.

- 픽셀의 위치가 이동하면서 보간(중간값의 생성)이 이루어지지 않기 때문에 일그러짐이 발생합니다.


사용 예:
Graphics2D g;
.
.
g.drawImage(getScaledImage(ImgBuf, 360,240), 320, 240, this);//ImgBuf이미지를 가로 360, 240픽셀로 출력
g.drawImage(getRotateImage(ImgBuf, 111, 320, 240, this);//ImgBuf이미지를 시계방향으로 111도 회전하여 출력


※위와 같이 하면 회전 시 중심점이 마구 움직이는 것을 볼 수 있는데, 그림 중앙을 축으로 회전시키기 위해서는

  int w = image.getWidth();
  int h = image.getHeight();
  
  g.drawImage(image, x-w/2, y-h/2, obs);


이런 식으로 하면 됩니다.

확대/축소와 회전을 동시에 하려면..
g.drawImage(getRotateImage(getScaledImage(ImgBuf, 480,480), 167), 320, 240, this);
g.drawImage(getScaledImage(getRotateImage(ImgBuf, 167), 480,480), 320, 240, this);


이런 식으로 한 쪽을 인수로 다른 쪽에 넣습니다. 위 코드는 두 예 모두 동일한 처리를 합니다. (단, 일그러짐에서 차이가 발생할 수도..)


아래는 위 함수를 적용한 간단한 예제 프로젝트(이클립스용)입니다.

이미지의 로딩, 사운드 등 게임 제작에 필요한 기초 함수가 함께 들어있고 게임의 기초가 되는 순환구조 스레드를 포함하고 있으므로(요시카 스크램블보다는 깨끗하게 정리된 편이라고 생각합니다) 자바로 게임을 만드려는 분들께 도움이 되지 않을까 기대합니다.


GameFrameWork.zip - 싱글 스레드를 사용한 간단 게임 프레임 워크 (※getAngle의 버그수정과 추가 함수가 갱신됐습니다. 2014.11.15)



프레임워크 구조
 JFrame - 창 선언, 프레임과 키, 마우스 이벤트
 Canvas - 빠른 화면 그리기
 Thread - 원활한 제어를 위한 순환구조

※싱글 스레드를 쓰는 이유는 프로그램을 프로그래머가 예측 가능한 상황 하에 두기 위해.
※싱글 스레드라고는 해도 키 이벤트, 마우스 이벤트 등에 의해 비동기적인 개입이 발생할 수 있다.


게임 제작을 위한 편의 함수들
 * 이미지 크기 조절(확대/축소)
 * 이미지 회전
 * 배경음악 연주
 * 효과음 발생
 * 일정 범위의 난수 구하기
 * 한 점에서 다른 점을 향한 각도(degree) 구하기
 * 두 점 사이의 거리 구하기
 * 상자충돌 여부
 * 이미지로부터 Rectangle 얻어내기
 * 점 a로부터 지정된 각도, 거리에 있는 점 b 구하기
 * 숫자 문자열에 comma 넣기
 * 그림숫자 출력
 * 이미지 클리핑
 * 이미지 클리핑 확장 버전 (프레임 출력)


Fin.




덧글

댓글 입력 영역


Books

Geek라이프

메가 드라이브 퍼펙트 카탈로그
마에다 히로유키 저/조기현 역

미소녀 일러스트 테크닉
B-은하, pen스케, 카와이 저/정유진 역

핵심강좌! Cocos2d-x
이재환 저

피규어의 교과서 레진 키트 & 도색 입문 편
후지타 시게토시 저/김정규 역
예스24 | 애드온2
일본서적 전문사이트 NEPIC