4

In the app I'm using the following sample to load an SVG image into ImageView:

Glide.with(context)
                .using(Glide.buildStreamModelLoader(Uri.class, context), 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())
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .load(uri)
                .into(imageView);

An ImageView in xml looks like this:

       <ImageView
        android:layout_width="46dp"
        android:layout_height="46dp"
        android:layout_marginTop="25dp"
        android:layout_gravity="center"
       />

So, the problem can be seen on the image below. The right icon was set from app's resources, while the left one is loaded from server using Glide. For some reason image is not scaling properly and looks blurry.

images to compare

I've already tried the solution from this answer: Image size too small when loading SVG with Glide, but it doesn't work.

anro
  • 1,300
  • 16
  • 30
  • try `Drawable d = imageView.getDrawable()` and use `Log.d` to dump `d.getClass()`, `d.getIntrinsicWidth()` and `d.getIntrinsicHeight()`, now what do you see on the logcat? – pskink Oct 11 '17 at 04:59
  • The left one is: d.getIntrinsicWidth() = 46, d.getIntrinsicHeight() = 46 The right one: d.getIntrinsicWidth() = 69, d.getIntrinsicHeight() = 69 – anro Oct 11 '17 at 05:46
  • and what about `d.getClass()` ? is it `android.graphics.drawable.PictureDrawable` and `android.graphics.drawable.BitmapDrawable` ? also does `getIntrinsicWidth` / `getIntrinsicHeight` changes if you use bigger `ImageView`? like 256px x 256 px for example – pskink Oct 11 '17 at 06:56
  • The left one is instance of android.graphics.drawable.PictureDrawable The intrinsic width/height haven't changed after I set ImageView's size as 56dp x 56dp. – anro Oct 11 '17 at 08:04
  • The right one is android.support.graphics.drawable.VectorDrawableCompat, and intrinsic width/heigh are also remain the same after setting different size to ImageView, but image there is scaling correctly. – anro Oct 11 '17 at 08:08
  • so the left uses fixed 46 x 46 pixels no matter how big is your image view, in your svg file what do you have as `xxx` and `yyy` in ``? – pskink Oct 11 '17 at 08:37
  • It is 46px there. I understand, it is the reason here, but doesn't svg format mean that image should scale anyway? – anro Oct 11 '17 at 09:01
  • No. If your SVG specifies a specific width, it will be drawn at that size. If you want it to scale, try setting the width and height in your SVG to `"100%"`. – Paul LeBeau Oct 11 '17 at 09:09
  • 46px is not normally the same as 46dp. So if your SVG is being drawn at 46x46px and scaled up to 46dp, that will be why it is looking blurry. – Paul LeBeau Oct 11 '17 at 09:10
  • So, did I get it right, that there is no way to modify it's size programatically and we should solve that problem at backend side, i.e. modify the source file? – anro Oct 11 '17 at 09:16

2 Answers2

7

After upgrading to glide v4 the problem has gone. Now I'm using the following code for loading svg:

      GlideApp.with(context)
            .as(PictureDrawable.class)
            .transition(withCrossFade())
            .fitCenter()
            .listener(new SvgSoftwareLayerSetter())
            .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.RESOURCE))
            .load(uri).into(imageView);

And in my AppGlideModule I have:

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, Registry registry) {
    registry.register(SVG.class, PictureDrawable.class, new SvgDrawableTranscoder())
            .prepend(SVG.class, new SvgEncoder())
            .append(InputStream.class, SVG.class, new SvgDecoder());
}

SvgDrawableTranscoder converts SVG to PictureDrawable with one simple method:

public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> {

    @Override
    public Resource<PictureDrawable> transcode(@NonNull Resource<SVG> toTranscode, @NonNull Options options) {
        SVG svg = toTranscode.get();
        Picture picture = svg.renderToPicture();
        PictureDrawable drawable = new PictureDrawable(picture);
        return new SimpleResource<>(drawable);
    }
}

And that's how I implemented SvgEncoder class:

public class SvgEncoder implements ResourceEncoder<SVG>{
    @NonNull
    @Override
    public EncodeStrategy getEncodeStrategy(@NonNull Options options) {
        return EncodeStrategy.SOURCE;
    }

    @Override
    public boolean encode(@NonNull Resource<SVG> data, @NonNull File file, @NonNull Options options) {
        try {
            SVG svg = data.get();
            Picture picture = svg.renderToPicture();
            picture.writeToStream(new FileOutputStream(file));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
anro
  • 1,300
  • 16
  • 30
1

For Android VectorDrawables, surprisingly the following worked for me (see this post):

Glide.with(context).load(myImage).dontTransform().into(myView);
User Rebo
  • 3,056
  • 25
  • 30