블로그 이미지
매몰

모바일 어플리케이션 개발 1인 기업 고영진모바일입니다. 저와 함께 맛깔스러운 앱을 만들어 보아요~

Rss feed Tistory
개발/android 2015.11.30 10:10

Bitmap 이미지를 byte로 바로 보낸다고? 그것도 소켓으로?



군대를 막 전역했을때 다시 완벽한 민간인이 되기 위해 책한권을 샀었다

바로 "TCP/IP 소켓 프로그래밍" 이었다


이때 처음 접한 네크워크 코딩술로

간단한 원도우용 채팅프로그램을 만들었고 

졸업후에는 PC와 스마트폰간의 연결앱인 "키보드에디터"를 출시하였다. 물론 쫄닥 망했다ㅎㅎ


어쨌든 그후에도 가끔씩 소켓기반의 앱을 만들면서 자연스럽게 이미지 전송도 하게되었다

여기서는 비트맵이미지를 파일형태가 아닌 Byte단위의 원본으로 바로 보내는 것을 다뤄보겠다.


파일도 결국은 Byte로 보내는것이지만... 

외부파일이 아닌 내부이미지를 불러와 바로 전송할때 유용할것이다~





-서버

public class Server implements Runnable {

@Override
public void run() {
try {
ServerSocket socket = new ServerSocket(9999);

while(true) {
Socket clientsoket = socket.accept();

//클라이언트로 보낼 출력스트림을 얻는다
DataOutputStream os = new DataOutputStream(clientsoket.getOutputStream());

//이미지를 불려온다
byte[] data = getImageByte(BitmapFactory.decodeResource(getResources(), R.drawable.image));

//비트맵이미지의 총크기를 4byte배열에 담아서 먼저 보낸다 (이때 꼭 4byte일 필요는 없다. 마음내키는대로~)
//총크기를 보내는 이유는 비트맵이미지가 전부 전송된 시점을 클라이언트에 알리기 위함이다
byte[] size = getByte(data.length);
os.write(size, 0, size.length);
os.flush();

//실제 데이터를 보낸다
os.write(data, 0, data.length);
os.flush();
}

socket.close();

} catch (IOException e) {
e.printStackTrace();

}
}
}

//비트맵의 byte배열을 얻는다
public byte[] getImageByte(Bitmap bitmap) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);

return out.toByteArray();
}
//숫자를 byte형태로 바꾼다
private byte[] getByte(int num) {
byte[] buf = new byte[4];
buf[0] = (byte)( (num >>> 24) & 0xFF );
buf[1] = (byte)( (num >>> 16) & 0xFF );
buf[2] = (byte)( (num >>> 8) & 0xFF );
buf[3] = (byte)( (num >>> 0) & 0xFF );

return buf;
}





-클라이언트

public class Client implements Runnable {

@Override
public void run() {
try {
Socket socket = new Socket("IP주소", 9999);

BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());

while(mRun) {
byte[] imagebuffer = null;
int size = 0;

byte[] buffer = new byte[10240];

int read;
while((read = bis.read(buffer)) != -1 && mRun) {
if (imagebuffer == null) {
//처음 4byte에서 비트맵이미지의 총크기를 추출해 따로 저장한다
byte[] sizebuffer = new byte[4];
System.arraycopy(buffer, 0, sizebuffer, 0, sizebuffer.length);
size = getInt(sizebuffer);
read -= sizebuffer.length;

//나머지는 이미지버퍼 배열에 저장한다
imagebuffer = new byte[read];
System.arraycopy(buffer, sizebuffer.length, imagebuffer, 0, read);
}
else {
//이미지버퍼 배열에 계속 이어서 저장한다
byte[] preimagebuffer = imagebuffer.clone();
imagebuffer = new byte[read + preimagebuffer.length];
System.arraycopy(preimagebuffer, 0, imagebuffer, 0, preimagebuffer.length);

System.arraycopy(buffer, 0, imagebuffer, imagebuffer.length - read, read);
}

//이미지버퍼 배열에 총크기만큼 다 받아졌다면 이미지를 저장하고 끝낸다
if(imagebuffer.length >= size) {
Bundle bundle = new Bundle();
bundle.putByteArray("Data", imagebuffer);

Message msg = mResultHandler.obtainMessage();
msg.setData(bundle);
mResultHandler.sendMessage(msg);

imagebuffer = null;
size = 0;
}

}
}

socket.close();
bis.close();

} catch (IOException e) {
e.printStackTrace();
}
}
}

//byte배열을 숫자로 바꾼다
private int getInt(byte[] data) {
int s1 = data[0] & 0xFF;
int s2 = data[1] & 0xFF;
int s3 = data[2] & 0xFF;
int s4 = data[3] & 0xFF;

return ((s1 << 24) + (s2 << 16) + (s3 << 8) + (s4 << 0));
}
//이미지뷰에 비트맵을 넣는다
public Handler mResultHandler = new Handler() {
public void handleMessage(Message msg) {
byte[] data = msg.getData().getByteArray("Data");

((ImageView) findViewById(R.id.ImageView)).setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
}
};



참고로~

언급했듯이 전송형태에 있어서

위 방법말고도 불러온 이미지를 파일로 만들어 보내는 형태도 있고,


이미지버퍼 배열을 데이터에 담는 방식에 있어서도

미리 받은 총크기로 배열을 생성한 뒤 계속 이어서 받는 방식도 있다


편한데로 응용해서 쓰시길 바란다



 

 



수제 앱 장인: 고영진


(주)고영진모바일

1인기업 대표이사 겸 개발자

  

     실패만 하고 있어도 꿈을 포기하지 않는 남자 

     제가 직접 경험하고 습득한 지식을 위주로 올릴게요

 





사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
  • yyoo 2017.05.25 16:41 신고 ADDR 수정/삭제 답글

    클라이언트의 mRun이 선언이 안되어있는데,
    어떤 변수인가요?ㅠㅠ

    • 대세를 따르지 않고 대세를 만드는 매몰 2017.05.29 12:39 신고 수정/삭제

      mRun 을 깜박했네요ㅎㅎ
      mRun은 만약에 있을 무한루프를 방지하기 위해서 넣은거에요
      그냥 빼셔도 되요

      만약 넣는다면
      Activity에 mRun을 전역변수로 추가하시고
      onCreate() 에 mRun = true
      onDestroy() 에 mRun = false
      를 해주시면 됩니다~

TOTAL 69,581 TODAY 10