9

I'm getting the vibrantSwatch color from bitmap using Palette.

To get bitmap from uri before I wrote this code(In API 29 getBitmap has depricated) :

Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(),
    Uri.fromFile(ImageModelArrayList.get(position).getImageUri()));

Because of deprication I wrote this code now to get bitmap:

 ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(),
                    Uri.fromFile(ImageModelArrayList.get(position).getImageUri()));
            Bitmap bitmap = ImageDecoder.decodeBitmap(source);

Now here in this Palette code I'm getting crash(If I use getBitmap no issue. If I use ImageDecoder I'm getting crash):

Palette p = createPaletteSync(bitmap);
            Palette.Swatch vibrantSwatch = p.getDominantSwatch();
            Log.d(TAG, "onBindViewHolder: vibrantSwatch " + vibrantSwatch);
            if (vibrantSwatch != null) {
                holder.constraintLayout.setBackgroundColor(vibrantSwatch.getRgb());
            }

Error:

2020-02-29 12:32:56.722 9865-9865/com.msp.project E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.msp.project, PID: 9865
java.lang.IllegalStateException: unable to getPixels(), pixel access is not supported on Config#HARDWARE bitmaps
    at android.graphics.Bitmap.checkHardware(Bitmap.java:401)
    at android.graphics.Bitmap.getPixels(Bitmap.java:1760)
Dnyaneshwar
  • 120
  • 1
  • 9

4 Answers4

14

You can copy the bitmap to a mutable one, not ideal but it works:

ImageDecoder.decodeBitmap(source).copy(Bitmap.Config.RGBA_F16, true)
Beuz
  • 193
  • 1
  • 12
  • Not sure if this is the best solution but it worked! – htafoya Oct 23 '20 at 05:33
  • Use following if you are still getting into exceptions: ImageDecoder.decodeBitmap(ImageDecoder.createSource(mContext.getContentResolver(),selectedImage)).copy(Bitmap.Config.ARGB_8888, true); – мalay мeнтa Mar 07 '21 at 06:49
9

In Compose & Coil:

import coil.compose.rememberImagePainter

val imagePainter = rememberImagePainter(
                    data = product.imageUrl,
                    builder = {
                        crossfade(true)
                        placeholder(R.drawable.ic_placeholder)
                        allowHardware(false) //IMPORTANT!
                    }
                )
Dr.jacky
  • 3,341
  • 6
  • 53
  • 91
6

By default ImageDecoder.decodeBitmap() returns immutable bitmap. And default allocation for the pixel memory is HARDWARE but may switch to software in case there is a small image or when HARDWARE is incompatible. (More info)

To get a mutable bitmap, you can set isMutableRequired = true. But when allocation is HARDWARE, bitmaps are immutable so first you need to change allocation of decoder.

You can handle this with other decodeBitmap() overload with OnHeaderDecodedListener.

var mutableBitmap = ImageDecoder.decodeBitmap(
                    source,
                    ImageDecoder.OnHeaderDecodedListener { decoder, info, source ->
                        decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
                        decoder.isMutableRequired = true
                    })
Akn
  • 421
  • 5
  • 9
1

Replace

ImageDecoder.decodeBitmap(source)

By

ImageDecoder.decodeBitmap(source, (imageDecoder, imageInfo, source1) -> imageDecoder.setMutableRequired(true));
J.Jacobs
  • 703
  • 6
  • 17