Skip to content

Commit

Permalink
Adding image manipulation preprocessor
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejmalecki authored May 13, 2023
1 parent 395b9e6 commit e242f75
Show file tree
Hide file tree
Showing 42 changed files with 1,818 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
allprojects {

group = "com.github.c64lib"
version = "1.6.0"
version = "1.7.0"

if (project.hasProperty(tagPropertyName)) {
version = project.property(tagPropertyName) ?: version
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/rbt.kotlin.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation("io.vavr:vavr-kotlin:0.10.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.7.0")
testImplementation("io.kotest:kotest-runner-junit5:4.5.0")
testImplementation("org.mockito:mockito-core:3.11.2")
}

tasks.withType<Test> { useJUnitPlatform() }
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ vavrVersion = 1.0.0-alpha-3
vavrKotlinVersion = 0.10.2
kotestVersion = 4.5.0
junitVersion = 5.7.0
pngjVersion = 2.1.0
19 changes: 19 additions & 0 deletions infra/gradle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ val kotlinVersion: String by project
val vavrVersion: String by project
val vavrKotlinVersion: String by project
val gradleDownloadTaskVersion: String by project
val pngjVersion: String by project
val tagPropertyName = "tag"


plugins {
id("rbt.kotlin")
id("java-gradle-plugin")
Expand All @@ -13,6 +15,15 @@ plugins {

group = "com.github.c64lib.retro-assembler"

configurations {
// Create a new configuration that extends from 'implementation'
create("resolvableImplementation") {
extendsFrom(project.configurations.implementation.get())
isCanBeResolved = true
}
}


tasks {
val copySubProjectClasses by
register("copySubProjectClasses") {
Expand All @@ -25,6 +36,8 @@ group = "com.github.c64lib.retro-assembler"
.filter { it.moduleGroup.startsWith(project.group.toString()) }
.flatMap { it.moduleArtifacts }
.map { it.file.parentFile.parentFile }


copy {
from(localDependencies)
into(buildDir)
Expand Down Expand Up @@ -62,6 +75,7 @@ dependencies {
implementation(gradleApi())
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
implementation("io.vavr:vavr:$vavrVersion")
implementation("ar.com.hjg:pngj:$pngjVersion")

compileOnly(project(":shared:domain"))
compileOnly(project(":shared:gradle"))
Expand Down Expand Up @@ -93,6 +107,11 @@ dependencies {

compileOnly(project(":processors:charpad"))
compileOnly(project(":processors:charpad:adapters:in:gradle"))

compileOnly(project(":processors:image"))
compileOnly(project(":processors:image:adapters:in:gradle"))
compileOnly(project(":processors:image:adapters:out:png"))
compileOnly(project(":processors:image:adapters:out:file"))
}

publishing { repositories { maven { url = uri("../../../consuming/maven-repo") } } }
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ import com.github.c64lib.rbt.processors.charpad.adapters.`in`.gradle.Charpad
import com.github.c64lib.rbt.processors.goattracker.adapters.`in`.gradle.Goattracker
import com.github.c64lib.rbt.processors.goattracker.adapters.out.gradle.ExecuteGt2RelocAdapter
import com.github.c64lib.rbt.processors.goattracker.usecase.PackSongUseCase
import com.github.c64lib.rbt.processors.image.adapters.`in`.gradle.ProcessImage
import com.github.c64lib.rbt.processors.image.adapters.out.file.C64CharsetWriter
import com.github.c64lib.rbt.processors.image.adapters.out.file.C64SpriteWriter
import com.github.c64lib.rbt.processors.image.adapters.out.png.ReadPngImageAdapter
import com.github.c64lib.rbt.processors.image.usecase.CutImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.ExtendImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.ReadSourceImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.SplitImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.WriteImageUseCase
import com.github.c64lib.rbt.processors.spritepad.adapters.`in`.gradle.Spritepad
import com.github.c64lib.rbt.shared.domain.SemVer
import com.github.c64lib.rbt.shared.filedownload.FileDownloader
Expand All @@ -63,6 +72,7 @@ import com.github.c64lib.rbt.shared.gradle.TASK_CHARPAD
import com.github.c64lib.rbt.shared.gradle.TASK_CLEAN
import com.github.c64lib.rbt.shared.gradle.TASK_DEPENDENCIES
import com.github.c64lib.rbt.shared.gradle.TASK_GOATTRACKER
import com.github.c64lib.rbt.shared.gradle.TASK_IMAGE
import com.github.c64lib.rbt.shared.gradle.TASK_PREPROCESS
import com.github.c64lib.rbt.shared.gradle.TASK_RESOLVE_DEV_DEPENDENCIES
import com.github.c64lib.rbt.shared.gradle.TASK_SPRITEPAD
Expand Down Expand Up @@ -123,9 +133,19 @@ class RetroAssemblerPlugin : Plugin<Project> {
task.preprocessingExtension = preprocessExtension
task.packSongUseCase = PackSongUseCase(ExecuteGt2RelocAdapter(project))
}
val image =
project.tasks.create(TASK_IMAGE, ProcessImage::class.java) { task ->
task.preprocessingExtension = preprocessExtension
task.readSourceImageUseCase = ReadSourceImageUseCase(ReadPngImageAdapter())
task.writeImageUseCase =
WriteImageUseCase(C64SpriteWriter(project), C64CharsetWriter(project))
task.cutImageUseCase = CutImageUseCase()
task.extendImageUseCase = ExtendImageUseCase()
task.splitImageUseCase = SplitImageUseCase()
}
val preprocess = project.tasks.create(TASK_PREPROCESS, Preprocess::class.java)

preprocess.dependsOn(charpad, spritepad, goattracker)
preprocess.dependsOn(charpad, spritepad, goattracker, image)

// TODO Somehow, the ResolveDevDeps should give the settings. How!?
val settings =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,24 @@ open class Goattracker : DefaultTask() {
@Internal lateinit var packSongUseCase: PackSongUseCase

@TaskAction
fun process() {
preprocessingExtension.goattrackerPipelines.forEach { pipeline ->
pipeline.outputs.forEach { output ->
packSongUseCase.apply(
PackSongCommand(
source = pipeline.getInput().get(),
output = output.getOutput().get(),
executable = output.executable,
useBuildDir = pipeline.getUseBuildDir().getOrElse(false),
bufferedSidWrites = output.bufferedSidWrites,
disableOptimization = output.disableOptimization,
playerMemoryLocation = output.playerMemoryLocation,
sfxSupport = output.sfxSupport,
sidMemoryLocation = output.sidMemoryLocation,
storeAuthorInfo = output.storeAuthorInfo,
volumeChangeSupport = output.volumeChangeSupport,
zeroPageLocation = output.zeroPageLocation,
zeropageGhostRegisters = output.zeropageGhostRegisters))
fun process() =
preprocessingExtension.goattrackerPipelines.forEach { pipeline ->
pipeline.outputs.forEach { output ->
packSongUseCase.apply(
PackSongCommand(
source = pipeline.getInput().get(),
output = output.getOutput().get(),
executable = output.executable,
useBuildDir = pipeline.getUseBuildDir().getOrElse(false),
bufferedSidWrites = output.bufferedSidWrites,
disableOptimization = output.disableOptimization,
playerMemoryLocation = output.playerMemoryLocation,
sfxSupport = output.sfxSupport,
sidMemoryLocation = output.sidMemoryLocation,
storeAuthorInfo = output.storeAuthorInfo,
volumeChangeSupport = output.volumeChangeSupport,
zeroPageLocation = output.zeroPageLocation,
zeropageGhostRegisters = output.zeropageGhostRegisters))
}
}
}
}
}
14 changes: 14 additions & 0 deletions processors/image/adapters/in/gradle/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
id("rbt.adapter.inbound.gradle")
}

group = "com.github.c64lib.retro-assembler.processors.image.adapters.in"

dependencies {
implementation(project(":processors:image"))
implementation(project(":shared:domain"))
implementation(project(":shared:gradle"))
implementation(project(":shared:binary-utils"))
implementation(project(":shared:processor"))
implementation(project(":shared:domain"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
MIT License
Copyright (c) 2018-2023 c64lib: The Ultimate Commodore 64 Library
Copyright (c) 2018-2023 Maciej Małecki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package com.github.c64lib.rbt.processors.image.adapters.`in`.gradle

import com.github.c64lib.rbt.processors.image.domain.Image
import com.github.c64lib.rbt.processors.image.usecase.CutImageCommand
import com.github.c64lib.rbt.processors.image.usecase.CutImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.ExtendImageCommand
import com.github.c64lib.rbt.processors.image.usecase.ExtendImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.ReadSourceImageCommand
import com.github.c64lib.rbt.processors.image.usecase.ReadSourceImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.SplitImageCommand
import com.github.c64lib.rbt.processors.image.usecase.SplitImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.WriteImageCommand
import com.github.c64lib.rbt.processors.image.usecase.WriteImageUseCase
import com.github.c64lib.rbt.processors.image.usecase.WriteMethod
import com.github.c64lib.rbt.shared.domain.Color
import com.github.c64lib.rbt.shared.gradle.GROUP_BUILD
import com.github.c64lib.rbt.shared.gradle.dsl.ImageCutExtension
import com.github.c64lib.rbt.shared.gradle.dsl.ImageExtendExtension
import com.github.c64lib.rbt.shared.gradle.dsl.ImageSplitExtension
import com.github.c64lib.rbt.shared.gradle.dsl.ImageTransformationExtension
import com.github.c64lib.rbt.shared.gradle.dsl.PreprocessingExtension
import java.io.File
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction

open class ProcessImage : DefaultTask() {

init {
description = "Processes PNG Image and convert it into hardware or software sprite shape(s)."
group = GROUP_BUILD
}

@Input lateinit var preprocessingExtension: PreprocessingExtension

@Internal lateinit var readSourceImageUseCase: ReadSourceImageUseCase

@Internal lateinit var writeImageUseCase: WriteImageUseCase

@Internal lateinit var cutImageUseCase: CutImageUseCase

@Internal lateinit var extendImageUseCase: ExtendImageUseCase

@Internal lateinit var splitImageUseCase: SplitImageUseCase

@TaskAction
fun process() =
preprocessingExtension.imagePipelines.forEach { pipeline ->
val inputFile = requireNotNull(pipeline.getInput().get())
val image = readSourceImageUseCase.apply(ReadSourceImageCommand(inputFile))
process(arrayOf(image), pipeline, pipeline.getUseBuildDir().get() ?: true)
}

private fun process(
images: Array<Image>,
extension: ImageTransformationExtension,
useBuildDir: Boolean
) {

val postImages: Array<Image> =
images
.flatMap {
when (extension) {
is ImageCutExtension ->
listOf(
cutImageUseCase.apply(
CutImageCommand(
image = it,
left = extension.left,
top = extension.top,
width = extension.width ?: (it.width - extension.left),
height = extension.height ?: (it.height - extension.top),
),
),
)
is ImageExtendExtension ->
listOf(
extendImageUseCase.apply(
ExtendImageCommand(
image = it,
newWidth = extension.newWidth ?: it.width,
newHeight = extension.newHeight ?: it.height,
fillColor = extension.fillColor ?: Color(0, 0, 0, 255)),
),
)
is ImageSplitExtension ->
splitImageUseCase
.apply(
SplitImageCommand(
image = it,
subImageWidth = extension.width ?: it.width,
subImageHeight = extension.height ?: it.height,
),
)
.toList()
else -> listOf(it)
}
}
.toTypedArray()

extension.cut?.let { process(postImages, it, useBuildDir) }
extension.split?.let { process(postImages, it, useBuildDir) }
extension.extend?.let { process(postImages, it, useBuildDir) }

extension.spriteWriter?.let {
postImages.forEachIndexed { i, image ->
writeImageUseCase.apply(
WriteImageCommand(
image,
WriteMethod.SPRITE,
toIndexedName(it.getOutput().get(), i, images),
useBuildDir),
)
}
}

extension.bitmapWriter?.let {
postImages.forEachIndexed { i, image ->
writeImageUseCase.apply(
WriteImageCommand(
image,
WriteMethod.BITMAP,
toIndexedName(it.getOutput().get(), i, images),
useBuildDir),
)
}
}
}

private fun toIndexedName(file: File, index: Int, array: Array<Image>): File =
when (array.size) {
1 -> file
0 -> throw GradleException("No images to process")
else -> File(file.parent, "${file.nameWithoutExtension}_${index}.${file.extension}")
}
}
11 changes: 11 additions & 0 deletions processors/image/adapters/out/file/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("rbt.adapter.outbound.gradle")
}

group = "com.github.c64lib.retro-assembler.processors.image"

dependencies {
implementation(project(":processors:image"))
implementation(project(":shared:domain"))
implementation(project(":shared:gradle"))
}
Loading

0 comments on commit e242f75

Please sign in to comment.