본문 바로가기
JAVASCRIPT/NodeJS

[NodeJS] Jimp 이용하여 비트맵 조작하기(c++ binary 통신)

by 원동호 2021. 1. 15.
반응형

자사 프로젝트로 스마트워치를 개발하고 있는데 워치 LED에 TCP서버측에서 bmp 파일을 읽어

binary로 전송 해야 하는 일이 생겨버렸다..

 

먼저 TCP 서버를 구축해야 했고 급했던 나머지 제일 빨리 구축할 수 있을것 같은 Node.js를 선택해

진행중이다. 늘 순차실행인 코드만 작성하다 Nodejs의 콜백이 나를 너무나 괴롭혔다... 분명 값이 나와야 할것 같으면

undefined.... undefined.... 그렇게 개념좀 익히면서 하나하나 디버그 돌려가면서 얼추 모든 기능은 완성된 상태이고,

정리만 남았다!

 

제일 나를 괴롭혔던 bmp조작... 다른 사람들이 보면 정말 못 짠 코드라고 생각하겠지만 워치 LED에

내가 전송한 이미지가 뜨는 순간을 정말 가슴 벅찼다!

 

바로 시작해보겠다.

 

전송하기 위한 선행조건이 몇가지 필요하다.

Q1 C++로 작성된 펌웨어에 최대 1kb(1024Byte) 바이너리 데이터를 전송해야 한다.(bmp 이미지를 읽어서)  
Q2 1bit color 이미지 여야 한다. ( 흑색 : 1, 백색 : 0 ) -> LED에서는 1의 데이터만 표시되고 0은 표시하지 않는다.
Q3 LED에 표시될 bmp 이미지의 픽셀별(X축,Y축) alpha 값을 읽어 0또는 1로 변환 해야한다.
(bmp 이미지가 1bit이미지가 아닐수도 있기 때문에 추가로 변환이 필요했음.)
Q4 bmp 이미지의 ( 0,0 ) ~ (127, 63)에 해당하는 좌표값의 픽셀을 읽어야 한다.  
Q5 세로로 8비트씩 읽어 1byte데이터로 변환해야 한다. ex) (0,0) ~(0,7) = 1byte , (1,0) ~ (1,7) = 1byte ......
각 픽셀 값 읽은 것을 8비트씩 합쳐서(단, hex로 변경 시에는 합친 데이터를 거꾸로 읽어야 한다.) hex데이터로 변환 해야 한다.

 

 

먼저 128 * 64 bmp 이미지를 준비했다. 128*64 비트맵은 비트로 표현하면 8192bit이지만

이걸 8비트씩 읽어서 1024byte(1K)로 만들어야 했다.

 

아래처럼 X축 0~127 , Y축 0~7 값을 다 읽고 난 후, X축 : 0~127 , Y축 8~15 ..... X축 : 0~127 , Y축 56~63 까지 읽도록 

반복 하게 작성 해야 했다.

 

 

 

바로 전 포스팅했던 Jimp 라이브러리를 이용해 이미지를 읽어 데이터를 처리했다.

 

    Jimp.read('test.bmp')
    .then(image=>{
      //초기번호, y축 픽셀 몇번째부터 읽을건지
      let INIT_NUM,PIXEL_CNT = 0;
      //8번씩 몇번 순회해야 하는지(세로가 64 이므로 8번 순회 해야한다.)
      let TOTAL_NUM = image.bitmap.height / 8; 
      let IMG_WIDTH = image.bitmap.width;    
      //읽어야 할 픽셀 값
      let PIXEL_HEIGHT=8;
      //아래 배열에 각 x,y축을 읽은 값을 차곡차곡쌓는다.
      let pixelArr= [];
      //총 8번 순회한다.
      for(INIT_NUM=0; INIT_NUM<TOTAL_NUM; INIT_NUM++){
        //0부터 127(가로길이)까지 반복한다.
        for(let x=0; x<IMG_WIDTH; x++){
          for(let y = PIXEL_CNT; y<PIXEL_HEIGHT; y++){
            let color = image.getPixelColor(x, y);
            // var r = (color >> 24) & 255; 
            // var g = (color >> 16) & 255; 
            // var b = (color >> 8) & 255; 
            let a = (color >> 0) & 255; 
            // console.log(`${x},${y}rgb : ${r}${g}${b}${a}`)
            //백색
            if(a!=0)pixelArr.push(1);
            
            //흑색
            else pixelArr.push(0);
          }
        }
        //한번 순회할때마다 현재위치한 픽셀값 +8, 총 읽어야할 픽셀값 +8을 해준다.
        PIXEL_CNT+=8;
        PIXEL_HEIGHT+=8;
      }
      //division함수는 총 배열을읽어 8개씩 합친 배열을 만든다.
      //각 픽셀값을 읽은 배열에 8개씩 묶어 새로운 배열을 만든다.
      let pixelJoinArr= pixelArr.division(8)

      //bbb는 aaa의 각 배열을 순회하여 n번째 배열안의 각 값들을 붙이고 reverse한 값을 int로 만든후 16진수 값으로 다시 변경한다.
      let pixelHexArr = pixelJoinArr.map(function(e){
        let test = parseInt(e.join("").split("").reverse().join(""),2).toString(16)
        if(test < 10) test ='0'+test;
        else test = test.toUpperCase()
        test='0x'+test
        return test;
      });
      return pixelHexArr;
    })
    .catch(err=>{
      console.log(err);
    })
    
    
         Array.prototype.division = function (n){
         let arr = this;
         let len = arr.length;
         let cnt = Math.floor(len / n) + (Math.floor(len % n) > 0 ? 1 : 0);
         let tmp = [];
      
         for (let i = 0; i < cnt; i++) {
             tmp.push(arr.splice(0, n));
         }
      
         return tmp;
       }

 

사실 TCP 서버를 C 로 작성하는게 Bitmap 조작도 쉽고 바이너리 데이터조작, 구조체 등등 좀더 편할 수 도 있겠지만,

웹 언어가 익숙하고 Node.js로 뭔가를 만들어 보고 싶기도 했어서 구축했지만 아직도 노드는 정말 싱숭생숭 한 언어인것같다. 코드가 정말 두서없고 정말 되게만 만든것 같기도 하지만 잘 작동하고 있고 계속 테스트해보면서 손볼 예정이다.

 

나와 같은 고민을 할 사람은 없을것 같지만 이걸 구현하면서 정말 힘들었고,

완성했을땐 너무 뿌듯해서 포스팅 하게되었다. 화이팅해야징

 

 

도움이 되셨다면 하트 및 댓글 부탁드립니다♥

 

반응형

댓글