Click here to Skip to main content
15,897,291 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 155.6K   5.7K   33  
This article introduces custom classes SvgImageView and SvgDrawable which allow to use SVG image just like any other image.
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.3
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software 
// is granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PATH_RENDERER_INCLUDED
#define AGG_SVG_PATH_RENDERER_INCLUDED

#include "agg_path_storage.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_conv_contour.h"
#include "agg_conv_curve.h"
#include "agg_color_rgba.h"
#include "agg_renderer_scanline.h"
#include "agg_bounding_rect.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_svg_path_tokenizer.h"

namespace agg
{
namespace svg
{
    template<class VertexSource> class conv_count
    {
    public:
        conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {}

        void count(unsigned n) { m_count = n; }
        unsigned count() const { return m_count; }

        void rewind(unsigned path_id) { m_source->rewind(path_id); }
        unsigned vertex(double* x, double* y) 
        { 
            ++m_count; 
            return m_source->vertex(x, y); 
        }

    private:
        VertexSource* m_source;
        unsigned m_count;
    };




    //============================================================================
    // Basic path attributes
    struct path_attributes
    {
        unsigned     index;
        rgba8        fill_color;
        rgba8        stroke_color;
        bool         fill_flag;
        bool         stroke_flag;
        bool         even_odd_flag;
        line_join_e  line_join;
        line_cap_e   line_cap;
        double       miter_limit;
        double       stroke_width;
        trans_affine transform;

        // Empty constructor
        path_attributes() :
            index(0),
            fill_color(rgba(0,0,0)),
            stroke_color(rgba(0,0,0)),
            fill_flag(true),
            stroke_flag(false),
            even_odd_flag(false),
            line_join(miter_join),
            line_cap(butt_cap),
            miter_limit(4.0),
            stroke_width(1.0),
            transform()
        {
        }

        // Copy constructor
        path_attributes(const path_attributes& attr) :
            index(attr.index),
            fill_color(attr.fill_color),
            stroke_color(attr.stroke_color),
            fill_flag(attr.fill_flag),
            stroke_flag(attr.stroke_flag),
            even_odd_flag(attr.even_odd_flag),
            line_join(attr.line_join),
            line_cap(attr.line_cap),
            miter_limit(attr.miter_limit),
            stroke_width(attr.stroke_width),
            transform(attr.transform)
        {
        }

        // Copy constructor with new index value
        path_attributes(const path_attributes& attr, unsigned idx) :
            index(idx),
            fill_color(attr.fill_color),
            stroke_color(attr.stroke_color),
            fill_flag(attr.fill_flag),
            stroke_flag(attr.stroke_flag),
            even_odd_flag(attr.even_odd_flag),
            line_join(attr.line_join),
            line_cap(attr.line_cap),
            miter_limit(attr.miter_limit),
            stroke_width(attr.stroke_width),
            transform(attr.transform)
        {
        }
    };


    //============================================================================
    // Path container and renderer. 
    class path_renderer
    {
    public:
        typedef pod_bvector<path_attributes>   attr_storage;

        typedef conv_curve<path_storage>       curved;
        typedef conv_count<curved>             curved_count;

        typedef conv_stroke<curved_count>      curved_stroked;
        typedef conv_transform<curved_stroked> curved_stroked_trans;

        typedef conv_transform<curved_count>   curved_trans;
        typedef conv_contour<curved_trans>     curved_trans_contour;

        path_renderer();

        void remove_all();

        // Use these functions as follows:
        // begin_path() when the XML tag <path> comes ("start_element" handler)
        // parse_path() on "d=" tag attribute
        // end_path() when parsing of the entire tag is done.
        void begin_path();
        void parse_path(path_tokenizer& tok);
        void end_path();

        // The following functions are essentially a "reflection" of
        // the respective SVG path commands.
        void move_to(double x, double y, bool rel=false);   // M, m
        void line_to(double x,  double y, bool rel=false);  // L, l
        void hline_to(double x, bool rel=false);            // H, h
        void vline_to(double y, bool rel=false);            // V, v
        void curve3(double x1, double y1,                   // Q, q
                    double x,  double y, bool rel=false);
        void curve3(double x, double y, bool rel=false);    // T, t
        void curve4(double x1, double y1,                   // C, c
                    double x2, double y2, 
                    double x,  double y, bool rel=false);
        void curve4(double x2, double y2,                   // S, s
                    double x,  double y, bool rel=false);
        void close_subpath();                               // Z, z

//        template<class VertexSource> 
//        void add_path(VertexSource& vs, 
//                      unsigned path_id = 0, 
//                      bool solid_path = true)
//        {
//            m_storage.add_path(vs, path_id, solid_path);
//        }


        unsigned vertex_count() const { return m_curved_count.count(); }
        

        // Call these functions on <g> tag (start_element, end_element respectively)
        void push_attr();
        void pop_attr();

        // Attribute setting functions.
        void fill(const rgba8& f);
        void stroke(const rgba8& s);
        void even_odd(bool flag);
        void stroke_width(double w);
        void fill_none();
        void stroke_none();
        void fill_opacity(double op);
        void stroke_opacity(double op);
        void line_join(line_join_e join);
        void line_cap(line_cap_e cap);
        void miter_limit(double ml);
        trans_affine& transform();

        // Make all polygons CCW-oriented
        void arrange_orientations()
        {
            m_storage.arrange_orientations_all_paths(path_flags_ccw);
        }

        // Expand all polygons 
        void expand(double value)
        {
            m_curved_trans_contour.width(value);
        }

        unsigned operator [](unsigned idx)
        {
            m_transform = m_attr_storage[idx].transform;
            return m_attr_storage[idx].index;
        }

        void bounding_rect(double* x1, double* y1, double* x2, double* y2)
        {
            agg::conv_transform<agg::path_storage> trans(m_storage, m_transform);
            agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2);
        }

        // Rendering. One can specify two additional parameters: 
        // trans_affine and opacity. They can be used to transform the whole
        // image and/or to make it translucent.
        template<class Rasterizer, class Scanline, class Renderer> 
        void render(Rasterizer& ras, 
                    Scanline& sl,
                    Renderer& ren, 
                    const trans_affine& mtx, 
                    const rect_i& cb,
                    double opacity=1.0)
        {
            unsigned i;

            ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2);
            m_curved_count.count(0);

            for(i = 0; i < m_attr_storage.size(); i++)
            {
                const path_attributes& attr = m_attr_storage[i];
                m_transform = attr.transform;
                m_transform *= mtx;
                double scl = m_transform.scale();
                //m_curved.approximation_method(curve_inc);
                m_curved.approximation_scale(scl);
                m_curved.angle_tolerance(0.0);

                rgba8 color;

                if(attr.fill_flag)
                {
                    ras.reset();
                    ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
                    if(fabs(m_curved_trans_contour.width()) < 0.0001)
                    {
                        ras.add_path(m_curved_trans, attr.index);
                    }
                    else
                    {
                        m_curved_trans_contour.miter_limit(attr.miter_limit);
                        ras.add_path(m_curved_trans_contour, attr.index);
                    }

                    color = attr.fill_color;
                    color.opacity(color.opacity() * opacity);
                    ren.color(color);
                    agg::render_scanlines(ras, sl, ren);
                }

                if(attr.stroke_flag)
                {
                    m_curved_stroked.width(attr.stroke_width);
                    //m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
                    m_curved_stroked.line_join(attr.line_join);
                    m_curved_stroked.line_cap(attr.line_cap);
                    m_curved_stroked.miter_limit(attr.miter_limit);
                    m_curved_stroked.inner_join(inner_round);
                    m_curved_stroked.approximation_scale(scl);

                    // If the *visual* line width is considerable we 
                    // turn on processing of curve cusps.
                    //---------------------
                    if(attr.stroke_width * scl > 1.0)
                    {
                        m_curved.angle_tolerance(0.2);
                    }
                    ras.reset();
                    ras.filling_rule(fill_non_zero);
                    ras.add_path(m_curved_stroked_trans, attr.index);
                    color = attr.stroke_color;
                    color.opacity(color.opacity() * opacity);
                    ren.color(color);
                    agg::render_scanlines(ras, sl, ren);
                }
            }
        }

    private:
        path_attributes& cur_attr();

        path_storage   m_storage;
        attr_storage   m_attr_storage;
        attr_storage   m_attr_stack;
        trans_affine   m_transform;

        curved                       m_curved;
        curved_count                 m_curved_count;

        curved_stroked               m_curved_stroked;
        curved_stroked_trans         m_curved_stroked_trans;

        curved_trans                 m_curved_trans;
        curved_trans_contour         m_curved_trans_contour;
    };

}
}

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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