Piasy / BigImageViewer

Big image viewer supporting pan and zoom, with very little memory usage and full featured image loading choices. Powered by Subsampling Scale Image View, Fresco, Glide, and Picasso. Even with gif and webp support! 🍻
MIT License
3.98k stars 402 forks source link

Implement CoilImageLoader #191

Open SkyleKayma opened 4 years ago

SkyleKayma commented 4 years ago

Hi, any plan for supporting Coil image loading library ?

https://github.com/coil-kt/coil

Thx,

Piasy commented 4 years ago

PR is welcome!

SkyleKayma commented 4 years ago

Before PR, is something like that suitable ? Or did I miss a very important notion? I wrote it quickly, there are obviously things to improve. It's based on what you have done for Glide.

I have never used Fresco, so I could not use it as a reference.

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import coil.Coil
import coil.api.load
import coil.request.RequestDisposable
import com.github.piasy.biv.loader.ImageLoader
import com.github.piasy.biv.metadata.ImageInfoExtractor
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream

/**
 * Created by Piasy{github.com/Piasy} on 09/11/2016.
 */
class CoilImageLoader(var context: Context, var imageLoader: coil.ImageLoader? = null) : ImageLoader {

    private val mRequestDisposableMap = hashMapOf<Int, RequestDisposable>()
    private val mImageLoader = imageLoader ?: Coil.loader()

    override fun loadImage(requestId: Int, uri: Uri, callback: ImageLoader.Callback) {
        val file = File(context.filesDir.toString(), "latestImageDownloaded.jpg")

        val disposable = mImageLoader.load(context, uri) {
            target(
                onStart = { callback.onStart() },
                onSuccess = { result ->
                    if (result is BitmapDrawable) {
                        saveBitmapToFile(file, result.bitmap, CompressFormat.JPEG, 100)
                    }
                    callback.onCacheHit(ImageInfoExtractor.getImageType(file), file)
                    callback.onSuccess(file)
                },
                onError = {
                    callback.onFail(Exception("Error on loading image with Coil"))
                }
            )
        }

        saveTarget(requestId, disposable)
    }

    private fun saveBitmapToFile(imageFile: File, bitmap: Bitmap, format: CompressFormat?, quality: Int) {
        val os: OutputStream
        try {
            os = FileOutputStream(imageFile)
            bitmap.compress(format, quality, os)
            os.flush()
            os.close()
        } catch (e: Exception) {
            Timber.e(e, "Error writing bitmap")
        }
    }

    override fun prefetch(uri: Uri) {
        // Do nothing
    }

    override fun cancel(requestId: Int) {
        clearTarget(requestId)
    }

    private fun clearTarget(requestId: Int) {
        mRequestDisposableMap.remove(requestId)?.dispose()
    }

    override fun cancelAll() {
        for (key in mRequestDisposableMap.keys) {
            cancel(key)
        }
    }

    private fun saveTarget(requestId: Int, disposable: RequestDisposable) {
        mRequestDisposableMap[requestId] = disposable
    }
}

Declared like this :

BigImageViewer.initialize(
    CoilImageLoader(applicationContext, ImageLoader(applicationContext) {
        // Custom params ...
        allowRgb565(false)
    })
)

We actually don't need to pass okHttpClient in parameters because we can create a custom ImageLoader from Coil like this:

ImageLoader(context) {
    okHttpClient {
        // Custom OkHttpClient
        OkHttpClient.Builder()
        .cache(CoilUtils.createDefaultCache(context))
        .build()
    }
}
Piasy commented 4 years ago

Looks cool. 👍

EchoTiger commented 4 years ago

Heyah! Any update on this? I'm currently planning on moving from Glide to Coil and would love to see Coil support in BigImageViewer.

SkyleKayma commented 4 years ago

No. I didn't had time to work on it. What's given above is working like that, you can add it in your project, or better take it and do a PR. 😉

EchoTiger commented 4 years ago

I wrote up a test project to run a quick test, and it seemed that there was some errors with Coil.loader() and target Maybe the current/later versions of Coil have removed or changed this?

I'm not at all familiar with Coil at the moment, but once I get around to experimenting with it maybe I'll be able to figure out something. 😄

saket commented 3 years ago

Keep in mind that the above code saves each image into a file twice -- once when Coil downloads the image and once when saveBitmapToFile() is called. For large images, this can increase load times by a couple hundred milliseconds. It's also called on the main thread, resulting in many dropped framerates.

mikaelzero commented 3 years ago

try it https://github.com/mikaelzero/mojito/blob/master/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt

nikita-bushuev commented 2 years ago

Since Coil 2.x you can retrieve files from disk cache and there is no need to save them manually. I implemented ImageLoader interface for the latest Coil (2.1.0 at the moment) in this gist, check it out 👀