-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add capability to have different shapes of the dots
- Loading branch information
Simon Scholz
committed
Nov 27, 2023
1 parent
999da75
commit cdc53c7
Showing
6 changed files
with
253 additions
and
1 deletion.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
kotlin-sample/src/main/kotlin/io/github/simonscholz/CustomDotsMain.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package io.github.simonscholz | ||
|
||
import io.github.simonscholz.qrcode.QrCodeConfig | ||
import io.github.simonscholz.qrcode.QrCodeDotShape | ||
import io.github.simonscholz.qrcode.QrCodeFactory | ||
import java.awt.Color | ||
import java.awt.Graphics2D | ||
import java.io.File | ||
import java.nio.file.Files | ||
import java.nio.file.Paths | ||
|
||
fun main() { | ||
val path = Paths.get(System.getProperty("user.home"), "qr-code-samples") | ||
Files.createDirectories(path) | ||
val qrCodeDir = path.toAbsolutePath().toString() | ||
val qrCodeApi = QrCodeFactory.createQrCodeApi() | ||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.CIRCLE) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-CIRCLE-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.ROUNDED_SQUARE) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-ROUND-SQUARE-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.HEXAGON) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-HEXAGON-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.TRIANGLE) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-TRIANGLE-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.HEART) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-HEART-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(QrCodeDotShape.HOUSE) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-HOUSE-dots-kotlin.png")) | ||
} | ||
|
||
QrCodeConfig.Builder("https://simonscholz.github.io/") | ||
.qrCodeDotStyler(::drawColorfulHouseWithDoorAndWindow) | ||
.qrCodeSize(800) | ||
.build() | ||
.run { | ||
qrCodeApi.createQrCodeImage(this) | ||
.toFile(File(qrCodeDir, "/qr-with-COLORFUL-HOUSE-dots-kotlin.png")) | ||
} | ||
} | ||
|
||
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) | ||
|
||
// 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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
qr-code/src/main/kotlin/io/github/simonscholz/qrcode/QrCodeDotStyler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package io.github.simonscholz.qrcode | ||
|
||
import io.github.simonscholz.qrcode.internal.graphics.CustomQrCodeDotStyler | ||
import java.awt.Graphics2D | ||
|
||
interface QrCodeDotStyler { | ||
fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) | ||
} | ||
|
||
enum class QrCodeDotShape : QrCodeDotStyler { | ||
SQUARE { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
graphics.fillRect(x, y, dotSize, dotSize) | ||
} | ||
}, | ||
ROUNDED_SQUARE { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
graphics.fillRoundRect(x, y, dotSize, dotSize, 10, 10) | ||
} | ||
}, | ||
CIRCLE { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
graphics.fillArc(x, y, dotSize, dotSize, 0, 360) | ||
} | ||
}, | ||
HEXAGON { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
CustomQrCodeDotStyler.drawHexagon(x, y, dotSize, graphics) | ||
} | ||
}, | ||
TRIANGLE { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
CustomQrCodeDotStyler.drawEquilateralTriangle(x, y, dotSize, graphics) | ||
} | ||
}, | ||
HEART { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
CustomQrCodeDotStyler.drawHeart(x, y, dotSize, graphics) | ||
} | ||
}, | ||
HOUSE { | ||
override fun createDot(x: Int, y: Int, dotSize: Int, graphics: Graphics2D) { | ||
CustomQrCodeDotStyler.drawHouse(x, y, dotSize, graphics) | ||
} | ||
}, | ||
; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
...e/src/main/kotlin/io/github/simonscholz/qrcode/internal/graphics/CustomQrCodeDotStyler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package io.github.simonscholz.qrcode.internal.graphics | ||
|
||
import java.awt.Graphics2D | ||
import java.awt.Point | ||
import java.awt.Polygon | ||
import kotlin.math.cos | ||
import kotlin.math.sin | ||
import kotlin.math.sqrt | ||
|
||
internal object CustomQrCodeDotStyler { | ||
|
||
fun drawHouse(x: Int, y: Int, size: Int, graphic: Graphics2D) { | ||
val roofHeight = size / 2 | ||
val houseWidth = size - 1 // -1 to have a gap between the houses | ||
val houseHeight = size - roofHeight | ||
|
||
// Draw the base of the house | ||
graphic.fillRect(x, y + roofHeight, houseWidth, houseHeight) | ||
|
||
// Draw the roof | ||
val roofXPoints = intArrayOf(x, x + houseWidth / 2, x + houseWidth) | ||
val roofYPoints = intArrayOf(y + roofHeight, y, y + roofHeight) | ||
graphic.fillPolygon(roofXPoints, roofYPoints, 3) | ||
} | ||
|
||
fun drawHeart(x: Int, y: Int, size: Int, graphic: Graphics2D) { | ||
val heartWidth = handleRoundingIssues(size) | ||
val heartHeight = handleRoundingIssues(size) | ||
val gap = heartWidth / 4 | ||
|
||
// Draw the left arc of the heart | ||
graphic.fillArc(x, y, heartWidth / 2, heartHeight / 2, 0, 180) | ||
|
||
// Draw the right arc of the heart | ||
graphic.fillArc(x + heartWidth / 2, y, heartWidth / 2, heartHeight / 2, 0, 180) | ||
|
||
// Draw the bottom triangle of the heart | ||
val triangleXPoints = intArrayOf(x, x + heartWidth / 2, x + heartWidth, x) | ||
val triangleYPoints = intArrayOf(y + heartHeight / 2 - gap, y + heartHeight - gap, y + heartHeight / 2 - gap, y + heartHeight / 2 - gap) | ||
graphic.fillPolygon(triangleXPoints, triangleYPoints, 4) | ||
} | ||
|
||
private fun handleRoundingIssues(size: Int): Int = | ||
if (size % 2 == 0) { | ||
size | ||
} else { | ||
size - 1 | ||
} | ||
|
||
fun drawHexagon(x: Int, y: Int, size: Int, graphic: Graphics2D) { | ||
val hexRadius = size / 2 | ||
graphic.fillPolygon(createHexagon(Point(x + hexRadius, y + hexRadius), hexRadius)) | ||
} | ||
|
||
private fun createHexagon(center: Point, radius: Int): Polygon { | ||
val polygon = Polygon() | ||
for (i in 0..5) { | ||
polygon.addPoint( | ||
(center.x + radius * cos(i * 2 * Math.PI / 6.0)).toInt(), | ||
(center.y + radius * sin(i * 2 * Math.PI / 6.0)).toInt(), | ||
) | ||
} | ||
return polygon | ||
} | ||
|
||
fun drawEquilateralTriangle(x: Int, y: Int, size: Int, graphic: Graphics2D) { | ||
val triangleHeight = (sqrt(3.0) / 2 * size).toInt() | ||
|
||
val triangleXPoints = intArrayOf(x, x + size / 2, x + size, x) | ||
val triangleYPoints = intArrayOf(y + triangleHeight, y, y + triangleHeight, y + triangleHeight) | ||
|
||
graphic.fillPolygon(triangleXPoints, triangleYPoints, 3) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters