From 0e263e0a494e1eab55a6d792bc208ec9121cff66 Mon Sep 17 00:00:00 2001 From: ISNing Date: Wed, 10 Apr 2024 20:54:33 +0800 Subject: [PATCH 01/14] kn: Allow reading barcode without instantiate a BarcodeReader object Example: ```kotlin val barcode = BarcodeReader.read(iv) ``` ```kotlin val barcode = BarcodeReader.read(iv, opts) ``` --- .../src/nativeMain/kotlin/zxingcpp/BarcodeReader.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeReader.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeReader.kt index 317cfbc727..3483fc15fa 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeReader.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeReader.kt @@ -24,9 +24,14 @@ internal fun CPointer?.toKStringNullPtrHandledAndFree(): String? = (thi @OptIn(ExperimentalForeignApi::class) class BarcodeReader : ReaderOptions() { @Throws(BarcodeReadingException::class) - fun read(imageView: ImageView): List = - ZXing_ReadBarcodes(imageView.cValue, cValue)?.let { cValues -> cValues.toKObject().also { ZXing_Barcodes_delete(cValues) } } - ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + fun read(imageView: ImageView): List = Companion.read(imageView, this) + + companion object { + @Throws(BarcodeReadingException::class) + fun read(imageView: ImageView, opts: ReaderOptions? = null): List = + ZXing_ReadBarcodes(imageView.cValue, opts?.cValue)?.let { cValues -> cValues.toKObject().also { ZXing_Barcodes_delete(cValues) } } + ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + } } class BarcodeReadingException(message: String?) : Exception("Failed to read barcodes: $message") From 9b8a93c650d190868893544cd00b116f51975cb7 Mon Sep 17 00:00:00 2001 From: ISNing Date: Wed, 10 Apr 2024 21:37:50 +0800 Subject: [PATCH 02/14] kn: Correct the arrangement of parameter for assert functions --- wrappers/kn/src/nativeTest/kotlin/Test.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wrappers/kn/src/nativeTest/kotlin/Test.kt b/wrappers/kn/src/nativeTest/kotlin/Test.kt index 6ff753cfb1..d690ff3a8e 100644 --- a/wrappers/kn/src/nativeTest/kotlin/Test.kt +++ b/wrappers/kn/src/nativeTest/kotlin/Test.kt @@ -29,13 +29,13 @@ class BarcodeReaderTest { assertNotNull(res) assert(res.isValid) - assertEquals(res.format, BarcodeFormat.EAN8) - assertEquals(res.text, expected) - assertContentEquals(res.bytes, expected.encodeToByteArray()) + assertEquals(BarcodeFormat.EAN8, res.format) + assertEquals(expected, res.text) + assertContentEquals(expected.encodeToByteArray(), res.bytes) assert(!res.hasECI) - assertEquals(res.contentType, ContentType.Text) - assertEquals(res.orientation, 0) - assertEquals(res.position.topLeft, PointI(4, 0)) - assertEquals(res.lineCount, 1) + assertEquals(ContentType.Text, res.contentType) + assertEquals(0, res.orientation) + assertEquals(PointI(4, 0), res.position.topLeft) + assertEquals(1, res.lineCount) } } From 134e484a1756fd1127ab8890f94e1353c340876d Mon Sep 17 00:00:00 2001 From: ISNing Date: Wed, 10 Apr 2024 21:14:38 +0800 Subject: [PATCH 03/14] kn: Add support for experimental barcode writer --- .github/workflows/ci.yml | 2 + .github/workflows/publish-kn.yml | 2 + wrappers/kn/README.md | 5 +- wrappers/kn/build.gradle.kts | 5 +- .../src/nativeMain/kotlin/zxingcpp/Barcode.kt | 23 +++++ .../kotlin/zxingcpp/BarcodeWriter.kt | 88 +++++++++++++++++++ .../nativeMain/kotlin/zxingcpp/ImageView.kt | 74 +++++++++++----- wrappers/kn/src/nativeTest/kotlin/Test.kt | 44 +++++++++- 8 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94a2b69f2d..5b4976d3c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,6 +158,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + submodules: true - name: Checkout toolchain initializer repository uses: actions/checkout@v4 diff --git a/.github/workflows/publish-kn.yml b/.github/workflows/publish-kn.yml index cf874b588d..435593b96d 100644 --- a/.github/workflows/publish-kn.yml +++ b/.github/workflows/publish-kn.yml @@ -20,6 +20,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + submodules: true - name: Checkout toolchain initializer repository uses: actions/checkout@v4 diff --git a/wrappers/kn/README.md b/wrappers/kn/README.md index 6c41d5a2f3..9af3753c5a 100644 --- a/wrappers/kn/README.md +++ b/wrappers/kn/README.md @@ -19,13 +19,14 @@ import zxingcpp.BarcodeFormat import zxingcpp.BarcodeReader import zxingcpp.ImageFormat import zxingcpp.ImageView +import zxingcpp.ImageViewImplNoCopy val data: ByteArray = ... // the image data val width: Int = ... // the image width val height: Int = ... // the image height -val format = ImageFormat.Lum // ImageFormat.Lum assumes grey scale image data +val format: ImageFormat = ImageFormat.Lum // ImageFormat.Lum assumes grey scale image data -val image = ImageView(data, width, height, format) +val image: ImageView = ImageViewImplNoCopy(data, width, height, format) val barcodeReader = BarcodeReader().apply { formats = setOf(BarcodeFormat.EAN13, BarcodeFormat.QRCode) tryHarder = true diff --git a/wrappers/kn/build.gradle.kts b/wrappers/kn/build.gradle.kts index 7ce21cba57..3ca1ef5fad 100644 --- a/wrappers/kn/build.gradle.kts +++ b/wrappers/kn/build.gradle.kts @@ -90,6 +90,7 @@ krossCompile { packageName = "zxingcpp.cinterop" includeDirs.from(buildDir) headers = listOf("$sourceDir/src/ZXingC.h") + compilerOpts += "-DZXING_EXPERIMENTAL_API=ON" } cmake.apply { val buildDir = "$cmakeDir/{projectName}/{targetName}" @@ -102,7 +103,9 @@ krossCompile { } + CustomCMakeCacheEntries( mapOf( "ZXING_READERS" to "ON", - "ZXING_WRITERS" to "OFF", + "ZXING_WRITERS" to "NEW", + "ZXING_EXPERIMENTAL_API" to "ON", + "ZXING_USE_BUNDLED_ZINT" to "ON", "ZXING_C_API" to "ON", ) )).asCMakeParams diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt index 26f86fc788..98cc1a63d7 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt @@ -53,6 +53,23 @@ fun ZXing_Position.toKObject(): Position = Position( @OptIn(ExperimentalForeignApi::class) class Barcode(val cValue: CValuesRef) { + companion object { + @ExperimentalWriterApi + fun fromText(text: String, opts: CreatorOptions): Barcode = + ZXing_CreateBarcodeFromText(text, text.length, opts.cValue)?.toKObject() + ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + @ExperimentalWriterApi + fun fromText(text: String, format: BarcodeFormat): Barcode = + fromText(text, CreatorOptions(format)) + @ExperimentalWriterApi + fun fromBytes(bytes: ByteArray, opts: CreatorOptions): Barcode = + ZXing_CreateBarcodeFromBytes(bytes.refTo(0), bytes.size, opts.cValue)?.toKObject() + ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + @ExperimentalWriterApi + fun fromBytes(bytes: ByteArray, format: BarcodeFormat): Barcode = + fromBytes(bytes, CreatorOptions(format)) + } + val isValid: Boolean get() = ZXing_Barcode_isValid(cValue) val errorMsg: String? by lazy { @@ -132,6 +149,12 @@ class Barcode(val cValue: CValuesRef) { } } +@ExperimentalWriterApi +fun Barcode.toSVG(opts: WriterOptions? = null): String = BarcodeWriter.writeToSVG(this, opts) + +@ExperimentalWriterApi +fun Barcode.toImage(opts: WriterOptions? = null): Image = BarcodeWriter.writeToImage(this, opts) + @OptIn(ExperimentalForeignApi::class) fun CValuesRef.toKObject(): Barcode = Barcode(this) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt new file mode 100644 index 0000000000..93e8ed2eb8 --- /dev/null +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt @@ -0,0 +1,88 @@ +package zxingcpp + +import cnames.structs.ZXing_CreatorOptions +import cnames.structs.ZXing_WriterOptions +import kotlinx.cinterop.* +import zxingcpp.cinterop.* +import kotlin.experimental.ExperimentalNativeApi +import kotlin.native.ref.createCleaner + +// TODO: Remove this annotation when the API is stable +@RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "The Writer API is experimental and may change in the future.") +@Retention(AnnotationRetention.BINARY) +annotation class ExperimentalWriterApi + + +@ExperimentalWriterApi +@OptIn(ExperimentalForeignApi::class) +class BarcodeWriter : WriterOptions() { + fun writeToSVG(barcode: Barcode): String = Companion.writeToSVG(barcode, this) + + fun writeToImage(barcode: Barcode): Image = Companion.writeToImage(barcode, this) + + companion object { + @OptIn(ExperimentalForeignApi::class) + fun writeToSVG(barcode: Barcode, opts: WriterOptions? = null): String = barcode.cValue.usePinned { + ZXing_WriteBarcodeToSVG(it.get(), opts?.cValue)?.toKStringNullPtrHandledAndFree() + ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + } + + @OptIn(ExperimentalForeignApi::class) + fun writeToImage(barcode: Barcode, opts: WriterOptions? = null): Image = barcode.cValue.usePinned { + ZXing_WriteBarcodeToImage(it.get(), opts?.cValue)?.toKObject() + ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + } + + } +} + +class BarcodeWritingException(message: String?) : Exception("Failed to write barcode: $message") + +@ExperimentalWriterApi +@OptIn(ExperimentalForeignApi::class) +open class CreatorOptions(format: BarcodeFormat) { + var format: BarcodeFormat + get() = ZXing_CreatorOptions_getFormat(cValue).parseIntoBarcodeFormat().first() + set(value) = ZXing_CreatorOptions_setFormat(cValue, value.rawValue) + var readerInit: Boolean + get() = ZXing_CreatorOptions_getReaderInit(cValue) + set(value) = ZXing_CreatorOptions_setReaderInit(cValue, value) + var forceSquareDataMatrix: Boolean + get() = ZXing_CreatorOptions_getForceSquareDataMatrix(cValue) + set(value) = ZXing_CreatorOptions_setForceSquareDataMatrix(cValue, value) + var ecLevel: String + get() = ZXing_CreatorOptions_getEcLevel(cValue)?.toKStringNullPtrHandledAndFree() ?: "" + set(value) = ZXing_CreatorOptions_setEcLevel(cValue, value) + + val cValue: CValuesRef? = ZXing_CreatorOptions_new(format.rawValue) + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + private val cleaner = createCleaner(cValue) { ZXing_CreatorOptions_delete(it) } +} + +@ExperimentalWriterApi +@OptIn(ExperimentalForeignApi::class) +open class WriterOptions { + var scale: Int + get() = ZXing_WriterOptions_getScale(cValue) + set(value) = ZXing_WriterOptions_setScale(cValue, value) + var sizeHint: Int + get() = ZXing_WriterOptions_getSizeHint(cValue) + set(value) = ZXing_WriterOptions_setSizeHint(cValue, value) + var rotate: Int + get() = ZXing_WriterOptions_getRotate(cValue) + set(value) = ZXing_WriterOptions_setRotate(cValue, value) + var withHRT: Boolean + get() = ZXing_WriterOptions_getWithHRT(cValue) + set(value) = ZXing_WriterOptions_setWithHRT(cValue, value) + var withQuietZones: Boolean + get() = ZXing_WriterOptions_getWithQuietZones(cValue) + set(value) = ZXing_WriterOptions_setWithQuietZones(cValue, value) + + val cValue: CValuesRef? = ZXing_WriterOptions_new() + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + private val cleaner = createCleaner(cValue) { ZXing_WriterOptions_delete(it) } +} diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt index c8cb9b7b40..2665082cd2 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt @@ -5,42 +5,54 @@ package zxingcpp +import cnames.structs.ZXing_Image import cnames.structs.ZXing_ImageView import kotlinx.cinterop.* import zxingcpp.cinterop.* import kotlin.experimental.ExperimentalNativeApi +import kotlin.native.ref.Cleaner import kotlin.native.ref.createCleaner @OptIn(ExperimentalForeignApi::class) -class ImageView( - val data: ByteArray, - val width: Int, - val height: Int, - val format: ImageFormat, - val rowStride: Int = 0, - val pixStride: Int = 0, -) { - private val pinnedData = data.pin() - val cValue: CPointer? = - ZXing_ImageView_new_checked( - pinnedData.addressOf(0).reinterpret(), - data.size, - width, - height, - format.cValue, - rowStride, - pixStride - ) +abstract class ImageView { + abstract val cValue: CValuesRef @Suppress("unused") @OptIn(ExperimentalNativeApi::class) - private val cValueCleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) } + protected abstract val cValueCleaner: Cleaner +} + +@OptIn(ExperimentalForeignApi::class) +open class ImageViewImplNoCopy( + data: ByteArray, + width: Int, + height: Int, + format: ImageFormat, + rowStride: Int = 0, + pixStride: Int = 0, +) : ImageView() { + private val pinnedData = data.pin() + + final override val cValue: CPointer = ZXing_ImageView_new_checked( + pinnedData.addressOf(0).reinterpret(), + data.size, + width, + height, + format.cValue, + rowStride, + pixStride + ) ?: error("Failed to create ZXing_ImageView") @Suppress("unused") @OptIn(ExperimentalNativeApi::class) private val pinnedDataCleaner = createCleaner(pinnedData) { it.unpin() } + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + override val cValueCleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) } } + @OptIn(ExperimentalForeignApi::class) enum class ImageFormat(internal val cValue: ZXing_ImageFormat) { None(ZXing_ImageFormat_None), @@ -57,3 +69,25 @@ enum class ImageFormat(internal val cValue: ZXing_ImageFormat) { @OptIn(ExperimentalForeignApi::class) fun ZXing_ImageFormat.parseIntoImageFormat(): ImageFormat? = ImageFormat.entries.firstOrNull { it.cValue == this } + +@ExperimentalWriterApi +@OptIn(ExperimentalForeignApi::class) +class Image(val cValueImage: CValuesRef) : ImageView() { + @Suppress("unchecked_cast") + override val cValue: CValuesRef = cValueImage as CValuesRef + + val data: ByteArray get() = ZXing_Image_data(cValueImage)?.run { + readBytes(width * height).also { ZXing_free(this) } + }?.takeUnless { it.isEmpty() } ?: throw OutOfMemoryError() + val width: Int get() = ZXing_Image_width(cValueImage) + val height: Int get() = ZXing_Image_height(cValueImage) + val format: ImageFormat get() = ZXing_Image_format(cValueImage).parseIntoImageFormat() ?: error("Unknown format ${ZXing_Image_format(cValueImage)} for image") + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + override val cValueCleaner = createCleaner(cValueImage) { ZXing_Image_delete(it) } +} + +@ExperimentalWriterApi +@OptIn(ExperimentalForeignApi::class) +fun CValuesRef.toKObject(): Image = Image(this) diff --git a/wrappers/kn/src/nativeTest/kotlin/Test.kt b/wrappers/kn/src/nativeTest/kotlin/Test.kt index d690ff3a8e..f11c827ada 100644 --- a/wrappers/kn/src/nativeTest/kotlin/Test.kt +++ b/wrappers/kn/src/nativeTest/kotlin/Test.kt @@ -19,7 +19,7 @@ class BarcodeReaderTest { if (it == '0') 255.toByte() else 0.toByte() } - val iv = ImageView(data.toByteArray(), data.size, 1, ImageFormat.Lum) + val iv = ImageViewImplNoCopy(data.toByteArray(), data.size, 1, ImageFormat.Lum) val br = BarcodeReader().apply { binarizer = Binarizer.BoolCast } @@ -38,4 +38,46 @@ class BarcodeReaderTest { assertEquals(PointI(4, 0), res.position.topLeft) assertEquals(1, res.lineCount) } + + @Test + @OptIn(ExperimentalNativeApi::class, ExperimentalWriterApi::class) + fun `create write and read barcode with text`() { + val text = "I have the best words." + val barcode = Barcode.fromText(text, BarcodeFormat.DataMatrix) + val image = barcode.toImage() + + val res = BarcodeReader.read(image).firstOrNull() + + assertNotNull(res) + assert(res.isValid) + assertEquals(BarcodeFormat.DataMatrix, res.format) + assertEquals(text, res.text) + assertContentEquals(text.encodeToByteArray(), res.bytes) + assert(!res.hasECI) + assertEquals(ContentType.Text, res.contentType) + assertEquals(0, res.orientation) + assertEquals(PointI(1, 1), res.position.topLeft) + assertEquals(0, res.lineCount) + } + + @Test + @OptIn(ExperimentalNativeApi::class, ExperimentalWriterApi::class) + fun `create write and read barcode with bytes`() { + val text = "I have the best words." + val barcode = Barcode.fromBytes(text.encodeToByteArray(), BarcodeFormat.DataMatrix) + val image = barcode.toImage() + + val res = BarcodeReader.read(image).firstOrNull() + + assertNotNull(res) + assert(res.isValid) + assertEquals(BarcodeFormat.DataMatrix, res.format) + assertEquals(text, res.text) + assertContentEquals(text.encodeToByteArray(), res.bytes) + assert(res.hasECI) + assertEquals(ContentType.Binary, res.contentType) + assertEquals(0, res.orientation) + assertEquals(PointI(1, 1), res.position.topLeft) + assertEquals(0, res.lineCount) + } } From ae47c3f61966234c74b49af37558f9daf3c6deb5 Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 12 Apr 2024 17:24:45 +0800 Subject: [PATCH 04/14] kn: Image no longer derives from ImageView --- .../nativeMain/kotlin/zxingcpp/ImageView.kt | 108 ++++++++++-------- wrappers/kn/src/nativeTest/kotlin/Test.kt | 6 +- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt index 2665082cd2..1a35d524a3 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt @@ -13,43 +13,52 @@ import kotlin.experimental.ExperimentalNativeApi import kotlin.native.ref.Cleaner import kotlin.native.ref.createCleaner -@OptIn(ExperimentalForeignApi::class) -abstract class ImageView { - abstract val cValue: CValuesRef - +@OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class) +class ImageView( + val cValue: CValuesRef, private val pinnedData: Pinned? = null, @Suppress("unused") - @OptIn(ExperimentalNativeApi::class) - protected abstract val cValueCleaner: Cleaner -} - -@OptIn(ExperimentalForeignApi::class) -open class ImageViewImplNoCopy( - data: ByteArray, - width: Int, - height: Int, - format: ImageFormat, - rowStride: Int = 0, - pixStride: Int = 0, -) : ImageView() { - private val pinnedData = data.pin() - - final override val cValue: CPointer = ZXing_ImageView_new_checked( - pinnedData.addressOf(0).reinterpret(), - data.size, - width, - height, - format.cValue, - rowStride, - pixStride - ) ?: error("Failed to create ZXing_ImageView") - + private val cValueCleaner: Cleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) }, @Suppress("unused") - @OptIn(ExperimentalNativeApi::class) - private val pinnedDataCleaner = createCleaner(pinnedData) { it.unpin() } + private val pinnedDataCleaner: Cleaner? = pinnedData?.let { createCleaner(pinnedData) { it.unpin() } } +) { - @Suppress("unused") - @OptIn(ExperimentalNativeApi::class) - override val cValueCleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) } + constructor( + pinnedData: Pinned, + pinnedDataCleaner: Cleaner? = createCleaner(pinnedData) { it.unpin() }, + width: Int, + height: Int, + format: ImageFormat, + rowStride: Int = 0, + pixStride: Int = 0, + ) : this( + cValue = ZXing_ImageView_new_checked( + pinnedData.addressOf(0).reinterpret(), + pinnedData.get().size, + width, + height, + format.cValue, + rowStride, + pixStride, + ) ?: error("Failed to create ZXing_ImageView"), + pinnedData = pinnedData, + pinnedDataCleaner = pinnedDataCleaner + ) + + constructor( + data: ByteArray, + width: Int, + height: Int, + format: ImageFormat, + rowStride: Int = 0, + pixStride: Int = 0, + ) : this( + pinnedData = data.pin(), + width = width, + height = height, + format = format, + rowStride = rowStride, + pixStride = pixStride, + ) } @@ -72,20 +81,29 @@ fun ZXing_ImageFormat.parseIntoImageFormat(): ImageFormat? = @ExperimentalWriterApi @OptIn(ExperimentalForeignApi::class) -class Image(val cValueImage: CValuesRef) : ImageView() { - @Suppress("unchecked_cast") - override val cValue: CValuesRef = cValueImage as CValuesRef - - val data: ByteArray get() = ZXing_Image_data(cValueImage)?.run { - readBytes(width * height).also { ZXing_free(this) } - }?.takeUnless { it.isEmpty() } ?: throw OutOfMemoryError() - val width: Int get() = ZXing_Image_width(cValueImage) - val height: Int get() = ZXing_Image_height(cValueImage) - val format: ImageFormat get() = ZXing_Image_format(cValueImage).parseIntoImageFormat() ?: error("Unknown format ${ZXing_Image_format(cValueImage)} for image") +class Image(val cValue: CValuesRef) { + val data: ByteArray + get() = ZXing_Image_data(cValue)?.run { + readBytes(width * height).also { ZXing_free(this) } + }?.takeUnless { it.isEmpty() } ?: throw OutOfMemoryError() + val width: Int get() = ZXing_Image_width(cValue) + val height: Int get() = ZXing_Image_height(cValue) + val format: ImageFormat + get() = ZXing_Image_format(cValue).parseIntoImageFormat() ?: error( + "Unknown format ${ + ZXing_Image_format( + cValue + ) + } for image" + ) @Suppress("unused") @OptIn(ExperimentalNativeApi::class) - override val cValueCleaner = createCleaner(cValueImage) { ZXing_Image_delete(it) } + val cValueCleaner = createCleaner(cValue) { ZXing_Image_delete(it) } + + @Suppress("unchecked_cast") + @OptIn(ExperimentalNativeApi::class) + fun asImageView(): ImageView = ImageView(cValue as CValuesRef, null, cValueCleaner, null) } @ExperimentalWriterApi diff --git a/wrappers/kn/src/nativeTest/kotlin/Test.kt b/wrappers/kn/src/nativeTest/kotlin/Test.kt index f11c827ada..46d12a3ac1 100644 --- a/wrappers/kn/src/nativeTest/kotlin/Test.kt +++ b/wrappers/kn/src/nativeTest/kotlin/Test.kt @@ -19,7 +19,7 @@ class BarcodeReaderTest { if (it == '0') 255.toByte() else 0.toByte() } - val iv = ImageViewImplNoCopy(data.toByteArray(), data.size, 1, ImageFormat.Lum) + val iv = ImageView(data.toByteArray(), data.size, 1, ImageFormat.Lum) val br = BarcodeReader().apply { binarizer = Binarizer.BoolCast } @@ -46,7 +46,7 @@ class BarcodeReaderTest { val barcode = Barcode.fromText(text, BarcodeFormat.DataMatrix) val image = barcode.toImage() - val res = BarcodeReader.read(image).firstOrNull() + val res = BarcodeReader.read(image.asImageView()).firstOrNull() assertNotNull(res) assert(res.isValid) @@ -67,7 +67,7 @@ class BarcodeReaderTest { val barcode = Barcode.fromBytes(text.encodeToByteArray(), BarcodeFormat.DataMatrix) val image = barcode.toImage() - val res = BarcodeReader.read(image).firstOrNull() + val res = BarcodeReader.read(image.asImageView()).firstOrNull() assertNotNull(res) assert(res.isValid) From 4c5189b9c468039e8d00401a1e34899efa37f1a2 Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 12 Apr 2024 19:31:41 +0800 Subject: [PATCH 05/14] kn: BarcodeWriter: Add copyright texts --- wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt index 93e8ed2eb8..ec4257d758 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt @@ -1,3 +1,8 @@ +/* +* Copyright 2024 ISNing +*/ +// SPDX-License-Identifier: Apache-2.0 + package zxingcpp import cnames.structs.ZXing_CreatorOptions From 942cd8835edae4001d6cb8e61d4b1698f64873f5 Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 26 Apr 2024 22:07:35 +0800 Subject: [PATCH 06/14] fixup! kn: Image no longer derives from ImageView --- wrappers/kn/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wrappers/kn/README.md b/wrappers/kn/README.md index 9af3753c5a..839c22dc6a 100644 --- a/wrappers/kn/README.md +++ b/wrappers/kn/README.md @@ -19,14 +19,13 @@ import zxingcpp.BarcodeFormat import zxingcpp.BarcodeReader import zxingcpp.ImageFormat import zxingcpp.ImageView -import zxingcpp.ImageViewImplNoCopy val data: ByteArray = ... // the image data val width: Int = ... // the image width val height: Int = ... // the image height val format: ImageFormat = ImageFormat.Lum // ImageFormat.Lum assumes grey scale image data -val image: ImageView = ImageViewImplNoCopy(data, width, height, format) +val image: ImageView = ImageView(data, width, height, format) val barcodeReader = BarcodeReader().apply { formats = setOf(BarcodeFormat.EAN13, BarcodeFormat.QRCode) tryHarder = true From 79b4d6682eb25825da7db82364347c7d72ca0979 Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 26 Apr 2024 22:19:20 +0800 Subject: [PATCH 07/14] kn: Refactor constructors for improved clarity and simplicity This commit addresses the use of fromText and fromBytes methods for constructing objects from strings or byte arrays. The changes include: Replacing fromText and fromBytes with overloaded constructors that take either a String or ByteArray parameter directly Removing the companion object since the secondary constructors handle the different input types Improves code clarity by using language features like function overloading instead of specially named methods These updates simplify the API by leveraging Kotlin's capabilities for constructor overloading based on parameter types. It makes the code more idiomatic and readable. --- .../src/nativeMain/kotlin/zxingcpp/Barcode.kt | 36 ++++++++++--------- wrappers/kn/src/nativeTest/kotlin/Test.kt | 4 +-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt index 98cc1a63d7..0815eecbfc 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt @@ -51,24 +51,28 @@ fun ZXing_Position.toKObject(): Position = Position( bottomLeft.toKObject(), ) +class BarcodeConstructionException(message: String?) : Exception("Failed to construct barcode: $message") + @OptIn(ExperimentalForeignApi::class) class Barcode(val cValue: CValuesRef) { - companion object { - @ExperimentalWriterApi - fun fromText(text: String, opts: CreatorOptions): Barcode = - ZXing_CreateBarcodeFromText(text, text.length, opts.cValue)?.toKObject() - ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) - @ExperimentalWriterApi - fun fromText(text: String, format: BarcodeFormat): Barcode = - fromText(text, CreatorOptions(format)) - @ExperimentalWriterApi - fun fromBytes(bytes: ByteArray, opts: CreatorOptions): Barcode = - ZXing_CreateBarcodeFromBytes(bytes.refTo(0), bytes.size, opts.cValue)?.toKObject() - ?: throw BarcodeReadingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) - @ExperimentalWriterApi - fun fromBytes(bytes: ByteArray, format: BarcodeFormat): Barcode = - fromBytes(bytes, CreatorOptions(format)) - } + + @OptIn(ExperimentalWriterApi::class) + constructor(text: String, opts: CreatorOptions) : this( + ZXing_CreateBarcodeFromText(text, text.length, opts.cValue) + ?: throw BarcodeConstructionException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + ) + + @OptIn(ExperimentalWriterApi::class) + constructor(text: String, format: BarcodeFormat) : this(text, CreatorOptions(format)) + + @OptIn(ExperimentalWriterApi::class) + constructor(bytes: ByteArray, opts: CreatorOptions) : this( + ZXing_CreateBarcodeFromBytes(bytes.refTo(0), bytes.size, opts.cValue) + ?: throw BarcodeConstructionException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) + ) + + @OptIn(ExperimentalWriterApi::class) + constructor(bytes: ByteArray, format: BarcodeFormat) : this(bytes, CreatorOptions(format)) val isValid: Boolean get() = ZXing_Barcode_isValid(cValue) diff --git a/wrappers/kn/src/nativeTest/kotlin/Test.kt b/wrappers/kn/src/nativeTest/kotlin/Test.kt index 46d12a3ac1..24f0f0be90 100644 --- a/wrappers/kn/src/nativeTest/kotlin/Test.kt +++ b/wrappers/kn/src/nativeTest/kotlin/Test.kt @@ -43,7 +43,7 @@ class BarcodeReaderTest { @OptIn(ExperimentalNativeApi::class, ExperimentalWriterApi::class) fun `create write and read barcode with text`() { val text = "I have the best words." - val barcode = Barcode.fromText(text, BarcodeFormat.DataMatrix) + val barcode = Barcode(text, BarcodeFormat.DataMatrix) val image = barcode.toImage() val res = BarcodeReader.read(image.asImageView()).firstOrNull() @@ -64,7 +64,7 @@ class BarcodeReaderTest { @OptIn(ExperimentalNativeApi::class, ExperimentalWriterApi::class) fun `create write and read barcode with bytes`() { val text = "I have the best words." - val barcode = Barcode.fromBytes(text.encodeToByteArray(), BarcodeFormat.DataMatrix) + val barcode = Barcode(text.encodeToByteArray(), BarcodeFormat.DataMatrix) val image = barcode.toImage() val res = BarcodeReader.read(image.asImageView()).firstOrNull() From 4987f4948fa831ceab98237b856ee52e752886be Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 26 Apr 2024 22:53:13 +0800 Subject: [PATCH 08/14] kn: Add documentation for experimental writer api --- wrappers/kn/README.md | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/wrappers/kn/README.md b/wrappers/kn/README.md index 839c22dc6a..2be127ed4b 100644 --- a/wrappers/kn/README.md +++ b/wrappers/kn/README.md @@ -12,6 +12,8 @@ to your `build.gradle.kts` file in the `dependencies` section of `nativeMain` so ## Use +### Reading + A trivial use case looks like this: ```kotlin @@ -40,6 +42,48 @@ barcodeReader.read(image).joinToString("\n") { barcode: Barcode -> Here you have to load your image into memory by yourself and pass the decoded data to the constructor of `ImageView`. +### Writing + +A trivial use case looks like this: + +```kotlin +import zxingcpp.BarcodeFormat +import zxingcpp.BarcodeWriter +import zxingcpp.CreatorOptions +import zxingcpp.ImageFormat +import zxingcpp.ImageView +import zxingcpp.toSVG +import zxingcpp.toImage + +val text: String = "Hello, World!" +val format = BarcodeFormat.QRCode +val width: Int = 256 +val height: Int = 256 + +val opts = CreatorOptions().apply { + format = BarcodeFormat.QRCode + // more options, see documentation +} + +val barcode = Barcode(text, opts) +// or +val barcode2 = Barcode(text, format) + +val barcodeWriter = BarcodeWriter().apply { + rotate = 10 + // more options, see documentation +} + +val svg: String = barcodeWriter.writeToSVG(barcode) +val image: ImageView = barcodeWriter.writeToImage(barcode) +// or +val svg: String = barcode.toSVG() +val image: ImageView = barcode.toImage() +``` + +> Note: The Writer api is still experimental and may change in future versions. +> You will have to opt-in `zxingcpp.ExperimentalWriterApi` to use it. + ## Build locally 1. Install JDK, CMake and Android NDK(With `$ANDROID_NDK` correctly configured) and ensure their From 903c8d5e8e1211cbeebc5dfa7f665e12b4a65136 Mon Sep 17 00:00:00 2001 From: ISNing Date: Fri, 26 Apr 2024 23:10:57 +0800 Subject: [PATCH 09/14] kn: Revert ImageView class changes --- .../nativeMain/kotlin/zxingcpp/ImageView.kt | 61 ++++++------------- wrappers/kn/src/nativeTest/kotlin/Test.kt | 4 +- 2 files changed, 22 insertions(+), 43 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt index 1a35d524a3..2625fdcd81 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt @@ -10,55 +10,36 @@ import cnames.structs.ZXing_ImageView import kotlinx.cinterop.* import zxingcpp.cinterop.* import kotlin.experimental.ExperimentalNativeApi -import kotlin.native.ref.Cleaner import kotlin.native.ref.createCleaner @OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class) class ImageView( - val cValue: CValuesRef, private val pinnedData: Pinned? = null, - @Suppress("unused") - private val cValueCleaner: Cleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) }, - @Suppress("unused") - private val pinnedDataCleaner: Cleaner? = pinnedData?.let { createCleaner(pinnedData) { it.unpin() } } + val data: ByteArray, + val width: Int, + val height: Int, + val format: ImageFormat, + val rowStride: Int = 0, + val pixStride: Int = 0, ) { - - constructor( - pinnedData: Pinned, - pinnedDataCleaner: Cleaner? = createCleaner(pinnedData) { it.unpin() }, - width: Int, - height: Int, - format: ImageFormat, - rowStride: Int = 0, - pixStride: Int = 0, - ) : this( - cValue = ZXing_ImageView_new_checked( + private val pinnedData = data.pin() + val cValue: CPointer? = + ZXing_ImageView_new_checked( pinnedData.addressOf(0).reinterpret(), - pinnedData.get().size, + data.size, width, height, format.cValue, rowStride, - pixStride, - ) ?: error("Failed to create ZXing_ImageView"), - pinnedData = pinnedData, - pinnedDataCleaner = pinnedDataCleaner - ) + pixStride + ) + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + private val cValueCleaner = createCleaner(cValue) { ZXing_ImageView_delete(it) } - constructor( - data: ByteArray, - width: Int, - height: Int, - format: ImageFormat, - rowStride: Int = 0, - pixStride: Int = 0, - ) : this( - pinnedData = data.pin(), - width = width, - height = height, - format = format, - rowStride = rowStride, - pixStride = pixStride, - ) + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + private val pinnedDataCleaner = createCleaner(pinnedData) { it.unpin() } } @@ -101,9 +82,7 @@ class Image(val cValue: CValuesRef) { @OptIn(ExperimentalNativeApi::class) val cValueCleaner = createCleaner(cValue) { ZXing_Image_delete(it) } - @Suppress("unchecked_cast") - @OptIn(ExperimentalNativeApi::class) - fun asImageView(): ImageView = ImageView(cValue as CValuesRef, null, cValueCleaner, null) + fun toImageView(): ImageView = ImageView(data, width, height, format) } @ExperimentalWriterApi diff --git a/wrappers/kn/src/nativeTest/kotlin/Test.kt b/wrappers/kn/src/nativeTest/kotlin/Test.kt index 24f0f0be90..d13a6b2dcc 100644 --- a/wrappers/kn/src/nativeTest/kotlin/Test.kt +++ b/wrappers/kn/src/nativeTest/kotlin/Test.kt @@ -46,7 +46,7 @@ class BarcodeReaderTest { val barcode = Barcode(text, BarcodeFormat.DataMatrix) val image = barcode.toImage() - val res = BarcodeReader.read(image.asImageView()).firstOrNull() + val res = BarcodeReader.read(image.toImageView()).firstOrNull() assertNotNull(res) assert(res.isValid) @@ -67,7 +67,7 @@ class BarcodeReaderTest { val barcode = Barcode(text.encodeToByteArray(), BarcodeFormat.DataMatrix) val image = barcode.toImage() - val res = BarcodeReader.read(image.asImageView()).firstOrNull() + val res = BarcodeReader.read(image.toImageView()).firstOrNull() assertNotNull(res) assert(res.isValid) From dbc3617c9f82ac53e94a7e2b2a79a32311dbc542 Mon Sep 17 00:00:00 2001 From: ISNing Date: Sat, 4 May 2024 14:18:43 +0800 Subject: [PATCH 10/14] kn: ImageView: Remove redundant opt-in ExperimentalNativeApi --- wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt index 2625fdcd81..e88f5fcaa2 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt @@ -12,7 +12,7 @@ import zxingcpp.cinterop.* import kotlin.experimental.ExperimentalNativeApi import kotlin.native.ref.createCleaner -@OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class) +@OptIn(ExperimentalForeignApi::class) class ImageView( val data: ByteArray, val width: Int, From aac289e8638b409d693dfd11c8f0f55cc4f10fa1 Mon Sep 17 00:00:00 2001 From: ISNing Date: Sat, 4 May 2024 14:28:41 +0800 Subject: [PATCH 11/14] kn: Remove the BarcodeWriter class --- .../src/nativeMain/kotlin/zxingcpp/Barcode.kt | 12 ++++++++-- .../kotlin/zxingcpp/BarcodeWriter.kt | 24 ------------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt index 0815eecbfc..12383a20b7 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt @@ -153,11 +153,19 @@ class Barcode(val cValue: CValuesRef) { } } +@OptIn(ExperimentalForeignApi::class) @ExperimentalWriterApi -fun Barcode.toSVG(opts: WriterOptions? = null): String = BarcodeWriter.writeToSVG(this, opts) +fun Barcode.toSVG(opts: WriterOptions? = null): String = cValue.usePinned { + ZXing_WriteBarcodeToSVG(it.get(), opts?.cValue)?.toKStringNullPtrHandledAndFree() + ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) +} +@OptIn(ExperimentalForeignApi::class) @ExperimentalWriterApi -fun Barcode.toImage(opts: WriterOptions? = null): Image = BarcodeWriter.writeToImage(this, opts) +fun Barcode.toImage(opts: WriterOptions? = null): Image = cValue.usePinned { + ZXing_WriteBarcodeToImage(it.get(), opts?.cValue)?.toKObject() + ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) +} @OptIn(ExperimentalForeignApi::class) fun CValuesRef.toKObject(): Barcode = Barcode(this) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt index ec4257d758..b7b432cf07 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/BarcodeWriter.kt @@ -17,30 +17,6 @@ import kotlin.native.ref.createCleaner @Retention(AnnotationRetention.BINARY) annotation class ExperimentalWriterApi - -@ExperimentalWriterApi -@OptIn(ExperimentalForeignApi::class) -class BarcodeWriter : WriterOptions() { - fun writeToSVG(barcode: Barcode): String = Companion.writeToSVG(barcode, this) - - fun writeToImage(barcode: Barcode): Image = Companion.writeToImage(barcode, this) - - companion object { - @OptIn(ExperimentalForeignApi::class) - fun writeToSVG(barcode: Barcode, opts: WriterOptions? = null): String = barcode.cValue.usePinned { - ZXing_WriteBarcodeToSVG(it.get(), opts?.cValue)?.toKStringNullPtrHandledAndFree() - ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) - } - - @OptIn(ExperimentalForeignApi::class) - fun writeToImage(barcode: Barcode, opts: WriterOptions? = null): Image = barcode.cValue.usePinned { - ZXing_WriteBarcodeToImage(it.get(), opts?.cValue)?.toKObject() - ?: throw BarcodeWritingException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) - } - - } -} - class BarcodeWritingException(message: String?) : Exception("Failed to write barcode: $message") @ExperimentalWriterApi From e6eca90dadcb55a9c30ab8250243701162f3fca6 Mon Sep 17 00:00:00 2001 From: ISNing Date: Sat, 4 May 2024 14:29:19 +0800 Subject: [PATCH 12/14] kn: Mark Barcode constructors as ExperimentalWriterApi --- wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt index 12383a20b7..9eda90c792 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/Barcode.kt @@ -56,22 +56,22 @@ class BarcodeConstructionException(message: String?) : Exception("Failed to cons @OptIn(ExperimentalForeignApi::class) class Barcode(val cValue: CValuesRef) { - @OptIn(ExperimentalWriterApi::class) + @ExperimentalWriterApi constructor(text: String, opts: CreatorOptions) : this( ZXing_CreateBarcodeFromText(text, text.length, opts.cValue) ?: throw BarcodeConstructionException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) ) - @OptIn(ExperimentalWriterApi::class) + @ExperimentalWriterApi constructor(text: String, format: BarcodeFormat) : this(text, CreatorOptions(format)) - @OptIn(ExperimentalWriterApi::class) + @ExperimentalWriterApi constructor(bytes: ByteArray, opts: CreatorOptions) : this( ZXing_CreateBarcodeFromBytes(bytes.refTo(0), bytes.size, opts.cValue) ?: throw BarcodeConstructionException(ZXing_LastErrorMsg()?.toKStringNullPtrHandledAndFree()) ) - @OptIn(ExperimentalWriterApi::class) + @ExperimentalWriterApi constructor(bytes: ByteArray, format: BarcodeFormat) : this(bytes, CreatorOptions(format)) val isValid: Boolean From a2cea2de74e1e8dd6b9d29812b3f7851e393f710 Mon Sep 17 00:00:00 2001 From: ISNing Date: Sat, 4 May 2024 14:29:39 +0800 Subject: [PATCH 13/14] kn: Correct example code in README --- wrappers/kn/README.md | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/wrappers/kn/README.md b/wrappers/kn/README.md index 2be127ed4b..ddb2ebb758 100644 --- a/wrappers/kn/README.md +++ b/wrappers/kn/README.md @@ -47,38 +47,30 @@ Here you have to load your image into memory by yourself and pass the decoded da A trivial use case looks like this: ```kotlin -import zxingcpp.BarcodeFormat -import zxingcpp.BarcodeWriter -import zxingcpp.CreatorOptions -import zxingcpp.ImageFormat -import zxingcpp.ImageView -import zxingcpp.toSVG -import zxingcpp.toImage +import zxingcpp.* val text: String = "Hello, World!" val format = BarcodeFormat.QRCode -val width: Int = 256 -val height: Int = 256 -val opts = CreatorOptions().apply { - format = BarcodeFormat.QRCode - // more options, see documentation -} +@OptIn(ExperimentalWriterApi::class) +val cOpts = CreatorOptions(format) // more options, see documentation -val barcode = Barcode(text, opts) +@OptIn(ExperimentalWriterApi::class) +val barcode = Barcode(text, cOpts) // or -val barcode2 = Barcode(text, format) +@OptIn(ExperimentalWriterApi::class) +val barcode2 = Barcode(text.encodeToByteArray(), format) -val barcodeWriter = BarcodeWriter().apply { - rotate = 10 +@OptIn(ExperimentalWriterApi::class) +val wOpts = WriterOptions().apply { + sizeHint = 400 // more options, see documentation } -val svg: String = barcodeWriter.writeToSVG(barcode) -val image: ImageView = barcodeWriter.writeToImage(barcode) -// or -val svg: String = barcode.toSVG() -val image: ImageView = barcode.toImage() +@OptIn(ExperimentalWriterApi::class) +val svg: String = barcode.toSVG(wOpts) +@OptIn(ExperimentalWriterApi::class) +val image: Image = barcode.toImage(wOpts) ``` > Note: The Writer api is still experimental and may change in future versions. From 7c4afeafab364428061fc8c0d9b0c61b7c18bfc9 Mon Sep 17 00:00:00 2001 From: ISNing Date: Sat, 4 May 2024 14:35:39 +0800 Subject: [PATCH 14/14] kn: Mark error from Image.format as internal error --- wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt index e88f5fcaa2..2f8fdb7f2c 100644 --- a/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt +++ b/wrappers/kn/src/nativeMain/kotlin/zxingcpp/ImageView.kt @@ -71,11 +71,8 @@ class Image(val cValue: CValuesRef) { val height: Int get() = ZXing_Image_height(cValue) val format: ImageFormat get() = ZXing_Image_format(cValue).parseIntoImageFormat() ?: error( - "Unknown format ${ - ZXing_Image_format( - cValue - ) - } for image" + "Unknown format ${ZXing_Image_format(cValue)} for image, " + + "this is an internal error, please report it to the library maintainers." ) @Suppress("unused") pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy