compose-imageloader icon indicating copy to clipboard operation
compose-imageloader copied to clipboard

Load image using bytearray

Open sunildhiman90 opened this issue 1 year ago • 14 comments

Hi,

Can we load image from ByteArray in compose imageloader? if yes how we can do that?

Thanks

sunildhiman90 avatar Jan 06 '24 09:01 sunildhiman90

Actually it is not loading image from ios uri, I used compose-multiplatform-file-picker for picking the file from iOS files, then i use rememberImagePainter, it does not load image. I gets this error in the logs:

2024-01-06 14:37:54.858217+0530 KMPAppExample[9447:410797] [DocumentManager] The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method}

And this is the path of image which im getting from file picker and using in rememberImagePainter: /Users/sunil/Library/Developer/CoreSimulator/Devices/F38BFB2D-6776-4B28-9D06-54D521E45237/data/Containers/Shared/AppGroup/8F44B401-AFFC-4219-ACFF-65142F2384AA/File Provider Storage/images (1)-536DD7B9-38CB-49E6-B42E-8FF33DB31BD5.JPEG

sunildhiman90 avatar Jan 06 '24 09:01 sunildhiman90

You can add a custom Fetcher like this:

class ByteArrayFetcher(
    private val data: ByteArray,
) : Fetcher {
    override suspend fun fetch(): FetchResult {
        return FetchResult.OfSource(
            source = Buffer().apply {
                write(data)
            }
        )
    }

    class Factory : Fetcher.Factory {
        override fun create(data: Any, options: Options): Fetcher? {
            if (data !is ByteArray) return null
            return ByteArrayFetcher(data)
        }
    }
}

and then:

ImageLoader {
    components {
        add(ByteArrayFetcher.Factory())
    }
}

qdsfdhvh avatar Jan 06 '24 12:01 qdsfdhvh

In the next version, I'll add to the default support #412

qdsfdhvh avatar Jan 06 '24 12:01 qdsfdhvh

@qdsfdhvh And how we can use it?

Like this with custom request and imageLoader in rememberImagePainter:

` val imageLoader = ImageLoader { components { add(ByteArrayFetcher.Factory()) } }

    Image(
        painter = rememberImagePainter(request = ImageRequest(data = byteArray), imageLoader = imageLoader),
        contentDescription = "",
        modifier = Modifier
            .padding(16.dp)
            .size(50.dp)
    )`

sunildhiman90 avatar Jan 07 '24 15:01 sunildhiman90

In addition to configuring it in ImageLoader, you can also configure it directly in ImageRequest, like this:

val request = remember {
    ImageRequest(data = byteArray) {
        components {
            add(ByteArrayFetcher.Factory())
        }
    }
}
Image(
    painter = rememberImagePainter(request),
    // ...
)

in version 1.7.2, default config is support ByteArray.

qdsfdhvh avatar Jan 08 '24 01:01 qdsfdhvh

Ok @qdsfdhvh huge thanks.

sunildhiman90 avatar Jan 08 '24 06:01 sunildhiman90

Hi @qdsfdhvh i tried it, But its not working, not sure if issue is with compose-multiplatform-file-picker get byte array logic or its with compose image loader. Did u tried it yourself?

sunildhiman90 avatar Jan 08 '24 07:01 sunildhiman90

Hi @sunildhiman90 , ByteArray should work fine, but there seems to be something wrong with MPFile.getFileByteArray() when I test it, so i used MPFile.platformFile, in #416, I supported android.net.Uri in android, platform.Foundation.NSURL in apple and java.io.File in desktop, and also support okio.Path, if some MPFile.platformFile not support, you can convert it to okio.Path in next verison 1.7.3.

qdsfdhvh avatar Jan 08 '24 11:01 qdsfdhvh

@qdsfdhvh I tried using platformFile as well, its also not working. So how can i load that image now from iOS file picker using compose image loader?

sunildhiman90 avatar Jan 10 '24 06:01 sunildhiman90

use version 1.7.3 and MPFile.platformFile, here is my test code.

qdsfdhvh avatar Jan 10 '24 11:01 qdsfdhvh

Thanks @qdsfdhvh, its working fine that way as u mentioned in version 1.7.3 and with MPFile.platformFile.

One question here, suppose i want to get the byte array of this image in base64 format, then how can i do that by any way or by any library in compose multiplatform, any idea?

sunildhiman90 avatar Jan 11 '24 06:01 sunildhiman90

Maybe need to manually extend MPFile and implement ByteArray reading for each platform (due to the issue with the default getFileByteArray()), and then perform base64 encoding.

qdsfdhvh avatar Jan 11 '24 07:01 qdsfdhvh

Hi one question here, why didnt you made these changes with compose multiplatform version 1.5.11 instead of 1.6.0-dev1334 ?

sunildhiman90 avatar Jan 12 '24 06:01 sunildhiman90

Mainly because of the dependency on compose.components.resources, I am currently using the new-resources-gradle-plugin from compose-multiplatform to manage resources. These changes have already been merged, so it is currently not convenient to downgrade the version of compose-multiplatform.

qdsfdhvh avatar Jan 13 '24 01:01 qdsfdhvh