본문 바로가기
Study/Android

Android에서 image BLOB MySQL에 저장하기

by Answer Choi 2017. 7. 26.
반응형

Android 소스


PHP 소스


MySQL DB 구조





원리



Android에서 image파일을 MySQL에 BLOB로 저장하기 위해서는 몇가지 과정을 거쳐야 합니다.



안드로이드 


카메라든 갤러리에서 가져온 Image을 압축하여


byte array 형태로 변환합니다.


그리고 변환된 데이터를 Base64로 string 형태로 인코딩합니다.


그리고 이 인코딩 된 데이터를 보내야하는데 중간에 공백이 있어 HTTP GET방식으로 


보낼 수 없습니다.


그래서 다시한번 UTF-8로 인코딩합니다.


PHP


받은 데이터를 base64로 디코딩합니다.


디코딩 된 데이터는 이진수이고 곳곳에 특수문자도 있어 escape합니다.


이제 최종 데이터를 mysql에 insert해주면 됩니다.


PHP에서도 주의할 점은 Apache 서버에서 get방식으로 url을 받을 수 있는 길이가 


제한되어 있어 수정해 줘야 합니다.


REQUEST-URI TOO LONG(LARGE) 에러


위 포스트를 참고해 주세요









주요 코드


image를 인코딩 하는 코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void BitMapToString(Bitmap bitmap){
    ByteArrayOutputStream baos=new  ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG,100, baos);    //bitmap compress
    byte [] arr=baos.toByteArray();
    String image= Base64.encodeToString(arr, Base64.DEFAULT);
    String temp="";
    try{
        temp="&imagedevice="+ URLEncoder.encode(image,"utf-8");
    }catch (Exception e){
        Log.e("exception",e.toString());
    }
    controlMysql addinfo=new controlMysql(temp);
    controlMysql.active=true;
    addinfo.start();
}
cs


Line 2~4 : image를 byte array에 넣는 코드입니다.


Line 5 : byte array를 base 64로 인코딩하는 코드입니다.


Line 6~11 : 인코딩된 데이터를 UTF-8로 한번더 인코딩하는 코드입니다.


Line 12~14 : 스레드를 통해 PHP로 보내는 코드입니다.



카메라나 갤러리 불러오는 코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void onClick(View v) {
    Intent intent=new Intent();
    switch(v.getId()){
    case R.id.cameraBtn:
        intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, camera);
        break;
    case R.id.galleryBtn:
        intent.setAction(Intent.ACTION_GET_CONTENT);
        intent.setType("image/-");
        startActivityForResult(intent, gallery);
        break;
    case R.id.CloseBtn:
        setResult(RESULT_CANCELED, intent);
        Toast.makeText(getApplicationContext(), "설정을 유지합니다.", Toast.LENGTH_SHORT).show();
        finish();
        break;
    default:
        break;
    }
}
cs


Line 4~7 : 카메라를 실행하는 코드입니다.


Line 8~12 : 갤러리를 실행하는 코드입니다.


위 인텐트들은 startActivityForResult로 실행했으므로 onActivityResult가 호출됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Intent intent=new Intent();
    Bitmap bm;
    if(resultCode==RESULT_OK){
        switch(requestCode){
        case camera:
            try {
                bm= Images.Media.getBitmap(getContentResolver(), data.getData());
                bm=resize(bm);
                intent.putExtra("bitmap",bm);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            setResult(RESULT_OK, intent);
            finish();
            break;
        case gallery:
            try {
                bm = Images.Media.getBitmap( getContentResolver(), data.getData());
                bm=resize(bm);
                intent.putExtra("bitmap",bm);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }catch(OutOfMemoryError e){
                Toast.makeText(getApplicationContext(), "이미지 용량이 너무 큽니다.", Toast.LENGTH_SHORT).show();
            }
            setResult(RESULT_OK, intent);
            finish();
            break;
        default:
            setResult(RESULT_CANCELED, intent);
            finish();
            break;
        }
    }else{
        setResult(RESULT_CANCELED, intent);
        finish();
    }
}
cs


카메라나 갤러리에서 정상적으로 작업을 수행하고나면 Line 5로 들어옵니다.


Line 7~19 : 카메라에서 호출한 코드입니다.


Line 20~36 : 갤러리에서 호출한 코드입니다.


각각의 코드에서 받아온 이미지를 메인의 이미지뷰에 띄우기 위에 인텐테 넣는데 


그전에 이미지를 리사이징해야합니다.(너무 크면 오류가 납니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Bitmap resize(Bitmap bm){
    Configuration config=getResources().getConfiguration();
    if(config.smallestScreenWidthDp>=800)
        bm = Bitmap.createScaledBitmap(bm, 400240true);
    else if(config.smallestScreenWidthDp>=600)
        bm = Bitmap.createScaledBitmap(bm, 300180true);
    else if(config.smallestScreenWidthDp>=400)
        bm = Bitmap.createScaledBitmap(bm, 200120true);
    else if(config.smallestScreenWidthDp>=360)
        bm = Bitmap.createScaledBitmap(bm, 180108true);
    else 
        bm = Bitmap.createScaledBitmap(bm, 16096true);
    return bm;
}
cs


이미지 리사이징 크기는 상황에 맞게 수정하시면됩니다.


우선은 디스플레이 사이즈에 맡게 수정되도록 만든 코드입니다.





동작화면



앱을 실행한 화면입니다.


사진 가져오기를 클릭합니다.



사진을 촬영하거나 갤러리에서 사진을 가져옵니다.



사진을 가져온 모습입니다.


사진 저장하기를 클릭합니다.



MySQL에 가보시면 업로드 된 사진을 확인할 수 있습니다.



PS web브라우저에서는 되는데 android에서는 안되는경우


제가 확인해 본 봐로는 bitnami에서 구현한 웹서버에서 잘 안되는 것 같습니다.


리눅스로 만든 서버에서 테스트를 해서 잘 몰랐는데, 윈도PC에 bitnami를 설치하고 해보니 


안되네요.


다른예제(login) 같은경우는 잘 되는데, 이 예제만 안되어 방법을 찾고있습니다.


이미지 용량에 따라 되는 파일도 있고 안되는 파일도 있는것 같습니다.


bitnami에 파일 제한이 있는지는 모르겠습니다.


PS 안드로이드 소스코드 업로드 


안드로이드 소스코드 좀 수정해서 다시 올렸습니다.


제가보기에도 버튼 눌렀을때 헤깔릴만한 부분들이 있어서...


12/4 카메라 권한요청부분 수정하였습니다.


반응형

인기글