달달한 스토리

728x90
반응형

 

오랜만에 글을 쓴다.

 

최근 주말 동안 비트코인이라는 신세계에 빠져서

 

안드로이드의 신경을 많이 쓰지 못했다.

 

그래서 그런지 막상 하려니까 머리가 복잡해지고 힘들었지만,

 

금방 다시 집중이 되어서 무사히 이미지 BLOB이란 기술을 오늘 알게 되었다.

 

사실 오늘도 삽질을 오래 하게 되었는데,

 

원래는 저번시간에 phpmyadmin에 디바이스에 사진 경로만 저장해서

 

보는 법을 올렸다.

 

2021.03.10 - [Programing/Android Studio With Java] - 안드로이드 phpmyadmin 연동 / 이미지 경로를 phpmyadmin에 올려보자. / 데이터 베이스 이미지 저장하고 불러오기 TIL # 14

 

안드로이드 phpmyadmin 연동 / 이미지경로를 phpmyadmin에 올려보자. / 데이터 베이스 이미지 저장하고

 뒤늦게 수정합니다 이미지 경로만 저장하여 하나의 디바이스에서만 불러 올 수 있습니다. 이 부분을 저도 착각하여 다음시간에 이미지 저장 후 불러오기 mysql편으로 올리겠습니다 오늘 프로필

daldalhanstory.tistory.com

하지만 이 방법은 해당 디바이스에서만 가능하지...

 

다른 디바이스에 로그인을 하면, 이미지는 없다고 나온다.

 

나는 이러한 문제점을 뒤늦게 발견하고,

 

아 그러면 서버에다가 이미지를 넣고 사용하는 법은 없을까 하고 찾아다녔다.

 

다행히 방법은 있었다.

 

바로 BLOB이란 기술이다.

 

블롭은 Binary Large Object의 약자로서,

 

바이너리의 형태로 큰 객체에 저장을 할 수 있는 기술이라고 할 수 있습니다.

 

여기서 말하는 큰 객체는 주로 비디오, 이미지 등등 멀티미디어를 말씀드릴 수 있습니다.

 

그럼 이 객체에 어떤 형식으로 저장을 할까요.

 

바로, 

 

4GB 이진 데이터로 저장할 수 있다고 합니다.

 

한마디로 이러한 큰 객체, 즉 멀티미디어적인 요소들을 바이너리 형태로 조각조각 나누어서

 

데이터베이스에 저장할 수 있는 방법 중 하나인 것이다.

 

그렇다면 한 번 사용을 해보자.

 


해결법

 

우선 위에 글처럼 같은 json형태로 데이터를 받아올 것이다.

 

 

그 전에 우리가 저번 시간에 배운 이미지에서 예제를 따오겠다.

 

우선 이미지에 인텐트를 보내 그 결과 값으로,

 

onActivityResult로 그 결괏값을 받았었다.

 

참고

 

2021.03.09 - [Programing/Android Studio With Java] - 안드로이드 갤러리에서 이미지 가져오기/ 이미지 회전 방지하기 Glide TIL # 13

 

안드로이드 갤러리에서 이미지 가져오기/ 이미지 회전 방지하기 Glide TIL # 13

프로필을 만드는 중에 갤러리에서 이미지만 가져오려고 여러 기능 들을 찾아보았다. 권한도 주고, 복잡한 기능들이 많았는데, 나는 간단히 갤러리에 사진만 가져올려고 했기 때문에, 이 정도로

daldalhanstory.tistory.com

 @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK) {

                uri = data.getData();
                Glide.with(getContext()).load(uri).into(Profile_Dialog.profileImage); //다이얼로그 이미지사진에 넣기
                Glide.with(getContext()).load(uri).into(userView); //설정시에 바로 프로필 유저뷰에 사진 넣기 (디비에서 온거아님)

                try {
                    ImageDecoder.Source source = ImageDecoder.createSource(getActivity().getContentResolver(), uri);
                    Bitmap bitmap = ImageDecoder.decodeBitmap(source);
                    bitmap = resize(bitmap);
                    String image = bitmapToByteArray(bitmap);
                    changeProfileImageToDB(image); //변경된 프로필 이미지 서버로 보내기

                } catch (Exception e) {

                }


            } else if (resultCode == RESULT_CANCELED) {// 취소시 호출할 행동 쓰기
            }
        }
    }

이런 식으로 말이다.

 

여기서 집중해야 할 것은 바로 이것이다.

 

try {
                    ImageDecoder.Source source = ImageDecoder.createSource(getActivity().getContentResolver(), uri); //소스 만들고,(디코딩)
                    Bitmap bitmap = ImageDecoder.decodeBitmap(source); //비트맵에 넣어준다.
                    bitmap = resize(bitmap); //사이즈 조정
                    String image = bitmapToByteArray(bitmap);
                    changeProfileImageToDB(image); //변경된 프로필 이미지 서버로 보내기

                } catch (Exception e) {

                }

이 try catch문이다.

 

우선 Mediastore.images.media.DATA

 

구문을 이용해서 이미지의 데이터를 받아오려 했지만,

 

API29 이후부터는 위에 구문을 사용할 수 없다고 한다.

 

그래서 스택오버플로우를 참조한 결과,

 

ImageDecoder 이미지를 디코딩(파일을 원래 형태로 되돌리는 일)을 하고

 

소스에 담아,

 

비트맵에 담아 디코딩을 완료하는 것으로 대체하면 된다고 한다.

 

그러고 나서 저 resize가 중요한데,

 

이미지가 바이너리 값을 넘기거나, 사진 크기가 안 맞을 수 있으므로,

 

사진 크기가 기본값을 넘기면,

 

조정해주는 메서드를 따로 만들어 둔 것이다.

 

바로 이 것이다.

 

 

private Bitmap resize(Bitmap bm){
        Configuration config=getResources().getConfiguration();
        if(config.smallestScreenWidthDp>=800)
            bm = Bitmap.createScaledBitmap(bm, 400, 240, true);
        else if(config.smallestScreenWidthDp>=600)
            bm = Bitmap.createScaledBitmap(bm, 300, 180, true);
        else if(config.smallestScreenWidthDp>=400)
            bm = Bitmap.createScaledBitmap(bm, 200, 120, true);
        else if(config.smallestScreenWidthDp>=360)
            bm = Bitmap.createScaledBitmap(bm, 180, 108, true);
        else
            bm = Bitmap.createScaledBitmap(bm, 160, 96, true);
        return bm;
    }

 

이 메서드를 꼭 사용하길 바란다.

 

 

그리고,

 

String image = bitmapToByteArray(bitmap);

 

이 메서드에 비트맵을 담는다.

 

이 비트맵을 서버에 저장하기 위해서는

 

블롭 형식으로 담아야 하는데,

 

블롭 객체에 담으려면,

 

보통 Drawable을 Bitmap으로 바꾸고,

 

Bitmap을 byte []으로 바꾸고,

 

그 byte []를 스트링으로 변환하는 과정을 거쳐서,

 

스트링으로 만들어야 비로소 이진 데이터로 데이터베이스에 저장을 할 수가 있게 된다.

 

그래서 준비했다.

 

저 과정을 순차적으로 해결하게 해주는 메서드이다.

 

/**비트맵을 바이너리 바이트배열로 바꾸어주는 메서드 */
    public String bitmapToByteArray(Bitmap bitmap) {
        String image = "";
        ByteArrayOutputStream stream = new ByteArrayOutputStream() ;
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream) ;
        byte[] byteArray = stream.toByteArray() ;
        image = "&image=" + byteArrayToBinaryString(byteArray);
        return image;
    }

    /**바이너리 바이트 배열을 스트링으로 바꾸어주는 메서드 */
    public static String byteArrayToBinaryString(byte[] b) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < b.length; ++i) {
            sb.append(byteToBinaryString(b[i]));
        }
        return sb.toString();
    }

    /**바이너리 바이트를 스트링으로 바꾸어주는 메서드 */
    public static String byteToBinaryString(byte n) {
        StringBuilder sb = new StringBuilder("00000000");
        for (int bit = 0; bit < 8; bit++) {
            if (((n >> bit) & 1) > 0) {
                sb.setCharAt(7 - bit, '1');
            }
        }
        return sb.toString();
    }

String image = bitmapToByteArray(bitmap);

 

이 메서드에 비트맵 하나만 넣어도,

 

저 위에 과정을 

 

전부 간단히 완료시켜준다.

 

이 과정을 모두 마치면,

 

String image에 담기게 되고,

 

db로 image 스트링을 보내게 된다.

 

private void changeProfileImageToDB(String image) {


        Response.Listener<String> responseListener = new Response.Listener<String>() { //여기서 여기서 Quest1에서 썼던 데이터를 다가져온다.

            @Override
            public void onResponse(String response) {
                try {
                    JSONObject jsonObject = new JSONObject(response);
                    boolean success = jsonObject.getBoolean("success");

                } catch (JSONException e) {
                    e.printStackTrace();
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        Profile_Img_Check profile_img_check = new Profile_Img_Check(id, image, responseListener);
        RequestQueue queue = Volley.newRequestQueue(getContext());
        queue.add(profile_img_check);

        Log.d("비트맵", String.valueOf(uri));
    }

아래 파라미터로 들어간 아이디 값은 어떤 아이디인지

 

판별하기 위해 넣어둔 것이므로,

 

착오가 없길 바란다.

 

public class Profile_Img_Check extends StringRequest  {



    //서버 url 설정(php파일 연동)
    final static  private String URL="서버이름/profileimg.php";
    private Map<String,String> map;

    public Profile_Img_Check(String id, String profileimg, Response.Listener<String>listener){
        super(Method.POST,URL,listener,null);

        map=new HashMap<>();
        map.put("id", id);
        map.put("profileimg", profileimg);
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return map;
    }
}

 

요청 코드를 입력한 클래스이다. 이전 시간에도 많이 써본 코드이다.

 

많이 쓰는 나의 최애 볼리 라이브러리다.(사실 아직 이거밖에 쓸 줄 몰라 잘 활용 중이다)

 

이어서 php코드이다.

 

<?php 
    $con = mysqli_connect("서버아이피", "아이디", "비번", "데이터베이스");
    mysqli_query($con,'SET NAMES utf8');

	$id = $_POST["id"];
    $profileimg = $_POST["profileimg"];
    

    mysqli_query($con, "UPDATE USER SET profileimg = '$profileimg' WHERE id = '$id'");
    
    $response = array();
    $response["success"] = true;
 
    echo json_encode($response);
?>

나 같은 경우는 아이디 값을 통해 사용자를 식별하고,

 

이미지를 업데이트할 수 있는 php코드를 사용하였다.

 

아 그리고 sql문도 정리해보았다.

 

CREATE TABLE `USER` (
`id` VARCHAR(20) NOT NULL,
`profileimg` longblob);

이런 식으로 longblob 형태로 삽입한다.

 

blob의 여러 가지 형태가 있지만,

 

아직 나는 그 부분에 대해 무지하므로,

 

더 깊게 포스팅하지는 않겠다.

 

이렇게 하게 되면 

 

 

데이터베이스에 이런 식으로 블롭 형태로 저장되는 것을 볼 수 있다.

 

친절하게 크기도 쓰여있다.

 

또 클릭을 하면 다운로드를 하여서

 

이 이미지 파일을 볼 수 있는 듯한데,

 

PDF로 변환해서 볼 수 있다고는 하는데,

 

아직 내가 그 부분은 하지 못해서...

 

직접 해보시길 바란다(필요하지 않으면 배우려 하지 않는 타입).

 

아무튼 도움이 됐길 바라며,

 

다음 시간은 이 데이터를 받아오는 방법을 알아보고자 한다.

 

나도 아직 안 해봐서 내일 해봐야겠다.

 

오늘도 이렇게 삽질에 흔적을 남기게 되었다.

 

내일도 열심히 삽질을 해보자.

 

파이팅!

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading