Skip to content

Commit

Permalink
refactoring so that the imageprinter knows about the color palette
Browse files Browse the repository at this point in the history
  • Loading branch information
patbeagan1 committed Nov 5, 2022
1 parent d677469 commit 1d92d43
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dev.patbeagan.consolevision

import dev.patbeagan.consolevision.imagefilter.ImageFilter
import java.awt.image.BufferedImage

inline fun BufferedImage.withLine(
onLineEnd: () -> Unit = {},
action: (Int, Int) -> Unit,
) {
(minY until height).forEach { y ->
(minX until width).forEach { x -> action(y, x) }
onLineEnd()
}
}

fun BufferedImage.applyFilter(imageFilter: ImageFilter) {
imageFilter(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,28 @@ class ConsoleVisionRuntime(
config: Config
) {

data class Config(
val reductionRate: Int,
val paletteReductionRate: Int,
val isCompatPalette: Boolean,
val shouldNormalize: Boolean,
val shouldMutateColors: Boolean = false
)

private val paletteColors: ColorPalette? =
paletteImage?.createColorPalette(config.paletteReductionRate)
private val paletteColors: ColorPalette? = paletteImage
?.createColorPalette(config.paletteReductionRate)

private val imagePrinter = ImagePrinter(
config.reductionRate,
ColorMapToAnsi(config.isCompatPalette),
config.shouldNormalize,
config.shouldMutateColors
config.shouldMutateColors,
paletteColors,
)

fun printFrame(file: BufferedImage): String {
// // todo make this an option
// print(CURSOR_TO_START)
return imagePrinter.getFrame(
file,
paletteColors
)
return imagePrinter.getFrame(file)
}

data class Config(
val reductionRate: Int,
val paletteReductionRate: Int,
val isCompatPalette: Boolean,
val shouldNormalize: Boolean,
val shouldMutateColors: Boolean = false
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import dev.patbeagan.consolevision.ansi.AnsiColor
import dev.patbeagan.consolevision.ansi.StyleExtensions.style
import dev.patbeagan.consolevision.imagefilter.ColorMutation
import dev.patbeagan.consolevision.imagefilter.ColorNormalization
import dev.patbeagan.consolevision.imagefilter.applyFilter
import dev.patbeagan.consolevision.types.ColorInt
import dev.patbeagan.consolevision.types.ColorPalette
import dev.patbeagan.consolevision.types.CompressionStyle
Expand All @@ -20,17 +19,15 @@ class ImagePrinter(
private val colorMapToAnsi: ColorMapToAnsi,
private val shouldNormalizeColors: Boolean,
private val shouldMutateColors: Boolean = false,
private val paletteColors: ColorPalette? = null,
private val compressionStyle: CompressionStyle = LOWER_HALF,
) {
private val applyPalette: (ColorInt, ColorPalette?) -> ColorInt =
{ colorInt: ColorInt, palette: ColorPalette? ->
palette?.matchColor(colorInt) ?: colorInt
}.memoize()

fun getFrame(
read: BufferedImage,
paletteColors: ColorPalette? = null,
compressionStyle: CompressionStyle = LOWER_HALF,
): String {
fun getFrame(read: BufferedImage): String {
applyFilters(read)
val out = buildOutput(read, compressionStyle, paletteColors)
return out.toString()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.patbeagan.consolevision.imagefilter

import dev.patbeagan.consolevision.types.ColorInt
import dev.patbeagan.consolevision.withLine
import java.awt.image.BufferedImage
import kotlin.random.Random

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.patbeagan.consolevision.imagefilter

import dev.patbeagan.consolevision.types.ColorInt
import dev.patbeagan.consolevision.withLine
import java.awt.image.BufferedImage

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,3 @@ import java.awt.image.BufferedImage
interface ImageFilter {
operator fun invoke(bufferedImage: BufferedImage)
}

inline fun BufferedImage.withLine(
onLineEnd: () -> Unit = {},
action: (Int, Int) -> Unit,
) {
(minY until height).forEach { y ->
(minX until width).forEach { x -> action(y, x) }
onLineEnd()
}
}

fun BufferedImage.applyFilter(imageFilter: ImageFilter) {
imageFilter(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package dev.patbeagan.consolevision.types

@JvmInline
value class ColorPalette(private val palette: Set<ColorInt>) {
fun matchColor(colorInt: ColorInt): ColorInt? =
palette.minByOrNull {
colorInt.removeAlpha().colorDistanceFrom(it)
}
fun matchColor(colorInt: ColorInt): ColorInt? = palette.minByOrNull {
colorInt.removeAlpha().colorDistanceFrom(it)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ value class CompressedPoint(private val base: Long) {
/**
* The first coordinate in the CompressedPoint
*/
val x get() = (base shr 32).toInt()
val x: Int get() = (base shr 32).toInt()

/**
* The second coordinate in the CompressedPoint
*/
val y get() = base.toInt() // (base and (2.0.pow(32) - 1).toLong()).toInt()
val y: Int get() = base.toInt() // (base and (2.0.pow(32) - 1).toLong()).toInt()

override fun toString(): String =
"CompressedPoint of ${this.x} to ${this.y}\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import dev.patbeagan.consolevision.types.ColorPalette
import java.awt.image.BufferedImage
import java.awt.image.DataBufferByte

fun BufferedImage.getByteData(): ByteArray {
val buffer = raster.dataBuffer as DataBufferByte
return buffer.data
}

fun BufferedImage.createColorPalette(
paletteReductionRate: Int,
): ColorPalette {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,21 @@ internal class ImagePrinterTest {

@Before
fun setup() {
imagePrinter = ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = false)
imagePrinter = ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
)
}

@Test
fun compatPalette() {
println(
ImagePrinter(0, ColorMapToAnsi(true), shouldNormalizeColors = false).getFrame(
ImagePrinter(
0,
ColorMapToAnsi(true),
shouldNormalizeColors = false,
).getFrame(
getScaledImage(readAsset(LENNA))
)
)
Expand All @@ -43,7 +51,11 @@ internal class ImagePrinterTest {
@Test
fun `sample image fullsize normalized`() {
println("sample image fullsize normalized")
ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = true)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = true,
)
.getFrame(readAsset(IMAGE_SMALL)).also { println(it) }
}

Expand All @@ -55,10 +67,18 @@ internal class ImagePrinterTest {
val read2 = getScaledImage(read)

println("Normalized: TRUE")
ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = true).getFrame(read1)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = true,
).getFrame(read1)
.also { println(it) }
println("Normalized: FALSE")
ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = false).getFrame(read2)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
).getFrame(read2)
.also { println(it) }
}

Expand All @@ -70,10 +90,18 @@ internal class ImagePrinterTest {
val read2 = getScaledImage(read)

println("Reduced: TRUE")
ImagePrinter(8, ColorMapToAnsi(false), shouldNormalizeColors = false).getFrame(read1)
ImagePrinter(
8,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
).getFrame(read1)
.also { println(it) }
println("Reduced: FALSE")
ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = false).getFrame(read2)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
).getFrame(read2)
.also { println(it) }
}

Expand All @@ -85,10 +113,18 @@ internal class ImagePrinterTest {
val read2 = getScaledImage(read)

println("Reduced: TRUE")
ImagePrinter(40, ColorMapToAnsi(false), shouldNormalizeColors = false).getFrame(read1)
ImagePrinter(
40,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
).getFrame(read1)
.also { println(it) }
println("Reduced: FALSE")
ImagePrinter(0, ColorMapToAnsi(false), shouldNormalizeColors = false).getFrame(read2)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
).getFrame(read2)
.also { println(it) }
}

Expand All @@ -100,9 +136,13 @@ internal class ImagePrinterTest {
@Test
fun `sample image compressed dots`() {
println("sample image compressed dots")
imagePrinter.getFrame(
readAsset(IMAGE_SMALL),
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
compressionStyle = CompressionStyle.DOTS_HIGH
).getFrame(
readAsset(IMAGE_SMALL),
).also { println(it) }
}

Expand All @@ -126,7 +166,7 @@ internal class ImagePrinterTest {
0,
ColorMapToAnsi(true),
shouldNormalizeColors = true,
shouldMutateColors = true
shouldMutateColors = true,
).getFrame(image)
.also { println(it) }
}
Expand Down Expand Up @@ -168,9 +208,14 @@ internal class ImagePrinterTest {
}.forEach { (first, second) ->
val (scale, transformOp) = read.getScaleToBoundBy(70, 70)
println(first)
imagePrinter.getFrame(
read.scale(scale, transformOp),
second?.createColorPalette(0)
ImagePrinter(
0,
ColorMapToAnsi(false),
shouldNormalizeColors = false,
compressionStyle = CompressionStyle.LOWER_HALF,
paletteColors = second?.createColorPalette(0),
).getFrame(
read.scale(scale, transformOp)
).also { println(it) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import dev.patbeagan.consolevision.ConsoleVisionRuntime
import dev.patbeagan.consolevision.ImageScaler
import dev.patbeagan.consolevision.server.RouteHandler
import dev.patbeagan.consolevision.util.Const
import dev.patbeagan.consolevision.util.getByteData
import io.ktor.application.*
import io.ktor.http.content.*
import io.ktor.request.*
Expand All @@ -14,6 +13,7 @@ import org.apache.commons.codec.digest.DigestUtils
import org.koin.core.component.inject
import org.slf4j.Logger
import java.awt.image.BufferedImage
import java.awt.image.DataBufferByte
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileWriter
Expand Down Expand Up @@ -104,9 +104,15 @@ class PostUpdateRoute : RouteHandler {
}
}
}

is PartData.FormItem -> TODO()
is PartData.BinaryItem -> TODO()
}
}
}
}

fun BufferedImage.getByteData(): ByteArray {
val buffer = raster.dataBuffer as DataBufferByte
return buffer.data
}

0 comments on commit 1d92d43

Please sign in to comment.