[Android / Glide] 이미지 URL을 읽어 JPG 포맷파일로 변환하기

1. remote url의 이미지를 비트맵 형식으로 가져온다.

1
2
3
4
5
6
7
fun loadBitmapImage(context: Context, url: String?, listener: RequestListener<Bitmap?>?) {
GlideApp.with(context)
.asBitmap()
.load(url)
.listener(listener)
.preload() //submit()으로 하면 Activity destroy 시점에서 오류
}

Glide를 사용해 listener를 통해 onResourceReady에서 비트맵 리소스를 받아 처리한다.

Glide를 쓰지 않고 가령, 갤러리에 저장된 이미지를 가져와 3번으로 넘어갈 경우, imageView에 비트맵을 저장하게 되는데, 이때 Bitmap의 recycle state를 관리해줘야할 수 있다. (참고: Glide에서 비트맵 이미지가 GC되는 과정)
이런 이유로 Android Developer 공식 문서에서는 대부분의 경우 Glide 라이브러리를 사용하여 앱에서 비트맵을 가져오고 디코딩하고 표시하는 것을 추천한다고 나와있다.

2. 비트맵을 JPG 포맷으로 압축, 저장한다.

이제 받아온 비트맵을 remoteTemp.jpg 라는 이름의 파일에 JPG 포맷으로 저장할 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mRemoteImageUri = Uri.fromFile(getReviewTempImageFile(context
, "remoteTemp.jpg"));
File bitmapFile = new File(mRemoteImageUri.getPath());

try {
FileOutputStream outputStream = new FileOutputStream(bitmapFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);

outputStream.flush();
outputStream.close();

setPickedImage(mRemoteImageUri);
} catch (Exception e) {
e.printStackTrace();
}

먼저 저장할 파일의 Uri를 만들었다. Uri를 생성하는 이유는 3번에서 파일의 사이즈를 얻어오기 위함이다. 자세히는 해당 번호 참조.

compress의 두 번째 인자값은 CompressFormat에 대한 압축률이며 0(minimum) ~ 100(maximum)으로 설정할 수 있다.

bitmap.compress(CompressFormat.PNG, 0, filestream)
위와 같이 PNG로 압축하여 출력할 경우 두 번째 인자값은 무시한다. PNG 파일의 특성이 손실률 없는 포맷에 해당하기 때문이다.

위의 코드에서는 FileOutputStream 객체를 사용하여 JPG로 압축한 비트맵이 파일에 저장되었으나 이를 파일로 저장하지 않고 처리하려면 ByteArrayOutputStream를 사용할 수 있다.

  • 코드 세부사항 파일에 저장하는 코드 상에서 사용한 getReviewTempImageFile 메소드는 아래와 같다. 여기서 ‣ 주의할 것.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public static File getReviewTempImageFile(Context context, String imageName) {
    String imgDirName = "/TestDir";
    String dirPath = context.getExternalFilesDir(null) + imgDirName;
    File saveDir = new File(dirPath);
    if (!saveDir.exists()) {
    saveDir.mkdir();
    }

    String nomediaFilePath = dirPath + "/.nomedia";
    File nomediaFile = new File(nomediaFilePath);
    if (!nomediaFile.exists()) {
    try {
    nomediaFile.createNewFile();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    String filePath = dirPath + "/" + imageName;
    return new File(filePath);
    }
    getExternalFilesDir()을 사용하기 때문에 미리 WRITE_EXTERNAL_STORAGE 퍼미션 처리를 해주어야 한다. crop을 수행하는 Activity에 진입하기 전에 체크해주는 게 가장 좋다. 해당 퍼미션을 체크하는 코드는 다음과 같다.
    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
    private void doImageSearch() {
        if (permissionCheck(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // start CropActivity
    } else {
    mRequestPermission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
    requestPermission(this, PermissionConstants.REQUEST_STORAGE_CODE, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    }

    public static boolean permissionCheck(Context context, String permission) {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M
            || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
            && ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
    }

    public static void requestPermission(Context context, int requestCode, String permission) {
        //shouldShowRequestPermissionRationale - 사용자가 권한 요청을 한번 거절 했을 경우 True
        if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission)) {
            try {
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
    .setData(Uri.parse("package:" + context.getPackageName()));
    ((Activity) context).startActivityForResult(intent, PermissionConstants.REQ_CODE_REQUEST_SETTING);
    } catch (ActivityNotFoundException e) {}
        } else {
           // 처음 권한 요청 및 다시 보지 않기를 선택하였을 경우 false
            ActivityCompat.requestPermissions((Activity) context, new String[]{permission}, requestCode);
        }
    }

3. 이미지 파일을 적절한 사이즈로 변경하여 재저장

crop을 준비하기 위해서는 디바이스의 한 화면에 적절한 크기로 이미지를 노출해야한다. 위의 코드에서 setPickedImage 메소드가 이 기능을 담당한다.

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
47
48
49
private void setPickedImage(@Nullable Uri rawBitmap) {
    mImageCaptureUri = Uri.fromFile(getReviewTempImageFile(context, "originTemp.jpg"));
    File bitmapFile = new File(mImageCaptureUri.getPath());
    try {
        Uri bitmapUri = mImageCaptureUri;
        if(rawBitmap != null)
            bitmapUri = rawBitmap;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = calculateBitmapSampleSize(this, bitmapUri);
        options.inJustDecodeBounds = false;

        InputStream is = getContentResolver().openInputStream(bitmapUri);
        Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);

        if (bitmap == null) return;

        String uriPath = getRealPathFromURI(context, bitmapUri);
        if(TextUtils.isEmpty(uriPath))
            uriPath = bitmapUri.getPath();
        ExifInterface exif = new ExifInterface(uriPath);

        int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        int exifDegree = exifOrientationToDegrees(exifOrientation);
        bitmap = rotate(bitmap, exifDegree);
        FileOutputStream outputStream = new FileOutputStream(bitmapFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);

        outputStream.flush();
        outputStream.close();

        startCrop(bitmap);
    } catch (Exception e) {
        e.printStackTrace();
        finish();
    }
}

@Override
public void finish() {
    if(mImageCaptureUri != null)
        deleteTempImageFile(mImageCaptureUri);
    if(mRemoteImageUri != null)
        deleteTempImageFile(mRemoteImageUri);
    mCropImage.setImageBitmap(null); // clear bitmap in imageView

    super.finish();
    overridePendingTransition(0,0);
}

[Android / Glide] 이미지 URL을 읽어 JPG 포맷파일로 변환하기

https://dl137584.github.io/2022/02/05/011-convert-remote-url-to-jpg-file/

Author

LEEJS

Posted on

2022-02-05

Updated on

2022-02-16

Licensed under

댓글