Skip to main content

Convert SVG files to Kotlin Compose ImageVector code with high fidelity and production-ready output

Project description

Svg to Compose-Vector

Convert SVG files to Kotlin Compose ImageVector code with high fidelity and production-ready output.

svg-to-compose-vector is a Python command-line tool that transforms SVG graphics into Compose ImageVector Kotlin code. It supports advanced SVG features including paths, shapes, gradients, transforms, and strokes, generating clean, optimized Compose code.

InstallationUsageFeaturesTemplatesExamples

Features

  • Complete SVG Support: Handles paths, basic shapes (rect, circle, ellipse, line, polygon), groups, transforms, gradients, and strokes
  • High Fidelity Conversion: Mathematically precise shape-to-path conversion with proper coordinate handling
  • Production-Ready Output: Generates clean Kotlin code following Compose best practices with optimal parameter usage
  • Flexible Templates: Built-in templates for different use cases (val declarations, composable functions, icon objects)
  • Advanced Color Support: Full support for hex, RGB, HSL, named colors, and gradients (linear and radial)
  • Smart Optimizations: Uses Compose built-in colors (Color.Red vs Color(0xFFFF0000)) and omits default parameters
  • Comprehensive Error Handling: Clear warnings for unsupported SVG features with graceful degradation
  • Batch Processing: Convert entire directories of SVG files at once

Quick Example

Convert an SVG file to Compose ImageVector code:

svg2compose convert icon.svg

Output:

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

ImageVector.Builder(
  name = "Icon",
  defaultWidth = 24.dp,
  defaultHeight = 24.dp,
  viewportWidth = 24f,
  viewportHeight = 24f,
).apply {
  path(fill = SolidColor(Color.Black)) {
    moveTo(12f, 2f)
    lineTo(22f, 12f)
    lineTo(12f, 22f)
    lineTo(2f, 12f)
    close()
  }
}.build()

Installation

From PyPI (Recommended)

pip install svg-to-compose-vector

From source using uv

git clone https://github.com/chachako/svg-to-compose-vector.git
cd svg-to-compose-vector
uv sync
uv run python -m src.cli --help

From source using pip

git clone https://github.com/chachako/svg-to-compose-vector.git
cd svg-to-compose-vector
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -e .
svg2compose --help

Usage

Basic conversion

# Convert to stdout
svg2compose convert icon.svg

# Convert to file
svg2compose convert icon.svg -o Icon.kt

# Specify icon name
svg2compose convert icon.svg -n HomeIcon

Using templates

# List available templates
svg2compose templates

# Use specific template
svg2compose convert icon.svg -t composable_function -o HomeIcon.kt

# Use custom template file
svg2compose convert icon.svg -t my_template.j2 -o CustomIcon.kt

Batch processing

# Convert all SVG files in a directory
svg2compose batch icons/ output/

# With custom naming pattern
svg2compose batch icons/ output/ --naming "Icon{name}"

# Using specific template
svg2compose batch icons/ output/ -t composable_function

File information

# Show SVG file details
svg2compose info icon.svg

Templates

svg-to-compose-vector provides four built-in templates for different use cases:

1. Default Template (default)

Basic ImageVector.Builder code without wrapper - ideal for embedding in existing code.

Usage:

svg2compose convert icon.svg -t default

Output:

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

ImageVector.Builder(
  name = "Icon",
  defaultWidth = 24.dp,
  defaultHeight = 24.dp,
  viewportWidth = 24f,
  viewportHeight = 24f,
).apply {
  path(fill = SolidColor(Color.Red)) {
    moveTo(12f, 12f)
    lineTo(18f, 12f)
    // ... more path commands
  }
}.build()

2. Val Declaration Template (val_declaration)

Creates a lazy val property - perfect for icon collections and design systems.

Usage:

svg2compose convert home_icon.svg -t val_declaration

Output:

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

val HomeIconIcon: ImageVector = ImageVector.Builder(
  name = "HomeIcon",
  defaultWidth = 24.dp,
  defaultHeight = 24.dp,
  viewportWidth = 24f,
  viewportHeight = 24f,
).apply {
  path(fill = SolidColor(Color.Black)) {
    moveTo(10f, 20f)
    verticalLineTo(14f)
    // ... more path commands
  }
}.build()

3. Composable Function Template (composable_function)

Generates a @Composable function with modifier and tint parameters - ideal for reusable components.

Usage:

svg2compose convert search_icon.svg -t composable_function

Output:

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier

@Composable
fun SearchIconIcon(
  modifier: Modifier = Modifier,
  tint: Color = Color.Unspecified
): ImageVector {
  return remember {
    ImageVector.Builder(
      name = "SearchIcon",
      defaultWidth = 24.dp,
      defaultHeight = 24.dp,
      viewportWidth = 24f,
      viewportHeight = 24f,
    ).apply {
      path(fill = SolidColor(Color.Black)) {
        moveTo(15.5f, 14f)
        horizontalLineTo(14.71f)
        // ... more path commands
      }
    }.build()
  }
}

4. Icon Object Template (icon_object)

Creates an object with a lazy ImageVector property - useful for organized icon libraries.

Usage:

svg2compose convert settings_icon.svg -t icon_object

Output:

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

object SettingsIconIcon {
  val imageVector: ImageVector by lazy {
    ImageVector.Builder(
      name = "SettingsIcon",
      defaultWidth = 24.dp,
      defaultHeight = 24.dp,
      viewportWidth = 24f,
      viewportHeight = 24f,
    ).apply {
      path(fill = SolidColor(Color.Black)) {
        moveTo(19.14f, 12.94f)
        curveTo(19.18f, 12.64f, 19.2f, 12.33f, 19.2f, 12f)
        // ... more path commands
      }
    }.build()
  }
}

Custom Templates

Create powerful custom Jinja2 templates using the complete set of available variables and filters.

Available Template Variables

Variable Type Description Example Value
imports str Formatted import statements import androidx.compose.ui.graphics.Color
build_code str Complete ImageVector.Builder code ImageVector.Builder(...)
name NameComponents Complete name object with all properties See properties below
namespace str Namespace in PascalCase Navigation
icon str Icon name in PascalCase HomeIcon
full_name str Full hierarchical name Navigation.HomeIcon
icon_name str Raw icon name for filters home_icon

NameComponents Properties

The name object provides extensive naming options, for example, if the input is navigation.home-icon.svg:

Property Description Output
name.raw_name Original input name navigation.home-icon
name.name Clean base name home_icon
name.namespace_part Namespace portion navigation
name.name_part Name portion home_icon
name.full_path Complete path navigation.home_icon
name.namespace_part_pascal Namespace in PascalCase Navigation
name.name_part_pascal Name in PascalCase HomeIcon
name.full_path_pascal Full path in PascalCase Navigation.HomeIcon
name.namespace_part_camel Namespace in camelCase navigation
name.name_part_camel Name in camelCase homeIcon
name.full_path_camel Full path in camelCase navigation.homeIcon

Available Filters

Transform any string with built-in filters:

Filter Description Example Usage Input Output
pascal_case Convert to PascalCase {{ "home-icon" | pascal_case }} home-icon HomeIcon
camel_case Convert to camelCase {{ "home-icon" | camel_case }} home-icon homeIcon
snake_case Convert to snake_case {{ "HomeIcon" | snake_case }} HomeIcon home_icon
indent Add indentation {{ build_code | indent(4, first=False) }} Code block Indented code

Template Examples

1. Icon Library with Documentation

{{- imports }}

/**
 * {{ name.name_part_pascal }} icon from {{ name.namespace_part_pascal or "Default" }} category
 * Generated from: {{ name.raw_name }}
 */
val {{ name.name_part_pascal }}Icon: ImageVector by lazy {
  {{ build_code | indent(2, first=False) }}
}
Kotlin Output:
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

/**
 * HomeIcon icon from Navigation category
 * Generated from: navigation.home-icon
 */
 val HomeIconIcon: ImageVector by lazy {
    ImageVector.Builder(
    name = "HomeIcon",
    defaultWidth = 24.dp,
    defaultHeight = 24.dp,
    viewportWidth = 24f,
    viewportHeight = 24f,
    ).apply {
    path(fill = SolidColor(Color.Black)) {
      moveTo(10f, 20f)
      verticalLineTo(14f)
      horizontalLineTo(14f)
      // ... path data
    }
    }.build()
 }

2. Sealed Class Icon System

{{- imports }}

sealed class {{ name.namespace_part_pascal or "Icons" }} {
  object {{ name.name_part_pascal }} : {{ name.namespace_part_pascal or "Icons" }}() {
    val imageVector: ImageVector by lazy {
      {{ build_code | indent(6, first=False) }}
    }
  }
}
Kotlin Output:
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

sealed class Ui {
  object Button : Ui() {
    val imageVector: ImageVector by lazy {
      ImageVector.Builder(
        name = "Button",
        defaultWidth = 24.dp,
        defaultHeight = 24.dp,
        viewportWidth = 24f,
        viewportHeight = 24f,
      ).apply {
        path(fill = SolidColor(Color.Black)) {
          moveTo(2f, 6f)
          curveTo(2f, 4.9f, 2.9f, 4f, 4f, 4f)
          // ... path data
        }
      }.build()
    }
  }
}

3. Composable with Custom Parameters

{{- imports }}
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp

@Composable
fun {{ name.name_part_pascal }}(
  size: Dp = 24.dp,
  tint: Color = Color.Unspecified,
  contentDescription: String? = "{{ name.name_part | replace("_", " ") | title }}"
): ImageVector {
  return remember(size, tint) {
    {{ build_code | indent(4, first=False) }}
  }
}
Kotlin Output:
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.Dp

@Composable
fun SearchIcon(
  size: Dp = 24.dp,
  tint: Color = Color.Unspecified,
  contentDescription: String? = "Search Icon"
): ImageVector {
  return remember(size, tint) {
    ImageVector.Builder(
      name = "SearchIcon",
      defaultWidth = 24.dp,
      defaultHeight = 24.dp,
      viewportWidth = 24f,
      viewportHeight = 24f,
    ).apply {
      path(fill = SolidColor(Color.Black)) {
        moveTo(15.5f, 14f)
        horizontalLineTo(14.71f)
        // ... path data
      }
    }.build()
  }
}

Advanced Usage

Conditional Logic:

{{- imports }}

{% if name.namespace_part %}
// {{ name.namespace_part_pascal }} Category Icons
package com.myapp.icons.{{ name.namespace_part | snake_case }}
{% endif %}

{% if name.namespace_part == "navigation" %}
@NavigationIcon
{% elif name.namespace_part == "action" %}
@ActionIcon
{% endif %}
val {{ name.name_part_pascal }}Icon: ImageVector = {{ build_code }}

Loop Through Categories:

{{- imports }}

// Generated icon path: {{ name.categories | join(" → ") }}
{% for category in name.categories[:-1] %}
// Category: {{ category | pascal_case }}
{% endfor %}
// Icon: {{ name.categories[-1] | pascal_case }}

val {{ name.full_path_pascal | replace(".", "") }}Icon: ImageVector = {{ build_code }}

Using Custom Template:

# Create your template file
svg2compose convert navigation.home.svg -t my_custom_template.j2 -o HomeIcon.kt

# The template receives all the variables and can generate any format you need

Jinja2 Features

All standard Jinja2 features are available:

  • Conditionals: {% if %}, {% elif %}, {% else %}
  • Loops: {% for item in list %}
  • Macros: {% macro %} for reusable code blocks
  • Comments: {# This is a comment #}
  • String operations: {{ string | upper | replace("_", "-") }}

Advanced Examples

Batch processing with templates

Convert multiple SVG files at once with consistent formatting:

# Convert all icons to composable functions
svg2compose batch icons/ src/main/kotlin/icons/ -t composable_function

Input directory structure:

icons/
├── home.svg
├── search.svg
└── settings.svg

Output directory structure:

src/main/kotlin/icons/
├── Home.kt
├── Search.kt
└── Settings.kt

Generated file content (Home.kt):

@Composable
fun HomeIcon(
  modifier: Modifier = Modifier,
  tint: Color = Color.Unspecified
): ImageVector {
  return remember {
    ImageVector.Builder(
      name = "Home",
      defaultWidth = 24.dp,
      defaultHeight = 24.dp,
      viewportWidth = 24f,
      viewportHeight = 24f,
    ).apply {
      path(fill = SolidColor(Color.Black)) {
        moveTo(10f, 20f)
        verticalLineTo(14f)
        horizontalLineTo(14f)
        // ... more path commands
      }
    }.build()
  }
}

Complex SVG with gradients and transforms

svg2compose convert complex_icon.svg -t composable_function

Automatically handles gradients and transforms:

@Composable
fun ComplexIcon(): ImageVector {
  return remember {
    ImageVector.Builder(
      name = "ComplexIcon",
      defaultWidth = 48.dp,
      defaultHeight = 48.dp,
      viewportWidth = 48f,
      viewportHeight = 48f,
    ).apply {
      group(
        name = "rotated-group",
        rotate = 45f,
        pivotX = 24f,
        pivotY = 24f,
      ) {
        path(
          fill = Brush.linearGradient(
            colorStops = arrayOf(
              0f to Color.Red,
              0.5f to Color.Yellow,
              1f to Color.Blue,
            ),
            start = Offset(0f, 0f),
            end = Offset(48f, 48f),
          ),
        ) {
          // path data...
        }
      }
    }.build()
  }
}

Supported SVG Features

Feature Support Notes
Paths ✅ Complete All path commands (M, L, C, A, Z, etc.)
Basic Shapes ✅ Complete rect, circle, ellipse, line, polygon, polyline
Groups & Transforms ✅ Complete translate, scale, rotate, matrix decomposition
Colors ✅ Complete hex, rgb, hsl, named colors with alpha support
Gradients ✅ Complete Linear and radial gradients with multiple stops
Strokes ✅ Complete Width, opacity, caps, joins, gradient strokes
ClipPath ✅ Basic Simple clipPath support for groups
Text ⚠️ Warning Text elements not supported by Compose ImageVector
Filters ⚠️ Warning Filter effects not supported by Compose ImageVector
Animations ⚠️ Warning Animation elements not supported (static conversion only)

Configuration

Use configuration files for consistent settings across projects:

{
  "template": "composable_function",
  "indent_size": 2,
  "use_named_colors": true,
  "optimize_output": true
}
svg2compose convert icon.svg -c config.json

Development

git clone https://github.com/chachako/svg-to-compose-vector.git
cd svg-to-compose-vector

# Setup development environment
uv sync --dev

# Run tests
uv run pytest

# Code formatting and linting
uv run ruff check
uv run ruff format

Requirements

  • Python 3.13+
  • Dependencies: jinja2, click (automatically installed)

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Acknowledgments

This project was inspired by the Valkyrie project.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

svg_to_compose_vector-0.1.6.tar.gz (39.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

svg_to_compose_vector-0.1.6-py3-none-any.whl (45.8 kB view details)

Uploaded Python 3

File details

Details for the file svg_to_compose_vector-0.1.6.tar.gz.

File metadata

  • Download URL: svg_to_compose_vector-0.1.6.tar.gz
  • Upload date:
  • Size: 39.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for svg_to_compose_vector-0.1.6.tar.gz
Algorithm Hash digest
SHA256 deba770f9de558aa9a01c01f99c0c7f3a7ac66baef130b3801531a4f615066c4
MD5 9a33b5abd1791991727131981a1c7fea
BLAKE2b-256 f98460ccdaa5c382011f7556794eb36eadb48b7729a98b919638cf6d14118682

See more details on using hashes here.

File details

Details for the file svg_to_compose_vector-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for svg_to_compose_vector-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 6e3f2c711f39d655cf295a61709dda5c92ba93015a4947b18034d701a15efc6d
MD5 248a69c5c60a2598f9707bcb95063bea
BLAKE2b-256 64325d47b08e644c504e60bafb5d59420f68b5ed124bb2266bb2fe4e0484878d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page