Skip to content

Commit 0e30b4d

Browse files
feat(ecl-auto): New QRCodeGraphicsFactory implementations
1 parent ee3f681 commit 0e30b4d

File tree

5 files changed

+71
-18
lines changed

5 files changed

+71
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package qrcode.render
2+
3+
import android.graphics.Canvas
4+
5+
/**
6+
* A platform-specific implementation of [QRCodeGraphicsFactory]. It makes it so that all [QRCodeGraphics] instances
7+
* created by the factory use the specified [canvas] and start drawing at the ([offsetX], [offsetY]) point.
8+
*
9+
* @see QRCodeGraphicsFactory
10+
* @see QRCodeGraphics.useCustomCanvas
11+
*/
12+
class AndroidQRCodeGraphicsFactory(
13+
var canvas: Canvas,
14+
val offsetX: Int = 0,
15+
val offsetY: Int = 0,
16+
) : QRCodeGraphicsFactory() {
17+
override fun newGraphics(width: Int, height: Int): QRCodeGraphics =
18+
super.newGraphics(width, height)
19+
.apply { useCustomCanvas(canvas, offsetX, offsetY) }
20+
}

src/androidMain/kotlin/qrcode/render/QRCodeGraphics.android.kt

+18-17
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,11 @@ actual open class QRCodeGraphics actual constructor(
2626
val AVAILABLE_FORMATS: Array<String> = CompressFormat.entries.map { it.name }.toTypedArray()
2727
}
2828

29-
protected fun createCanvas(image: Bitmap) = Canvas(image)
30-
3129
/** [Bitmap] being used for the drawing operations. */
3230
private var image: Bitmap = Bitmap.createBitmap(width, height, ARGB_8888)
3331

3432
/** [Canvas] that handles the presenting. */
35-
private var canvas: Canvas = createCanvas(image)
33+
private lateinit var canvas: Canvas
3634

3735
/** Cache of [Paint] objects being used. Just to try and use the least amount of CPU/memory possible. */
3836
private val paintCache = mutableMapOf<Int, Paint>()
@@ -45,6 +43,14 @@ actual open class QRCodeGraphics actual constructor(
4543
private var customCanvasOffsetX: Int = 0
4644
private var customCanvasOffsetY: Int = 0
4745

46+
protected fun useCanvas(): Canvas {
47+
if (!customCanvas && !this::canvas.isInitialized) {
48+
canvas = Canvas(image)
49+
}
50+
51+
return canvas
52+
}
53+
4854
/**
4955
* Allows this object to draw directly to a user specified [Canvas].
5056
*
@@ -93,12 +99,7 @@ actual open class QRCodeGraphics actual constructor(
9399
if (changed) {
94100
changed = false
95101
image = Bitmap.createBitmap(width, height, ARGB_8888)
96-
97-
if (!customCanvas) {
98-
canvas = createCanvas(image)
99-
} else {
100-
this.canvas.setBitmap(image)
101-
}
102+
useCanvas().setBitmap(image)
102103
}
103104
}
104105

@@ -163,7 +164,7 @@ actual open class QRCodeGraphics actual constructor(
163164

164165
/** Draw a straight line from point `(x1,y1)` to `(x2,y2)`. */
165166
actual open fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Int, thickness: Double) {
166-
canvas.drawLine(
167+
useCanvas().drawLine(
167168
(x1 + customCanvasOffsetX).toFloat(),
168169
(y1 + customCanvasOffsetY).toFloat(),
169170
(x2 + customCanvasOffsetX).toFloat(),
@@ -181,12 +182,12 @@ actual open class QRCodeGraphics actual constructor(
181182
x + width - halfThickness + customCanvasOffsetX,
182183
y + height - halfThickness + customCanvasOffsetY,
183184
)
184-
canvas.drawRect(rect, paintFromCache(color, STROKE, thickness))
185+
useCanvas().drawRect(rect, paintFromCache(color, STROKE, thickness))
185186
}
186187

187188
/** Fills the rectangle starting at point `(x,y)` and having `width` by `height`. */
188189
actual open fun fillRect(x: Int, y: Int, width: Int, height: Int, color: Int) {
189-
canvas.drawRect(
190+
useCanvas().drawRect(
190191
Rect(
191192
x + customCanvasOffsetX,
192193
y + customCanvasOffsetY,
@@ -234,7 +235,7 @@ actual open class QRCodeGraphics actual constructor(
234235
) {
235236
val halfThickness = (thickness / 2.0).roundToInt()
236237

237-
canvas.drawRoundRect(
238+
useCanvas().drawRoundRect(
238239
buildRectF(x + halfThickness, y + halfThickness, width - halfThickness * 2, height - halfThickness * 2),
239240
borderRadius.toFloat(),
240241
borderRadius.toFloat(),
@@ -264,7 +265,7 @@ actual open class QRCodeGraphics actual constructor(
264265
*
265266
*/
266267
actual open fun fillRoundRect(x: Int, y: Int, width: Int, height: Int, borderRadius: Int, color: Int) {
267-
canvas.drawRoundRect(
268+
useCanvas().drawRoundRect(
268269
buildRectF(x, y, width, height),
269270
borderRadius.toFloat(),
270271
borderRadius.toFloat(),
@@ -276,7 +277,7 @@ actual open class QRCodeGraphics actual constructor(
276277
* Draw the edges of an ellipse (aka "a circle") which occupies the area `(x,y,width,height)`
277278
*/
278279
actual fun drawEllipse(x: Int, y: Int, width: Int, height: Int, color: Int, thickness: Double) {
279-
canvas.drawOval(
280+
useCanvas().drawOval(
280281
buildRectF(x, y, width, height),
281282
paintFromCache(color, STROKE, thickness),
282283
)
@@ -287,7 +288,7 @@ actual open class QRCodeGraphics actual constructor(
287288
*
288289
*/
289290
actual fun fillEllipse(x: Int, y: Int, width: Int, height: Int, color: Int) {
290-
canvas.drawOval(
291+
useCanvas().drawOval(
291292
buildRectF(x, y, width, height),
292293
paintFromCache(color),
293294
)
@@ -308,6 +309,6 @@ actual open class QRCodeGraphics actual constructor(
308309
*/
309310
open fun drawImage(img: Bitmap, x: Int, y: Int) {
310311
changed = true
311-
canvas.drawBitmap(img, x.toFloat(), y.toFloat(), null)
312+
useCanvas().drawBitmap(img, x.toFloat(), y.toFloat(), null)
312313
}
313314
}

src/commonMain/kotlin/qrcode/QRCodeBuilder.kt

+12-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,15 @@ class QRCodeBuilder @JvmOverloads constructor(
191191
return this
192192
}
193193

194-
/** Use a custom [QRCodeGraphicsFactory] instead of the default. */
194+
/**
195+
* Use a custom [QRCodeGraphicsFactory] instead of the default. Use this to have a way to better control how and
196+
* where the QRCode drawing will occur.
197+
*
198+
* The currently available implementations on this library are:
199+
*
200+
* - **Android:**`qrcode.render.AndroidQRCodeGraphicsFactory`
201+
* - **JVM:** `qrcode.render.JvmQRCodeGraphicsFactory`
202+
*/
195203
fun withGraphicsFactory(factory: QRCodeGraphicsFactory): QRCodeBuilder {
196204
graphicsFactory = factory
197205
return this
@@ -306,6 +314,9 @@ class QRCodeBuilder @JvmOverloads constructor(
306314
/**
307315
* Builds a [QRCode] instance ready to use.
308316
*
317+
* **Important:** if you want to use your own drawing instrument (for example an Android `Canvas` or a JVM
318+
* `BufferedImage`) call `freshlyBuiltQrCode.graphics
319+
*
309320
* @see QRCode.renderToBytes
310321
* @see QRCode.render
311322
*/

src/commonMain/kotlin/qrcode/render/QRCodeGraphicsFactory.kt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package qrcode.render
22

3+
import qrcode.QRCode
34
import kotlin.js.ExperimentalJsExport
45
import kotlin.js.JsExport
56

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package qrcode.render
2+
3+
import java.awt.image.BufferedImage
4+
5+
/**
6+
* A platform-specific implementation of [QRCodeGraphicsFactory]. It makes it so that all [QRCodeGraphics] instances
7+
* created by the factory use the specified [bufferedImage] and start drawing at the ([offsetX], [offsetY]) point.
8+
*
9+
* @see QRCodeGraphicsFactory
10+
* @see QRCodeGraphics.useCustomBufferedImage
11+
*/
12+
class JvmQRCodeGraphicsFactory(
13+
var bufferedImage: BufferedImage,
14+
val offsetX: Int = 0,
15+
val offsetY: Int = 0,
16+
) : QRCodeGraphicsFactory() {
17+
override fun newGraphics(width: Int, height: Int): QRCodeGraphics =
18+
super.newGraphics(width, height)
19+
.apply { useCustomBufferedImage(bufferedImage, offsetX, offsetY) }
20+
}

0 commit comments

Comments
 (0)