burhanrashid52 / PhotoEditor

A Photo Editor library with simple, easy support for image editing using paints,text,filters,emoji and Sticker like stories.
MIT License
4.12k stars 989 forks source link

Filters are not working when I use ActivityResultLauncher #419

Closed Yumin2019 closed 2 years ago

Yumin2019 commented 2 years ago

I'm using PhotoEditor library. I've been really thankful for your PhotoEditor personally. but while I'm using it, I got an error when I use registerForActivityResult functions

In your project, you're using startActivityForResult functions. when I used them, I didn't get this issue. but registerForActivityResult are different.

    // registerForActivityResult
    protected lateinit var cameraLauncher: ActivityResultLauncher<Uri>
    protected lateinit var galleryLauncher: ActivityResultLauncher<String>

in EditProfileFragment


    fun cameraButton()
    {
        if(CB_SingleSystemMgr.isDialog(CB_SingleSystemMgr.DIALOG_TYPE.ITEM_LIST_DIALOG))
            return

        val listItem = arrayListOf(
            DialogItem(getString(R.string.str_camera), R.drawable.camera,
                callback =
                {
                    Log.i(strTag, "camera")
                    cameraLauncher.launch(imageUri)
                }),
            DialogItem(getString(R.string.str_gallery), R.drawable.image,
                callback =
                {
                    Log.i(strTag, "gallery")
                    galleryLauncher.launch("image/*")
                })
        )

        CB_ItemListDialog(requireActivity(), getString(R.string.str_change_profile_image), listItem, true)
    }

onCreate

// camera launcher
        cameraLauncher = registerForActivityResult(ActivityResultContracts.TakePicture())
        { isSaved ->

            if(!isSaved)
            {
                Log.e(strTag, "user canceled camera")
                return@registerForActivityResult
            }

            imageProcess()
        }

        galleryLauncher = registerForActivityResult(ActivityResultContracts.GetContent())
        { uri ->

            if(uri == null)
            {
                Log.e(strTag, "user canceled gallery")
                return@registerForActivityResult
            }

            imageUri = uri
            imageProcess()
        }

imageProcess function

 protected fun imageProcess()
    {
        CB_AppFunc.networkScope.launch {

            imageBitmap = CB_AppFunc.getBitmapFromUri(requireActivity().applicationContext.contentResolver, imageUri!!)
            if(imageBitmap == null)
            {
                Log.e(strTag, "failed to convert uri to bitmap")
                uploadFailed()
                return@launch
            }

            // N 버전 이상만 화면 회전을 시도한다. (외부 저장소 권한 제거) orientation
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            {
                try
                {
                    val inputStream = CB_AppFunc.application.contentResolver.openInputStream(imageUri!!)!!
                    val exifInterface = ExifInterface(inputStream)
                    imageBitmap = CB_AppFunc.changeImageOrientation(imageBitmap!!, exifInterface)
                }
                catch (e: IOException)
                {
                    e.printStackTrace()
                    imageBitmap = null
                }

                if(imageBitmap == null)
                {
                    Log.e(strTag, "failed to change orientation on image")
                    uploadFailed()
                    return@launch
                }
            }

            // image is not null, go to EditImageActivity
            CB_AppFunc.mainScope.launch {
                CB_ViewModel.editorBitmap = imageBitmap
                CB_PhotoEditorActivity.cameraListener = this@CB_CameraBaseFragment
                startActivity(Intent(requireActivity(), EditImageActivity::class.java))
            }
        }
    }

onCreate in EditImageActivity

 Bitmap bitmap = CB_ViewModel.Companion.getEditorBitmap();

        if(bitmap == null)
            Log.e(TAG, "bitmap is null");

        mPhotoEditorView.getSource().setImageBitmap(bitmap);


startActivityForResult: Camera / gallery => bitmap => EditImageActivity (OK) registerForActivityResult: Camera / gallery => bitmap => EditImageActivity (I got bitmap but filters are not working)

I'm testing Android API 30 Emulator

Thanks.

Yumin2019 commented 2 years ago

I was replacing my functions to startActivityForResult and added orientation logic and I got an error like this.

java.lang.IllegalStateException: Software rendering doesn't support hardware bitmaps

I googled it and I changed my getBitmapFromUri function like this.

Previous

 fun getBitmapFromUri(imageUri: Uri): Bitmap?
        {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
            {
                ImageDecoder.decodeBitmap(ImageDecoder.createSource(application.contentResolver, imageUri))
            }
            else
            {
                MediaStore.Images.Media.getBitmap(application.contentResolver, imageUri)
            }
        } 

Now

  fun getBitmapFromUriSoftware(imageUri: Uri): Bitmap = let {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
            {
                return@let ImageDecoder.decodeBitmap(ImageDecoder.createSource(application.contentResolver, imageUri))
                { decoder: ImageDecoder, _: ImageDecoder.ImageInfo?, _: ImageDecoder.Source? ->
                    decoder.isMutableRequired = true
                    decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
                }
            }

            BitmapDrawable(application.resources,
                MediaStore.Images.Media.getBitmap(application.contentResolver, imageUri)).bitmap
        }

And it works well without exception. and I tried this way to my ActivityResultLauncher issue as well. and Magically it works too without any problem.

https://developer.android.com/reference/android/graphics/ImageDecoder#setMutableRequired(boolean)

according to google document

By default, a Bitmap created by decodeBitmap will be immutable i.e. Bitmap.isMutable() returns false. This can be changed with setMutableRequired(true).

Mutable Bitmaps are incompatible with ALLOCATOR_HARDWARE, because Bitmap.Config#HARDWARE Bitmaps cannot be mutable. Attempting to combine them will throw an IllegalStateException.

anyways, I think if we use decodeBitmap function, we need to care about this mutable attribution. I think it's better to mention about this in readme file.

about IllegalStateException http://bumptech.github.io/glide/doc/hardwarebitmaps.html

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 20 days with no activity. Remove stale label or comment or this will be closed in 4 days.

Yumin2019 commented 2 years ago

comment

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 20 days with no activity. Remove stale label or comment or this will be closed in 4 days.

github-actions[bot] commented 2 years ago

This issue was closed because it has been stalled for 5 days with no activity.