'임베이드 장비/이젠 한물간 Wipi'에 해당되는 글 2건

Jlet에서의 encodeImage 란 함수가 있습니다.

Graphics 밑에 딸려 나온 것으로 역할은 이미지 데이터를 byte [] 뽑아줍니다.
음... 사용법에 대해선 전에 주의점으로 소개를 했지만 다시 써봅니다.

public static Image CopyImage(Image src)
{
  // 지금 들어오는 src를 바로  그래픽 받아오게 하면, 읽기 전용상태라 NullPointException이 발생한다
  // 이를 방지하기위해 Image copy본을 만든뒤 그 이미지를 encodeImage 하면된다.

  byte []temp = null;
  Image copy = Image.createImage(src);
  Graphics g = copy.getGraphics();
 
  temp = g.encodeImage(0, 0, src.getWidth(), src.getHeight());
  Image result = Image.createImage(temp, 0, temp.length);
 
  return result;
 }

C언어와 달리 들어오는 Image src 에 대해서 바로 접근이 안됩니다.
C언어라면, 함수가 호출되면서 Image src의 복사본이 오게 되겠지만, Java 문법상.. (아니 Wipi만 그런가?)
C 언어로 치면 Image CopyImage(const Image &src) 와 같이 들어오는거 같습니다.

참 비효율적이라고 생각 됩니다. 아니.. 내공이 부족한건지.. 하여간 윗 소스는
1. 받아온 Image의 Copy 를 생성한다.
2. 그 복사본 이미지에 대한 그래픽을 만든다.
3. byte [] temp 라는 배열 안에 복사본 이미지 전체 영역, (0,0)~(width, height)만큼 인코딩 시킨다
4. 가져온 temp byte 배열을 가지고 이미지를 생성한다. 생성하되, 시작 번지는 0 ~ temp 길이 만큼임

으로 생각하시면 됩니다..


왜 이렇게 하는건지는 잘 모르겠지만. 뭐 wipi가 그러니 그려러니 하는 수밖에 없죠.. 왠지 알면 알수록
꼬인다는 느낌이 Wipi입니다.. orz

하여간 이 encodeImage 저는 이미지에 대해 변화를 많이 주는 프로세싱을 하다 보니,
일반적으로
1. GetPixel 로 좌표의 RGB 알아낸다.
2. 이 RGB를 적당한 알고리즘으로 변형시킨다.
3. SetColor 로 RGB값을 지정한다.
4. SetPixel로 해당 좌표에 점을 찍는다…

를 하기엔, 퍼포먼스가 너무 딸리게 됩니다. 돌아가는 환경이 PC로 치면 386,486급을 달리고 있고,
거기에 어셈만큼 빠른 C언어가 아닌 Java… 버추얼 PC를 통해서 느린 판국에 Class 개념의 객체 지향은
일반 C언어의 순차적 언어에 비하면 많이 느리죠
(모바일 경우.. 뭐 어떻게 뜯어 고쳐서 Jlet도 Clet에 비하면 80%정도 성능을 낸다고 합니다만.. 음…)

하여간, MFC의 (비교대상이 되려나..) GetPixel, SetPixel 를 사용하면 최신 듀얼 CPU 컴퓨터도 버벅이는 상황에서
모바일이라고 별수 있나요.. 그래서 GetPixel, SetPixel 을 사용하지 않고 이것을 배열에 다 넣은뒤
이 배열 값을 조작한 다음 다시 나중에 이미지 만들면 되겠다 싶어서 encodeImage에 대해 파게 됬습니다.. orz

우선 들어가기 앞서 Wipi Jlet API 에선 뭐라고 설명하는지 살펴 봅니다.

encodeImage
public byte[] encodeImage(int x, int y, int w, int h)

화면의 특정 영역을 BMP 포맷으로 인코딩한다. 인코딩된 BMP 포맷은 바이트 어레이로 반환되며 파일로 저장하거나 다시 이미지 생성에 이용할 수도 있다.

Parameters:
x - 인코딩할 영역의 시작 x 좌표
y - 인코딩할 영역의 시작 x 좌표
w - 인코딩할 영역의 폭
h - 인코딩할 영역의 폭

Returns:
인코딩된 BMP 포맷의 바이트어레이, 인코딩에 실패하면 null

Throws:
java.lang.IllegalArgumentException - 대상 영역의 일부가 Graphics의 범위를 벗 어나는 경우 또는 w, h가 음수인 경우

출처 : http://www.developerzone.co.kr/release/wipi/SKT_WIPI_JAVA2.0_API/org/kwis/msp/lcdui/Graphics.html#encodeImage(int,%20int,%20int,%20int)

음….. 화면 특정 영역을 BMP포멧으로 인코딩이라고 되있습니다.
여기서 햇갈리는게.. BMP포멧이 뭘까요?
BMP 포멧에 대해선 BMP 구조에 대해 알아야 하는데, 일반적인 BMP는 MS에서 만든 그거겠죠… 라고 생각하다가 조금 고생했습니다..
우선 BMP가 크게 header + (8bit 이하 그림이면) palettle +pixel data 로 구성 되있죠.

처음엔 그냥 BMP 포멧이라 하길래 BGR 값으로 byte 가 쫙~~~~~~~~~ 뽑힐줄 알았는데…
앞에 Header가 있더군요. Orz 일단 Header size 부터 알아냅시다..

System.out.println(src.getWidth()+"x" + src.getHeight() + "Imaghe bytes are " + temp.length);

System.out.println("pixel total number : " + src.getWidth()* src.getHeight());

System.out.println("header size : " + (temp.length - (src.getWidth() * src.getHeight()*3)));

System.out.println();

위 소스를 보면 이미지의 넓이, 높이에 대한 인코딩 추출 byte 길이가 나오고,
실제 이미지에 쓰인 픽셀이 몇 개인지 (해상도라고 하죠 보통..) 출력하고
header 사이즈에 대해 출력됩니다.

저기에 보면 temp 전체 길이에 대해서 픽셀 숫자의 3배수를 뺍니다.
여기서 혼동이 되는게 BMP 포맷은, 1픽셀을 4byte 로 표현합니다, AABBGGRR 로 구성되어있죠
하지만 Wipi 상 BMP 포맷은 RRGGBB 3byte 입니다.

가끔 MSDN 이 좋다고 느껴지는게, 조금 복잡하거나 생소한 API경우 예제 소스를 같이 포함해서 사용법에 대해 나와있는데
Wipi경우 이건 뭐 API만 쑥 던져주고 알아서 삽질하셈 인건지 뭔지… orz

하여간 저렇게 해서 header size를 알아냈으니 그 이후 픽셀부터 수정하면 될까요…?
정답은 꼭 그렇지는 않다 입니다..

허나 대부분은 저렇게 해서 나온 size 에서 + a 지점부터 x,y좌표 계산한 번지의 byte 숫자를 바꾸면 이미지 색이 바뀜니다.
alpha 값은… 저도 많이 삽질했지만 특별한 규칙이 있는건지 없는건지;;;
alpha 값은… header + 특정변수 의 변경값이 0,0의 픽셀을 변하는 곳이.. alpha값입니다.. (이 뭐 무책임한.. orz)
즉, 결론은... 저런거 삽질 할 시간에 차라리 int 같은 배열로 뽑아서 관리 하는게 훨~~~ 씬 편합니다.
int 로 어떻게 뽑냐면..
static int[] CraeteArrayImage(Image srcImg)
 {
      Image copyImg = Image.createImage(srcImg);
      Graphics g = copyImg.getGraphics();
   
      int[] arrayImg = new int[srcImg.getWidth()*srcImg.getHeight()];
 
      int bpp = 32;// getDisplay().getBitsPerPixel();
      int bpl = (srcImg.getWidth() * bpp + 7) / 8;
      g.getRGBPixels(0, 0, srcImg.getWidth(), srcImg.getHeight(), arrayImg, 0, bpl);
      return arrayImg;
 }
이렇게 해주시거나..
아니면...

static int[] CraeteArrayImage(Image srcImg)
 {
      Image copyImg = Image.createImage(srcImg);
      Graphics g = copyImg.getGraphics();
   
      int[] arrayImg = new int[srcImg.getWidth()*srcImg.getHeight()];
      int cnt = 0;
      for(int y=0; y < copyImg.getHeight(); ++y)
      {
           for(int x=0; x < copyImg.getWidth(); ++x)
          {
                 arrayImg[cnt++] = g.getPixel(x, y);
           }
       }
 
       return arrayImg;
 }
물론... int 는 4byte... 그림 RGB만 차지하는 byte는 3byte 이므로 불필요한 공간 25%가 더 쌓이는 코드입니다.
저걸 byte로 바꿔서 코딩하면.. 금방 될껍니다 ^^;

신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

 public static Image CopyImage(Image src)
 {
  // 짐 들어오는 src를 바로  그래픽 받아오게 하면, 읽기 전용상태라 NullPointException이 발생한다
  // 이를 방지하기위해 Image copy본을 만든뒤 그 이미지를 encodeImage 하면된다.
  byte []temp = null;
  Image copy = Image.createImage(src);
  Graphics g = copy.getGraphics();
 
  temp = g.encodeImage(0, 0, src.getWidth(), src.getHeight());
  Image result = Image.createImage(temp, 0, temp.length);
 
  return result;
 }

음.. 하여간 Image copy를 써야 한다는점 체크
참고로. encodeImage 하면, 이미지 전체를 (헤더, 팔레트, 맵 등..)을 가져오는거 같다.
맵만 가져오는줄 알고 작업하다 낭패 봤음.. orz
신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

Tag Java