Skip to content

Commit

Permalink
Add custom styles for dots to app
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Scholz committed Dec 3, 2023
1 parent ac0076f commit b29f8c2
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.simonscholz.model

enum class DotShapes {
SQUARE,
ROUNDED_SQUARE,
CIRCLE,
HEXAGON,
TRIANGLE,
HEART,
HOUSE,
HOUSE_WITH_DOOR_AND_WINDOW,
SMILEY,
PUMPKIN,
CHRISTMAS_TREE,
CAR,
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package io.github.simonscholz.model

import io.github.simonscholz.qrcode.LogoShape
import io.github.simonscholz.qrcode.QrCodeDotShape

data class QrCodeConfig(
val qrCodeContent: String,
val size: Int,
val backgroundColor: ColorInfo,
val foregroundColor: ColorInfo,
val dotShape: QrCodeDotShape,
val dotShape: DotShapes,

val logoBase64: String,
val logoRelativeSize: Double,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package io.github.simonscholz.service

import io.github.simonscholz.model.DotShapes
import io.github.simonscholz.model.QrCodeConfigViewModel
import io.github.simonscholz.qrcode.QrCodeConfig
import io.github.simonscholz.qrcode.QrCodeDotShape
import io.github.simonscholz.qrcode.QrCodeDotStyler
import io.github.simonscholz.qrcode.QrCodeFactory
import io.github.simonscholz.qrcode.QrPositionalSquaresConfig
import java.awt.Image
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import javax.imageio.ImageIO

class ImageService(private val qrCodeConfigViewModel: QrCodeConfigViewModel) {

Expand All @@ -16,7 +21,7 @@ class ImageService(private val qrCodeConfigViewModel: QrCodeConfigViewModel) {
bgColor = qrCodeConfigViewModel.backgroundColor.value,
fillColor = qrCodeConfigViewModel.foregroundColor.value,
)
.qrCodeDotStyler(qrCodeConfigViewModel.dotShape.value)
.qrCodeDotStyler(mapCustomDotStyler(qrCodeConfigViewModel.dotShape.value))
.qrBorderConfig(
color = qrCodeConfigViewModel.borderColor.value,
relativeSize = qrCodeConfigViewModel.relativeBorderSize.value,
Expand Down Expand Up @@ -44,18 +49,84 @@ class ImageService(private val qrCodeConfigViewModel: QrCodeConfigViewModel) {
return QrCodeFactory.createQrCodeApi().createQrCodeImage(qrCodeConfig)
}

private fun getScaledLogo(logo: Image, qrCodeConfigViewModel: QrCodeConfigViewModel): Image {
val maxLogoSize = (qrCodeConfigViewModel.size.value * qrCodeConfigViewModel.logoRelativeSize.value).toInt()
if (logo.getWidth(null) <= maxLogoSize && logo.getHeight(null) <= maxLogoSize) {
return logo
private fun mapCustomDotStyler(value: DotShapes): QrCodeDotStyler =
when (value) {
DotShapes.SQUARE -> QrCodeDotShape.SQUARE
DotShapes.CIRCLE -> QrCodeDotShape.CIRCLE
DotShapes.ROUNDED_SQUARE -> QrCodeDotShape.ROUNDED_SQUARE
DotShapes.HEXAGON -> QrCodeDotShape.HEXAGON
DotShapes.TRIANGLE -> QrCodeDotShape.TRIANGLE
DotShapes.HEART -> QrCodeDotShape.HEART
DotShapes.HOUSE -> QrCodeDotShape.HOUSE
DotShapes.HOUSE_WITH_DOOR_AND_WINDOW -> QrCodeDotStyler { x, y, size, graphic ->
drawColorfulHouseWithDoorAndWindow(x, y, size, graphic)
}
DotShapes.SMILEY -> QrCodeDotStyler { x, y, size, graphic ->
drawSmiley(x, y, size, graphic)
}
DotShapes.PUMPKIN -> QrCodeDotStyler { x, y, size, graphic ->
drawPumpkin(x, y, size, graphic)
}
DotShapes.CHRISTMAS_TREE -> QrCodeDotStyler { x, y, size, graphic ->
drawChristmasTree(x, y, size, graphic)
}
DotShapes.CAR -> QrCodeDotStyler { x, y, size, graphic ->
drawCar(x, y, size, graphic)
}
}

if (logo.getWidth(null) > logo.getHeight(null)) {
val ratio = logo.getHeight(null).toDouble() / logo.getWidth(null).toDouble()
return logo.getScaledInstance(maxLogoSize, (maxLogoSize * ratio).toInt(), Image.SCALE_SMOOTH)
private fun drawSmiley(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) {
drawDotImage(x, y, dotSize, graphics, "smiley_fill.png")
}

private fun drawPumpkin(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) {
drawDotImage(x, y, dotSize, graphics, "halloween_pumpkin.png")
}

private fun drawChristmasTree(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) {
drawDotImage(x, y, dotSize, graphics, "christmas_tree.png")
}

private fun drawCar(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) {
drawDotImage(x, y, dotSize, graphics, "car.png")
}

private fun drawDotImage(x: Int, y: Int, dotSize: Int, graphics: Graphics2D, image: String) {
val resource = ImageService::class.java.getClassLoader().getResource(image)
resource?.let {
val imageDot = ImageIO.read(it)
graphics.drawImage(imageDot, x, y, dotSize, dotSize, null)
}
}

private fun drawColorfulHouseWithDoorAndWindow(x: Int, y: Int, size: Int, graphic: Graphics2D) {
val roofHeight = size / 2
val houseWidth = size
val houseHeight = size - roofHeight

// Draw the base of the house
graphic.color = Color.RED
graphic.fillRect(x, y + roofHeight, houseWidth, houseHeight)

// Draw the roof
graphic.color = Color.BLUE
val roofXPoints = intArrayOf(x, x + houseWidth / 2, x + houseWidth)
val roofYPoints = intArrayOf(y + roofHeight, y, y + roofHeight)
graphic.fillPolygon(roofXPoints, roofYPoints, 3)

// Draw the door
val doorWidth = size / 5
val doorHeight = size / 2 - 1
val doorX = x + (houseWidth - size / 5) / 2 + size / 10
val doorY = y + roofHeight + houseHeight - doorHeight + 1
graphic.color = Color.GREEN
graphic.fillRect(doorX, doorY, doorWidth, doorHeight)

val ratio = logo.getWidth(null).toDouble() / logo.getHeight(null).toDouble()
return logo.getScaledInstance((maxLogoSize * ratio).toInt(), maxLogoSize, Image.SCALE_SMOOTH)
// Draw the window
val windowSize = size / 5
val windowX = x + size / 5
val windowY = y + roofHeight + size / 5
graphic.color = Color.YELLOW
graphic.fillRect(windowX, windowY, windowSize, windowSize)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package io.github.simonscholz.ui
import io.github.simonscholz.extension.toIntObservable
import io.github.simonscholz.extension.toObservable
import io.github.simonscholz.extension.toSelectedItemObservable
import io.github.simonscholz.model.DotShapes
import io.github.simonscholz.model.QrCodeConfigViewModel
import io.github.simonscholz.qrcode.QrCodeDotShape
import io.github.simonscholz.ui.properties.BorderPropertiesUI
import io.github.simonscholz.ui.properties.LogoPropertiesUI
import io.github.simonscholz.ui.properties.PositionalSquaresPropertiesUI
Expand Down Expand Up @@ -57,7 +57,7 @@ object PropertiesUI {
CustomItems.createColorPickerItem(baseTaskPane, "Foreground Color:", qrCodeConfigViewModel.foregroundColor, dataBindingContext)

baseTaskPane.add(JLabel("Dot Shape:"))
val logoShapes = QrCodeDotShape.entries.toTypedArray()
val logoShapes = DotShapes.entries.toTypedArray()
val shapeComboBox = JComboBox(logoShapes)
dataBindingContext.bindValue(shapeComboBox.toSelectedItemObservable(), qrCodeConfigViewModel.dotShape)
baseTaskPane.add(shapeComboBox, "wrap, growx, span 3, width 200:220:300")
Expand Down Expand Up @@ -95,9 +95,6 @@ object PropertiesUI {
clickedApply()
}

// TODO allow to save config
// propertiesPanel.add(JButton("Save Config"), "wrap, growx, span 2, gaptop 25")

val scrollPane = JScrollPane(jxTaskPaneContainer)
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED)
scrollPane.viewport.minimumSize = Dimension(500, 0)
Expand Down
Binary file added qr-code-app/src/main/resources/car.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added qr-code-app/src/main/resources/christmas_tree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added qr-code-app/src/main/resources/halloween_pumpkin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package io.github.simonscholz.qrcode

import java.awt.Color
import java.awt.Graphics2D
import java.awt.Image
import kotlin.reflect.KFunction4

const val DEFAULT_IMG_SIZE = 300

Expand Down Expand Up @@ -66,14 +64,6 @@ class QrCodeConfig @JvmOverloads constructor(
this.qrCodeDotStyler = qrCodeDotStyler
}

fun qrCodeDotStyler(qrCodeDotStyler: KFunction4<Int, Int, Int, Graphics2D, Unit>) = apply {
this.qrCodeDotStyler = object : QrCodeDotStyler {
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) {
qrCodeDotStyler.invoke(x, y, dotSize, graphics)
}
}
}

fun build() = QrCodeConfig(
qrCodeText = qrCodeText,
qrCodeSize = qrCodeSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.github.simonscholz.qrcode
import io.github.simonscholz.qrcode.internal.graphics.CustomQrCodeDotStyler
import java.awt.Graphics2D

interface QrCodeDotStyler {
fun interface QrCodeDotStyler {
fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D)
}

Expand Down

0 comments on commit b29f8c2

Please sign in to comment.