안드로이드에서 서버로 이미지 전송하기

이정현·2021년 5월 15일
7

개발하고자 하는 것🐳


사용자가 안드로이드 앱에서 앨범의 이미지를 선택하면 서버로 선택한 이미지를 전송하여 서버측 폴더에 저장한다.
안드로이드 스튜디오에서 이미지를 Base64 형식으로 인코딩한 문자열을 서버측에 전달하고, 서버는 문자열을 디코딩하여 이미지를 얻도록 한다.
서버는 GoormIDE에서 구현하고, 언어는 Node.js를 사용한다.


Android Studio🐋

아래는 앨범에서 이미지를 선택하고 Base64 형식으로 인코딩하는 코드이다.
이 기능과 관련 없는 기타 코드는 생략하고 올린다.

class FindActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layout.fragment_find)
        val imageBtn: Button = findViewById(id.btn_UploadPicture)

        imageBtn.setOnClickListener {
            openGallery()
        }
}

imageBtn을 클릭하면 openGalley() 함수가 호출되며 앱에서 앨범이 실행된다.

private fun openGallery(){
        val intent = Intent(Intent.ACTION_PICK)

        intent.type = MediaStore.Images.Media.CONTENT_TYPE
        intent.type = "image/*"
        startActivityForResult(intent, 102)
    }
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        super.onActivityResult(requestCode, resultCode, intent)

        if (requestCode == 102 && resultCode == Activity.RESULT_OK){
            currentImageURL = intent?.data
            // Base64 인코딩부분
            val ins: InputStream? = currentImageURL?.let {
                applicationContext.contentResolver.openInputStream(
                    it
                )
            }
            val img: Bitmap = BitmapFactory.decodeStream(ins)
            ins?.close()
            val resized = Bitmap.createScaledBitmap(img, 256, 256, true)
            val byteArrayOutputStream = ByteArrayOutputStream()
            resized.compress(Bitmap.CompressFormat.JPEG, 60, byteArrayOutputStream)
            val byteArray: ByteArray = byteArrayOutputStream.toByteArray()
            val outStream = ByteArrayOutputStream()
            val res: Resources = resources
            profileImageBase64 = Base64.encodeToString(byteArray, NO_WRAP)
            // 여기까지 인코딩 끝

            // 이미지 뷰에 선택한 이미지 출력
            val imageview: ImageView = findViewById(id.pet_image)
            imageview.setImageURI(currentImageURL)
            try {
                //이미지 선택 후 처리
            }catch (e: Exception){
                e.printStackTrace()
            }
        } else{
            Log.d("ActivityResult", "something wrong")
        }
    }

onActivityResult에서 앨범에서 선택한 이미지의 Uri를 사용하여 비트맵 이미지를 생성한 후, 이를 Base64 형식으로 인코딩을 진행한다. 이 과정은 onActivityResult 내의 //Base64 인코딩 부분 ~ // 여기까지 인코딩 끝 주석 사이의 코드를 통해 진행된다.
Base64로 인코딩 한 문자열을 Json형태로 서버로 넘기는 경우, 용량이 크게 늘어나 전송이 되기 때문에 서버측에선 이를 디코딩하기가 힘들다는 문제가 발생한다.
하지만 현재 개발하고자 하는 프로그램에서는 원본 이미지의 크기와 품질이 크게 중요한 요소가 아니었기 때문에 Bitmap.createScaledBitmap(img, 256, 256, true) 를 통해 이미지 크기를 256x256으로 리사이징 시키고 resized.compress(Bitmap.CompressFormat.JPEG, 60, byteArrayOutputStream) 을 통해 이미지의 품질을 60으로 설정하였다.
이렇게 생성한 Base64 인코딩 문자열은 뷰모델을 사용하여 서버로 전송하였다.


Node.js🐟

app.post('/search', (req, res) => {
   var paramDecoded;
	var inputData;
   req.on('data', (data) => {
	   paramDecoded = decodeURIComponent(data);
   });

   req.on('end', () => {
	var bufwrite = paramDecoded.split('=')[1];
	var buf = Buffer.from(bufwrite,'base64');
  	fs.writeFileSync("/workspace/Potato_Pizza/dalbok/capture_images/capture_img.jpg", buf);  
	console.log('******** base64로 인코딩되었던 파일 쓰기 성공 ********');
   });

서버는 앱으로부터 "img=base64 형식으로 인코딩된 문자열" 의 메시지를 전달 받는다. split('=')를 사용하여 img, base64 형식으로 인코딩된 문자열로 요소를 나눈다. 이 중 필요한 데이터는 base64 형식으로 인코딩된 문자열 이기 때문에 split('=')[1]의 데이터를 받아온다.
문자열을 base64로 디코딩한 후, 폴더에 저장하는 코드는 아래 두 줄이다.

var buf = Buffer.from(bufwrite,'base64');
fs.writeFileSync("폴더 경로/이미지이름.jpg", buf);

결과🐬


안드로이드 어플에서 사진을 첨부하고 검색 버튼을 클릭하면 이미지가 서버에 전송된다.
지역, 상세지역, 동물의 종류 정보 역시 문자열 형태로 이미지와 함께 서버로 전송하였다.

앱으로부터 받은 이미지를 서버의 폴더에 저장한 후, 이를 출력한 결과 사진이 잘 저장됨을 확인할 수 있다.

profile
개발자 꿈나무

1개의 댓글

comment-user-thumbnail
2022년 5월 16일

안녕하세요! 쓰신 포스팅을 보고 같은 방식으로 시도해 보려고 하는데 검색 버튼을 눌렀을 때 서버로 보내는 버튼의 OnclickListener의 작동방식이 궁금합니다 혹시 답변해 주실 수 있을까요?

답글 달기