Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use android tools for SVG to Vector Drawable conversion #47

Merged
merged 22 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ jobs:
id: properties
shell: bash
run: |
cat changelog.md
PROPERTIES="$(./gradlew properties --console=plain -q)"
VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
CHANGELOG="${CHANGELOG//'%'/'%25'}"
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
echo "::set-output name=version::$VERSION"
echo "::set-output name=changelog::$CHANGELOG"

echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: build
run: ./gradlew build
Expand Down
23 changes: 20 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: 21
distribution: zulu

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
Expand All @@ -42,11 +43,27 @@ jobs:
SONATYPE_PROFILE_ID: ${{ secrets.SONATYPE_PROFILE_ID }}
run: ./gradlew -Psigning.keyId=${{ secrets.SIGNING_KEY_ID}} -Psigning.password=${{ secrets.SIGNING_KEY_PASSWORD }} -Psigning.secretKeyRingFile=${{ secrets.SIGNING_KEY_FILE_PATH }} --no-configuration-cache publishAndReleaseToMavenCentral

- name: Patch Changelog
# Set environment variables
- name: Export Properties
id: properties
shell: bash
run: |
./gradlew patchChangelog --release-note="`cat << EOM
CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d'
${{ github.event.release.body }}
EOM`"
EOM
)"

echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

# Update Unreleased section with the current release note
- name: Patch Changelog
if: ${{ steps.properties.outputs.changelog != '' }}
env:
CHANGELOG: ${{ steps.properties.outputs.changelog }}
run: |
./gradlew patchChangelog --release-note="$CHANGELOG"

- name: Open PR for Changelog Update
env:
Expand Down
8 changes: 2 additions & 6 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.changelog.date
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jlleitschuh.gradle.ktlint.KtlintExtension
Expand All @@ -14,6 +13,8 @@ plugins {

version = property("VERSION_NAME").toString()

changelog.path.set("changelog.md")

subprojects {
apply<KtlintPlugin>()
configure<KtlintExtension> {
Expand Down Expand Up @@ -84,8 +85,3 @@ subprojects {
)
}
}

changelog {
header.set(provider { "${version.get()}\n_${date()}_\n" })
groups.set(listOf("New", "Improvement", "Fix", "Upgrade"))
}
57 changes: 14 additions & 43 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,27 @@

## Unreleased

### New
- Use Android Studio conversion tools are used for SVG → vector drawable conversions
### Added

### Improvement
- More robust SVG → vector conversions by Android Studio tools

### Fix

### Upgrade

## 2.1.0

_09-14-2021_
## 2.1.0 - 09-14-2021

- New: Simplified optimization machinery with `ElementVisitor`
- Improvement: `MergePaths` no longer requires its own tree traversal
- Improvement: Attribute values omit leading zeros where possible
- Fix: theme referenced colors like `?attrs/dark` no longer cause crashes
- Upgrade: Build tools

## 2.0.2

_06.02.2021_
## 2.0.2 - 06.02.2021

- Fixed: Vector Drawable shorthand hex colors (like #FFF) are properly handled

## 2.0.1

_06.01.2021_
## 2.0.1 - 06.01.2021

- Fixed: Groups that wrap clip paths are no longer removed

## 2.0.0

_05.29.2021_
## 2.0.0 - 05.29.2021

- New, breaking(vgo-core): Structured graphic element attributes.
* This greatly simplifies the conversions between formats
Expand All @@ -48,59 +35,43 @@ _05.29.2021_
- Fixed: Test failures on Windows due to path handling
- Upgrade: Build with Kotlin 1.5.10

## 1.4.1

_02.16.2021_
## 1.4.1 - 02.16.2021

- Added: A new type for the `shrinkVectorArtwork` task

## 1.4.0

_02.15.2021_
## 1.4.0 - 02.15.2021

- Added: Gradle plugin
- Improved: Reworked the gradle modules to better be published as a library (vgo-core) and thin application wrapper (vgo).
- Added: Sonatype publishing

## 1.3.0

_01.18.2021_
## 1.3.0 - 01.18.2021

- Added: Collapse multiple Bézier curves into elliptical arcs when possible
- Improvement: Target JVM 11

## 1.2.2

_10.20.2020_
## 1.2.2 - 10.20.2020

- Improvement: Show filenames with statistics with multiple file inputs and `--stats`
- Improvement: Remove Kotlin metadata from the output jar
- Fixed: Temporarily removed an optimization that distorted some images

## 1.2.1

_10.01.2020_
## 1.2.1 - 10.01.2020

- Fixed: Some images with curves that lie on a circle omit any representation of that circle in the output
- Fixed: Modifying files in-place sometimes results in destroying non-vector files.

## 1.2.0

_09.28.2020_
## 1.2.0 - 09.28.2020

- Improvement: Resort to distribution via a fat jar. Requires managing fewer files and results in a smaller installation since R8 can operate on classes from dependencies as well.
- Improvement: Use R8 for optimization. R8 produces a slightly smaller jar and in some cases faster code as well.

## 1.1.1

_07.13.2020_
## 1.1.1 - 07.13.2020

- Fixed: A crash when running on a file in the current directory
- Improvement: Report an error when an input file doesn't exist

## 1.1.0

_06.20.2020_
## 1.1.0 - 06.20.2020

- New: Remove redundant close path commands
- Improvement: Use the Gradle Application Plugin to build application distrobutions, simplifying installation and making running the tool a little simpler.
18 changes: 13 additions & 5 deletions vgo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ plugins {
id("com.vanniktech.maven.publish")
}

sourceSets {
main {
java.srcDirs("src/generated/kotlin")
}
}
kotlin.sourceSets.getByName("main").kotlin.srcDir("src/generated/kotlin")

val r8: Configuration by configurations.creating

dependencies {
implementation(project(":vgo-core"))
implementation("com.android.tools:sdk-common:31.5.1")

testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.28.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
Expand Down Expand Up @@ -55,6 +52,17 @@ tasks {
"**/module-info.class",
"META-INF/maven/**",
"META-INF/*.version",
"META-INF/LICENSE*",
"META-INF/LGPL2.1",
"META-INF/DEPENDENCIES",
"META-INF/AL2.0",
"META-INF/BCKEY.DSA",
"META-INF/BC2048KE.DSA",
"META-INF/BCKEY.SF",
"META-INF/BC2048KE.SF",
"**/NOTICE*",
"javax/activation/**",
"xsd/catalog.xml",
)
}
}
Expand Down
62 changes: 45 additions & 17 deletions vgo/src/main/kotlin/com/jzbrooks/vgo/Application.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package com.jzbrooks.vgo

import com.android.ide.common.vectordrawable.Svg2Vector
import com.jzbrooks.BuildConstants
import com.jzbrooks.vgo.core.Writer
import com.jzbrooks.vgo.svg.ScalableVectorGraphic
import com.jzbrooks.vgo.svg.ScalableVectorGraphicWriter
import com.jzbrooks.vgo.svg.SvgOptimizationRegistry
import com.jzbrooks.vgo.svg.parse
import com.jzbrooks.vgo.svg.toVectorDrawable
import com.jzbrooks.vgo.util.xml.asSequence
import com.jzbrooks.vgo.vd.VectorDrawable
import com.jzbrooks.vgo.vd.VectorDrawableOptimizationRegistry
import com.jzbrooks.vgo.vd.VectorDrawableWriter
import com.jzbrooks.vgo.vd.toSvg
import org.w3c.dom.Document
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import javax.xml.parsers.DocumentBuilderFactory
import kotlin.math.absoluteValue
Expand Down Expand Up @@ -63,11 +65,11 @@ class Application {
if (inputs.isEmpty()) {
require(outputs.isEmpty())

var path = readLine()
var path = readlnOrNull()
val standardInPaths = mutableListOf<String>()
while (path != null) {
standardInPaths.add(path)
path = readLine()
path = readlnOrNull()
}

inputs = standardInPaths
Expand Down Expand Up @@ -139,30 +141,54 @@ class Application {
input.inputStream().use { inputStream ->
val sizeBefore = inputStream.channel.size()

val document =
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input).apply {
documentElement.normalize()
}
val document = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(input)
document.documentElement.normalize()

val rootNodes = document.childNodes.asSequence().filter { it.nodeType == Document.ELEMENT_NODE }.toList()

var graphic =
when {
rootNodes.any { it.nodeName == "svg" || input.extension == "svg" } -> parse(rootNodes.first())
rootNodes.any { it.nodeName == "vector" && input.extension == "xml" } ->
com.jzbrooks.vgo.vd.parse(
rootNodes.first(),
)
rootNodes.any { it.nodeName == "svg" || input.extension == "svg" } -> {
if (outputFormat == "vd") {
ByteArrayOutputStream().use { pipeOrigin ->
val errors = Svg2Vector.parseSvgToXml(input.toPath(), pipeOrigin)
if (errors != "") {
System.err.println(
"""
Skipping ${input.path}

$errors
""".trimIndent(),
)
null
} else {
val pipeTerminal = ByteArrayInputStream(pipeOrigin.toByteArray())
val convertedDocument =
DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(pipeTerminal)
convertedDocument.documentElement.normalize()

val documentRoot =
convertedDocument.childNodes.asSequence().first {
it.nodeType == Document.ELEMENT_NODE
}

com.jzbrooks.vgo.vd.parse(documentRoot)
}
}
} else {
parse(rootNodes.first())
}
}
rootNodes.any { it.nodeName == "vector" && input.extension == "xml" } -> {
com.jzbrooks.vgo.vd.parse(rootNodes.first())
}
else -> if (input == output) return else null
}

if (graphic is VectorDrawable && outputFormat == "svg") {
graphic = graphic.toSvg()
}

if (graphic is ScalableVectorGraphic && outputFormat == "vd") {
graphic = graphic.toVectorDrawable()
}

val optimizationRegistry =
when (graphic) {
is VectorDrawable -> VectorDrawableOptimizationRegistry()
Expand Down Expand Up @@ -217,9 +243,10 @@ class Application {
assert(input.isDirectory)
assert(output.isDirectory || !output.exists())

input.listFiles { file -> !file.isHidden }?.forEach { file ->
for (file in input.walkTopDown().filter { file -> !file.isHidden && !file.isDirectory }) {
handleFile(file, File(output, file.name), options)
}

if (printStats) {
val message = "| Total bytes saved: ${(totalBytesBefore - totalBytesAfter).roundToInt()} |"
val border = "-".repeat(message.length)
Expand Down Expand Up @@ -262,6 +289,7 @@ class Application {
get() = key.isDirectory && (value.isDirectory || !value.exists())

companion object {
private val DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance()
private const val HELP_MESSAGE = """
> vgo [options] [file/directory]

Expand Down