Click here to Skip to main content
15,886,919 members
Articles / Mobile Apps / Android

Android ImageView and Drawable with SVG Support

Rate me:
Please Sign up or sign in to vote.
4.75/5 (11 votes)
14 Dec 2010CPOL3 min read 155K   5.7K   33   25
This article introduces custom classes SvgImageView and SvgDrawable which allow to use SVG image just like any other image.

Introduction

This article shows how to use SVG images in Android. The goal is to use SVG images just like any other images, using Drawable and ImageView classes. New classes are introduced for this purpose: SvgDrawable and SvgImageView.

These classes support all Android scale types for images: fitXY, fitStart, fitEnd, centerCrop and so on. What is important, the image is stretched in vector format, before rasterization. I believe this improves overall performance.

Background

You are encouraged to read the article by Igor Kushnarev beforehand. Carl D. Worth, Anton Persson and Igor Kushnarev have done a great job. This article is a continuation of their work.

I needed to change their implementation because of the following reasons:

  • Actually a lot (if not all) SVG images have the desired width and height. They are written in the file. And I want to use them too. The original implementation did not care about SVG width and height.
  • I need a Drawable class to work with image, not just an ImageView. Because Drawable can be used in many other Android classes.
  • I want to use advantage of scale types for images: fitXY, fitStart, fitEnd, centerCrop and so on.
  • FitXY scale type requires non-uniform scaling of image. This is required but was not supported by the original native code.
  • I do not want standard ImageView class to scale rasterized bitmap in case of SVG Drawable. I want that vector image would be scaled according to scale type before rasterization. This will improve performance and quality of image.

Prerequisites

Well, if you have read the article by Igor Kushnarev, you should already have this:

  • Eclipse with Java, Android and CDT support
  • Android SDK
  • Android NDK
  • Sequoyah Android Native Support in Eclipse

Points of Interest

Width and height of SVG image

Please look at /jni/libsvg-android/svg_android.c.

I've added two functions that return width and height of SVG image to Java class SvgRaster:

  • Java_com_libsvg_SvgRaster_svgAndroidGetWidth(),
  • Java_com_libsvg_SvgRaster_svgAndroidGetHeight().

They use values from DOM model, which were set on parsing the XML structure.

Scaling Support

I've been selecting from two basic approaches to implement Android scale types support:

  1. Rewrite the whole ImageView class. Because it was written specially for raster bitmaps, it takes the whole work to make matrix transformation, not letting the Drawable itself to take care about scaling.
  2. Cheat on ImageView class. Make it believe that Drawable has a good size and should not be scaled using Matrix transform. Let the SVG image make scaling in vector, before rasterization.

I've chosen the second approach because it is easier.

Before ImageView class prepares matrix transform, we let SvgDrawable to adjust its width and height to match those from ImageView with respect to scaleType.

For this purpose, we rewrite setScaleType(), setImageDrawable() and onSizeChanged().

Java
@Override
public void setScaleType (ImageView.ScaleType scaleType) {
    super.setScaleType(scaleType);
    if (! mIsSvg) {
        return;
    } 

    SvgDrawable svg = (SvgDrawable) getDrawable(); 
    // Let SVG scale itself!
    super.setImageDrawable(null); 
    svg.setScaleType(scaleType);
    int vWidth = getWidth() - getPaddingLeft() - getPaddingRight();
    int vHeight = getHeight() - getPaddingTop() - getPaddingBottom();
    svg.adjustToParentSize(vWidth, vHeight);
    super.setImageDrawable(svg);
} 

Notice that we first call super.setImageDrawable(null). Then we change SVG image scaling. And then return it with super.setImageDrawable(svg). This trick works!

SvgDrawable Class

This is a rather simple implementation based on ideas of Igor Kushnarev.

Scaling support required new function:

Java
public void adjustToParentSize(int vWidth, int vHeight) 

It is called from SvgImageView when onSizeChanged(), setScaleType() and on load.

Please also notice that we choose how to render svg image in onBoundsChange():

  • using non-uniform scaling - SvgRaster.svgAndroidRenderToArea()
  • using uniform scaling - SvgRaster.svgAndroidRenderToAreaUniform

Non-uniform Scaling Support in libsvgandroid

Please look at /jni/libsvg-android/svg_android_render.c.

I've changed function:

Java
svg_status_t svgAndroidRenderToArea(JNIEnv *env, 
svg_android_t *svg_android, jobject android_canvas, int x, int y, int w, int h) { 
    ... 
    svg_android->fit_to_area = -1; 
    svg_android->fit_uniform = 0; 
    ... 
    return svg_render (svg_android->svg, &SVG_ANDROID_RENDER_ENGINE, svg_android);
}

svg_android->fit_uniform is a newly added member, which is used in: _svg_android_set_viewport_dimension().

In svgAndroidRenderToArea(), it is set to zero (false).

In svgAndroidRenderToAreaUniform(), it is set to -1 (true).

Using SvgImageView

Look at /res/layout/main2.xml.

Part of this file:

XML
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/TableView" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:stretchColumns="1">
    <TableRow
        android:layout_weight="1.0"
        android:layout_height="fill_parent">
        <com.libsvg.SvgImageView
            android:src="@drawable/smile01" 
            android:background="#FF806440"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" 
            android:layout_gravity="center"
            android:scaleType="fitXY" 
            />
        <com.libsvg.SvgImageView
            android:src="@drawable/smile02" 
            android:background="#FF758040"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" 
            android:layout_gravity="center" 
            android:scaleType="fitStart" 
            />

Notice the tags <com.libsvg.SvgImageView>. They have all the attributes of standard ImageView.

Result

Upon successful compile and run, you should see the following picture of smiles in a table.
Table has two rows with 3 images on each row.

screenshot.jpg

It demonstrates different scale types for SVG images.

Currently, from left to right, from top to bottom:
fitXY, fitStart, fitEnd,
centerCrop, center, centerInside

Conclusion

Hope this article will help to improve Android development. If you have something to add - please write here and share your code!

--
Sincerely yours,
Pavel B. Chernov

History

  • 14th December, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSvg Rendering problem Pin
Member 961927128-Feb-13 1:35
Member 961927128-Feb-13 1:35 
I'm using a project, in which there is a spinner class where svg file names will be displayed. When user selects the svg filename that svg filename is sent to another activity where svg is rendered on the screen. In the second activity there is a button, on click of that button it goes back to the first activity i.e.,spinner activity.The problem occurs when this cycle is repeated.

code which i have written is:

RelativeLayout myLayout = new RelativeLayout(this);
SvgDrawable svgd = new SvgDrawable(getResources(),filePath);
ImageView img = new ImageView(this_act);
RelativeLayout.LayoutParams imgParams = new RelativeLayout.LayoutParams(600, 600);
img.setImageDrawable(svgd);
System.out.println("after setMargins");
img.setBackgroundColor(Color.LTGRAY);
myLayout.addView(img, imgParams);
setContentView(myLayout);

error code goes like this:


JNI WARNING: threadid=2 using env from threadid=1
W/dalvikvm( 3839): in Lcom/libsvg/SvgRaster;.svgAndroidDestroy (J)V (DeleteGlobalRef)
I/dalvikvm( 3839): "HeapWorker" daemon prio=5 tid=2 NATIVE
I/dalvikvm( 3839): | group="system" sCount=0 dsCount=0 obj=0x4050eaf0 self=0x1165f0
I/dalvikvm( 3839): | sysTid=3841 nice=0 sched=0/0 cgrp=default handle=969568
I/dalvikvm( 3839): | schedstat=( 76129115 68302254 26 )
I/dalvikvm( 3839): at com.libsvg.SvgRaster.svgAndroidDestroy(Native Method)
I/dalvikvm( 3839): at com.libsvg.SvgDrawable.finalize(SvgDrawable.java:411)
I/dalvikvm( 3839): at dalvik.system.NativeStart.run(Native Method)
I/dalvikvm( 3839):
E/dalvikvm( 3839): VM aborting
I/DEBUG ( 2926): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 2926): Build fingerprint: 'generic/sdk/generic:2.3.3/GRI34/101070:eng/test-keys'
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadd00d
I/DEBUG ( 2926): r0 fffffec4 r1 deadd00d r2 00000026 r3 00000000
I/DEBUG ( 2926): r4 800a45c0 r5 00000001 r6 00000004 r7 42656fa0
I/DEBUG ( 2926): r8 100ffa88 r9 42656f98 10 42656f84 fp 44728888
I/DEBUG ( 2926): ip 800a4720 sp 100ff9f8 lr afd19375 pc 80045a4a cpsr 20000030
I/ActivityManager( 61): Displayed com.example.multiplesvg/.RendreingMultipleSvgActivity: +777ms
I/DEBUG ( 2926): #00 pc 00045a4a /system/lib/libdvm.so
I/DEBUG ( 2926): #01 pc 00037748 /system/lib/libdvm.so
I/DEBUG ( 2926): #02 pc 00037868 /system/lib/libdvm.so
I/DEBUG ( 2926): #03 pc 000392b0 /system/lib/libdvm.so
I/DEBUG ( 2926): #04 pc 0005500e /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #05 pc 0005506a /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #06 pc 000550c4 /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #07 pc 00053656 /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #08 pc 00052100 /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #09 pc 00052150 /data/data/com.example.multiplesvg/lib/libsvgandroid.so
I/DEBUG ( 2926): #10 pc 00017d74 /system/lib/libdvm.so
I/DEBUG ( 2926): #11 pc 00048ecc /system/lib/libdvm.so
I/DEBUG ( 2926): #12 pc 00041a86 /system/lib/libdvm.so
I/DEBUG ( 2926): #13 pc 0004e624 /system/lib/libdvm.so
I/DEBUG ( 2926): #14 pc 0001cfd4 /system/lib/libdvm.so
I/DEBUG ( 2926): #15 pc 000220dc /system/lib/libdvm.so
I/DEBUG ( 2926): #16 pc 00020fd0 /system/lib/libdvm.so
I/DEBUG ( 2926): #17 pc 0005f430 /system/lib/libdvm.so
I/DEBUG ( 2926): #18 pc 0005f656 /system/lib/libdvm.so
I/DEBUG ( 2926): #19 pc 0005592c /system/lib/libdvm.so
I/DEBUG ( 2926): #20 pc 000559bc /system/lib/libdvm.so
I/DEBUG ( 2926): #21 pc 00055b58 /system/lib/libdvm.so
I/DEBUG ( 2926): #22 pc 00053a68 /system/lib/libdvm.so
I/DEBUG ( 2926): #23 pc 00011a7c /system/lib/libc.so
I/DEBUG ( 2926): #24 pc 00011640 /system/lib/libc.so
I/DEBUG ( 2926):
I/DEBUG ( 2926): code around pc:
I/DEBUG ( 2926): 100ff9d4 afd183d9 /system/lib/libc.so
I/DEBUG ( 2926): 100ff9d8 42656fa0
I/DEBUG ( 2926): 100ff9dc 0005eb82 [heap]
I/DEBUG ( 2926): 100ff9e0 00000001
I/DEBUG ( 2926): 100ff9e4 00000004
I/DEBUG ( 2926): 100ff9e8 42656fa0
I/DEBUG ( 2926): 100ff9ec afd18437 /system/lib/libc.so
I/DEBUG ( 2926): 100ff9f0 df002777
I/DEBUG ( 2926): 100ff9f4 e3a070ad
I/DEBUG ( 2926): #00 100ff9f8 00000000
I/DEBUG ( 2926): 100ff9fc 8003774d /system/lib/libdvm.so
I/DEBUG ( 2926): #01 100ffa00 00000000
I/DEBUG ( 2926): 100ffa04 8003786d /system/lib/libdvm.so
I/BootReceiver( 61): Copying /data/tombstones/tombstone_03 to DropBox (SYSTEM_TOMBSTONE)
D/Zygote ( 33): Process 3839 terminated by signal (11)
E/InputDispatcher( 61): channel '40658698 com.example.multiplesvg/com.example.multiplesvg.MultipleSvgActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x8
E/InputDispatcher( 61): channel '40658698 com.example.multiplesvg/co
C#
m.example.multiplesvg.MultipleSvgActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
I/ActivityManager(   61): Process com.example.multiplesvg (pid 3839) has died.
I/WindowManager(   61): WIN DEATH: Window{40658698 com.example.multiplesvg/com.example.multiplesvg.MultipleSvgActivity paused=false}
I/WindowManager(   61): WIN DEATH: Window{4076e910 com.example.multiplesvg/com.example.multiplesvg.RendreingMultipleSvgActivity paused=false}
I/ActivityManager(   61): Start proc com.example.multiplesvg for activity com.example.multiplesvg/.MultipleSvgActivity: pid=3848 uid=10057 gids={}
E/InputDispatcher(   61): channel '40759d68 Starting com.example.multiplesvg (server)' ~ Consumer closed input channel or an error occurred.  events=0x8
E/InputDispatcher(   61): channel '40759d68 Starting com.example.multiplesvg (server)' ~ Channel is unrecoverably broken and will be disposed!
I/WindowManager(   61): WINDOW DIED Window{40759d68 Starting com.example.multiplesvg paused=false}
E/InputQueue-JNI(   61): channel '40759d68 Starting com.example.multiplesvg (client)' ~ Publisher closed input channel or an error occurred.  events=0x8

Questioncalling the libsvg from a separate project Pin
Member 961927118-Feb-13 2:58
Member 961927118-Feb-13 2:58 
QuestionVM Aborting error Pin
ewdfewfew2328-Feb-12 8:57
ewdfewfew2328-Feb-12 8:57 
Questionhow to scroll the image Pin
Member 198809227-Feb-12 22:16
Member 198809227-Feb-12 22:16 
AnswerRe: how to scroll the image Pin
Manfeel18-Sep-12 14:27
Manfeel18-Sep-12 14:27 
QuestionThanks for your work + Drawable question ! Pin
Ernesto S31-Dec-11 7:01
Ernesto S31-Dec-11 7:01 
QuestionThank you Pin
mcflysoft27-Aug-11 0:51
mcflysoft27-Aug-11 0:51 
Generallayout problem Pin
peter5031826-Mar-11 3:30
peter5031826-Mar-11 3:30 
QuestionSVG that doesn't work Pin
feeder18034-Feb-11 8:01
feeder18034-Feb-11 8:01 
AnswerRe: SVG that doesn't work Pin
Alejandro Xalabarder4-Feb-11 15:23
Alejandro Xalabarder4-Feb-11 15:23 
GeneralRe: SVG that doesn't work Pin
feeder18035-Feb-11 0:49
feeder18035-Feb-11 0:49 
GeneralRe: SVG that doesn't work Pin
diov5-Feb-11 1:21
diov5-Feb-11 1:21 
GeneralRe: SVG that doesn't work Pin
diov5-Feb-11 7:21
diov5-Feb-11 7:21 
GeneralRe: SVG that doesn't work Pin
Alejandro Xalabarder6-Feb-11 10:16
Alejandro Xalabarder6-Feb-11 10:16 
GeneralRe: SVG that doesn't work Pin
feeder18036-Feb-11 21:01
feeder18036-Feb-11 21:01 
GeneralRe: SVG that doesn't work Pin
diov7-Feb-11 0:49
diov7-Feb-11 0:49 
GeneralRe: SVG that doesn't work Pin
Alejandro Xalabarder7-Feb-11 13:14
Alejandro Xalabarder7-Feb-11 13:14 
GeneralRe: SVG that doesn't work Pin
Anton Persson25-Feb-11 10:09
Anton Persson25-Feb-11 10:09 
GeneralRe: SVG that doesn't work Pin
diov25-Feb-11 14:15
diov25-Feb-11 14:15 
GeneralLowest Android Version Support? MVO5 Pin
Nic_Roche17-Dec-10 11:28
professionalNic_Roche17-Dec-10 11:28 
GeneralRe: Lowest Android Version Support? MVO5 Pin
diov17-Dec-10 11:55
diov17-Dec-10 11:55 
GeneralRe: Lowest Android Version Support? MVO5 Pin
Nic_Roche30-Dec-10 15:16
professionalNic_Roche30-Dec-10 15:16 
GeneralThank you guys! Pin
diov17-Dec-10 8:39
diov17-Dec-10 8:39 
GeneralMy vote of 5 Pin
RaviRanjanKr17-Dec-10 3:20
professionalRaviRanjanKr17-Dec-10 3:20 
GeneralMy vote of 5 Pin
sam.hill14-Dec-10 5:03
sam.hill14-Dec-10 5:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.