Mauker
Mauker

Reputation: 11497

Does Glide have a method for loading both PNG and SVG?

I'm using Glide to load some images asynchronously into some of my ImageViews, and I know it can handle images like PNG or JPG as it can handle SVG.

Thing is, As far as I know, the way I load those two kinds of image differs. Like:

Loading "normal" images

Glide.with(mContext)
                .load("URL")
                .into(cardHolder.iv_card);

Loading SVG

GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(mContext)
        .using(Glide.buildStreamModelLoader(Uri.class, mContext), InputStream.class)
        .from(Uri.class)
        .as(SVG.class)
        .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
        .sourceEncoder(new StreamEncoder())
        .cacheDecoder(new FileToStreamDecoder<>(new SVGDecoder()))
        .decoder(new SVGDecoder())
        .listener(new SvgSoftwareLayerSetter<Uri>());

requestBuilder
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .load(Uri.parse("URL"))
        .into(cardHolder.iv_card);

And if I try to load SVG with the first method it won't work. If I try to load PNG or JPG with the second method, it won't work either.

Is there a generic way to load both image types using Glide?

The server where I'm fetching those images from don't tell me the image type before I download it. It's a REST server and the resource will be retrieved in a way like "http://foo.bar/resource". The only way to know the image type is reading the HEAD response.

Upvotes: 40

Views: 66795

Answers (10)

Hassan El Sayed Ammer
Hassan El Sayed Ammer

Reputation: 137

first of all, Coil has an issue. you can't load SVG and PNG- JPG,etc .at the same time so this solution will be as workaround using the Extension function

1- Make sure you use this dependency

  • For normal images implementation "io.coil-kt:coil:2.5.0"
  • For SVG images implementation "io.coil-kt:coil-svg:2.5.0"

2- Create an exception file name it Extension.Kt

3- Create this extension function

import android.widget.ImageView
import coil.ImageLoader
import coil.decode.SvgDecoder
import coil.request.ImageRequest
import com.codestation.football_league_application.R

fun ImageView.loadImageUrl(imageUrl: String) {
    val imageLoader = ImageLoader.Builder(context)
        .components { add(SvgDecoder.Factory()) }
        .build()

    val request = ImageRequest.Builder(context)
        .crossfade(true)
        .crossfade(1000)
        .placeholder(R.drawable.placeholder)
        .data(url)
        .target(this)
        .build()

    imageLoader.enqueue(request)
}

4-In your adapter or Activity/Fragment call your imageView.loadImageUrl extension function and pass image Url to It as a parameter.

  imageView.loadImageUrl(imageUrl)

Upvotes: 0

Sadegh J
Sadegh J

Reputation: 1862

ALTERNATIVE WAY : kotlin + Coil

This solution will work well with .svg , .png , .jpg

add dependency:

//Coil (https://github.com/coil-kt/coil)
implementation("io.coil-kt:coil:2.5.0")
implementation("io.coil-kt:coil-svg:2.5.0")

add this function to your code:

fun ImageView.loadUrl(url: String) {
    val imageLoader = ImageLoader.Builder(context)
        .components { add(SvgDecoder.Factory()) }
        .build()

    val request = ImageRequest.Builder(context)
        .crossfade(true)
        .crossfade(500)
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.error)
        .data(url)
        .target(this)
        .build()

    imageLoader.enqueue(request)
}

Then call this method in your activity or fragment:

  imageView.loadUrl(url)
  // Sample SVG url : https://upload.wikimedia.org/wikipedia/commons/3/36/Red_jungle_fowl_white_background.png

Upvotes: 22

Aleksandr K
Aleksandr K

Reputation: 69

Use the Sharp library, in place of the Glide library

implementation 'com.pixplicity.sharp:library:1.1.0'

InputStream stream = response.body().byteStream();
                   Sharp.loadInputStream(stream).into(target);
                    stream.close();  

An example can be seen here https://www.geeksforgeeks.org/how-to-load-svg-from-url-in-android-imageview/

fun fetchSvg(context: Context, url: String, target: ImageView) {
    val httpClient = OkHttpClient.Builder()
        .cache(Cache(context.cacheDir, 5 * 1024 * 1014))
        .build()
 
    val request: Request = Request.Builder().url(url).build()
    httpClient.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call?, e: IOException?) {
            // we are adding a default image if we gets any error.
            target.setImageResource(R.drawable.ic_app_logo)
        }

        @Throws(IOException::class)
        override fun onResponse(call: Call?, response: Response) {
       
            response.body()?.apply {
                val stream = this.byteStream()
                Sharp.loadInputStream(stream).into(target)
                stream.close()
            }
        }
    })
}

use code

 if(item.logo.endsWith("svg"))
               Media.fetchSvg(icon.context,item.logo, icon)
            else{
               Glide.with(icon.context).load(Uri.parse(item.logo)).into(icon)
            }

Upvotes: 0

BekaBot
BekaBot

Reputation: 510

GlideToVectorYou did not work for me, so I used coil with coil-svg extension library

Upvotes: 2

Mattia Ruggiero
Mattia Ruggiero

Reputation: 880

In case anyone still needs it, with Glide v4 you can use Glide-SVG library for adding SVG support easily to Glide. You only need to import Android SVG library too, and you can render any SVG with Glide using this simple, standard line of code:

GlideApp.with(this).load(url).into(imageView)

where GlideApp is your locally generated Glide Module, like the following:

@GlideModule
class GlideModule : AppGlideModule() {
    override fun isManifestParsingEnabled() = false

    override fun applyOptions(context: Context, builder: GlideBuilder) {
        super.applyOptions(context, builder)
        builder.setLogLevel(Log.DEBUG)
    }
}

Upvotes: 1

jaideep rawat
jaideep rawat

Reputation: 471

I also faced the same problem what i have done solved my problem you just have 2 do 2 things which work perfectly Go to the link https://github.com/corouteam/GlideToVectorYou 1- just copy past maven dependancy to project build allprojects { repositories { ... maven { url 'https://jitpack.io' } } } 2-add the dependency in app build like implementation 'com.github.corouteam:GlideToVectorYou:v2.0.0'

thanks it will resolve to load the svg make sure that you are loading same as i am doing

Glide.with(holder.itemView.getContext()) .load(imageurl) .apply(new RequestOptions() .placeholder(R.drawable.placeholder) .dontAnimate() .fitCenter()) .into(holder.image);

Upvotes: 0

sak
sak

Reputation: 1298

For Glide 4+ use this library called GlideToVectorYou which uses Glide internally.

fun ImageView.loadSvg(url: String?) {
    GlideToVectorYou
        .init()
        .with(this.context)
        .setPlaceHolder(R.drawable.loading, R.drawable.actual)
        .load(Uri.parse(url), this)
}

Source: How to load remote svg files with Picasso library

Upvotes: 1

Maheshwar Ligade
Maheshwar Ligade

Reputation: 6855

You can use Glide & AndroidSVG together to achieve your goal.

There is sample from Glide for SVG.Sample Example

Setup RequestBuilder

requestBuilder = Glide.with(mActivity)
    .using(Glide.buildStreamModelLoader(Uri.class, mActivity), InputStream.class)
    .from(Uri.class)
    .as(SVG.class)
    .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
    .sourceEncoder(new StreamEncoder())
    .cacheDecoder(new FileToStreamDecoder<SVG>(new SvgDecoder()))
    .decoder(new SvgDecoder())
    .placeholder(R.drawable.ic_facebook)
    .error(R.drawable.ic_web)
    .animate(android.R.anim.fade_in)
    .listener(new SvgSoftwareLayerSetter<Uri>());

Use RequestBuilder with uri

Uri uri = Uri.parse("http://upload.wikimedia.org/wikipedia/commons/e/e8/Svg_example3.svg");
requestBuilder
    .diskCacheStrategy(DiskCacheStrategy.SOURCE)
    // SVG cannot be serialized so it's not worth to cache it
    .load(uri)
    .into(mImageView);

This way you can achieve your goal. I hope this is helpful.

Upvotes: 24

Justin
Justin

Reputation: 18186

For others who reach this thread because they're looking for a way to load SVG's in Xamarin Android, the accepted answer won't work because a lot of those classes / methods don't seem to be available in the Xamarin Glide nuget package. Here is what worked for me:

public static void SetSvgFromBytes (this ImageView imageView, byte[] bytes, int width, int height) {
            // Load the SVG from the bytes.
            var stream = new MemoryStream (bytes);
            var svg = SVG.GetFromInputStream (stream);
            // Create a Bitmap to render our SVG to.
            var bitmap = Bitmap.CreateBitmap (width, height, Bitmap.Config.Argb8888);
            // Create a Canvas to use for rendering.
            var canvas = new Canvas (bitmap);
            canvas.DrawRGB (255, 255, 255);
            // Now render the SVG to the Canvas.
            svg.RenderToCanvas (canvas);
            // Finally, populate the imageview from the Bitmap.
            imageView.SetImageBitmap (bitmap);
        }

It requires the AndroidSVG.Xamarin nuget package.

Upvotes: 1

Josue Amador
Josue Amador

Reputation: 166

I added a flexible decoding pipeline to decode an image or SVG, maybe can help! based on glide SVG example

Decoder

class SvgOrImageDecoder : ResourceDecoder<InputStream, SvgOrImageDecodedResource> {

override fun handles(source: InputStream, options: Options): Boolean {
    return true
}

@Throws(IOException::class)
override fun decode(
    source: InputStream, width: Int, height: Int,
    options: Options
): Resource<SvgOrImageDecodedResource>? {
    val array = source.readBytes()
    val svgInputStream = ByteArrayInputStream(array.clone())
    val pngInputStream = ByteArrayInputStream(array.clone())

    return try {
        val svg = SVG.getFromInputStream(svgInputStream)

        try {
            source.close()
            pngInputStream.close()
        } catch (e: IOException) {}

        SimpleResource(SvgOrImageDecodedResource(svg))
    } catch (ex: SVGParseException) {
        try {
            val bitmap = BitmapFactory.decodeStream(pngInputStream)
            SimpleResource(SvgOrImageDecodedResource(bitmap = bitmap))
        } catch (exception: Exception){
            try {
                source.close()
                pngInputStream.close()
            } catch (e: IOException) {}
            throw IOException("Cannot load SVG or Image from stream", ex)
        }
    }
}

Transcoder

class SvgOrImageDrawableTranscoder : ResourceTranscoder<SvgOrImageDecodedResource, PictureDrawable> {
override fun transcode(
    toTranscode: Resource<SvgOrImageDecodedResource>,
    options: Options
): Resource<PictureDrawable>? {
    val data = toTranscode.get()

    if (data.svg != null) {
        val picture = data.svg.renderToPicture()
        val drawable = PictureDrawable(picture)
        return SimpleResource(drawable)
    } else if (data.bitmap != null)
        return SimpleResource(PictureDrawable(renderToPicture(data.bitmap)))
    else return null
}

private fun renderToPicture(bitmap: Bitmap): Picture{
    val picture = Picture()
    val canvas = picture.beginRecording(bitmap.width, bitmap.height)
    canvas.drawBitmap(bitmap, null, RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat()), null)
    picture.endRecording();

    return picture
}

Decoded Resource

data class SvgOrImageDecodedResource(
val svg:SVG? = null,
val bitmap: Bitmap? = null)

Glide Module

class AppGlideModule : AppGlideModule() {
override fun registerComponents(
    context: Context, glide: Glide, registry: Registry
) {
    registry.register(SvgOrImageDecodedResource::class.java, PictureDrawable::class.java, SvgOrImageDrawableTranscoder())
        .append(InputStream::class.java, SvgOrImageDecodedResource::class.java, SvgOrImageDecoder())
}

// Disable manifest parsing to avoid adding similar modules twice.
override fun isManifestParsingEnabled(): Boolean {
    return false
}

}

Upvotes: 10

Related Questions