Implemented EpcQrCodeCreator

This commit is contained in:
dankito 2020-11-13 02:54:54 +01:00
parent 1b6e5c363b
commit 249fe588ed
10 changed files with 235 additions and 13 deletions

View File

@ -0,0 +1,20 @@
package net.codinux.banking.epcqrcode
open class CreatorParam(
var receiverName: String = "",
var iban: String = "",
var bic: String? = null,
var amount: Double? = null,
var reference: String? = null,
var noteToUser: String? = null,
var encoding: EpcQrCodeCharacterSet = EpcQrCodeCharacterSet.UTF_8
)

View File

@ -5,5 +5,5 @@ open class EncodeToQrCodeConfig(
open val width: Int = 500,
open val height: Int = 500,
open val format: ImageFormat = ImageFormat.PNG,
open val encoding: EpcQrCodeEncoding = EpcQrCodeEncoding.Utf8
open val encoding: EpcQrCodeCharacterSet = EpcQrCodeCharacterSet.UTF_8
)

View File

@ -0,0 +1,102 @@
package net.codinux.banking.epcqrcode
open class EpcQrCode(
/**
* 3 bytes.
* Always(?) has value "BCD".
*/
open val serviceTag: String,
/**
* 3 bytes.
* Has either value "001" or "002".
*/
open val version: EpcQrCodeVersion,
/**
* 1 byte.
* The values 1,2,3,4,5,6,7 and 8 determine the interpretation of data to be used.
* In that order they qualify UTF-8, ISO 8895-1, ISO 8895-2, ISO 8895-4, ISO 8895-5, ISO 8895- 7, ISO 8895-10 and ISO 8895-15
*/
open val coding: EpcQrCodeCharacterSet,
/**
* 3 bytes.
* The Function is defined by its key value: SCT - SEPA Credit Transfer
*/
open val function: String,
/**
* Receiver's BIC.
* Mandatory in Version 001, optional in Version 002.
* Either 8 or 11 bytes.
*/
open val bic: String?,
/**
* Receiver name.
* Max. 70 characters
*/
open val receiverName: String,
/**
* Receiver's IBAN.
* Max. 34 bytes.
*/
open val iban: String,
/**
* Three capital letter currency code.
* Only set if amount is also set.
* The only Currency value available with this version is EUR.
*/
open val currencyCode: String?,
/**
* Optional amount.
* Max. 12 bytes.
*/
open val amount: Double?, // TODO: use BigDecimal
/**
* Optional purpose code.
* Max. 4 bytes.
*/
open val purposeCode: String?,
open val remittanceReference: String?,
open val remittanceText: String?,
open val originatorInformation: String?
) {
companion object {
const val ServiceTagDefaultValue = "BCD"
const val FunctionDefaultValue = "SCT"
const val CurrencyCodeDefaultValue = "EUR"
const val PurposeCodeDefaultValue = "CHAR"
}
/**
* [remittanceReference] and [remittanceText] are mutual exclusive, that means one of both has to be set
* but they are never set both at the same time.
*
* remittance returns the one that is set.
*/
open val remittance: String
get() = remittanceReference ?: remittanceText ?: "" // they should never be both null
override fun toString(): String {
return "$receiverName $amount $currencyCode ${remittance}"
}
}

View File

@ -0,0 +1,22 @@
package net.codinux.banking.epcqrcode
enum class EpcQrCodeCharacterSet(val code: Int) {
UTF_8(1),
ISO_8895_1(2),
ISO_8895_2(3),
ISO_8895_4(4),
ISO_8895_5(5),
ISO_8895_7(6),
ISO_8895_10(7),
ISO_8895_15(8)
}

View File

@ -0,0 +1,65 @@
package net.codinux.banking.epcqrcode
open class EpcQrCodeCreator {
// companion object {
// val AmountNumberFormat = Decim
// }
open fun generate(param: CreatorParam): EpcQrCode {
return EpcQrCode(
EpcQrCode.ServiceTagDefaultValue,
EpcQrCodeVersion.Version2,
param.encoding,
EpcQrCode.FunctionDefaultValue,
param.bic,
param.receiverName,
param.iban,
EpcQrCode.CurrencyCodeDefaultValue,
param.amount,
EpcQrCode.PurposeCodeDefaultValue,
null,
param.reference,
param.noteToUser
)
}
open fun generateAsString(param: CreatorParam): String {
val epcQrCode = generate(param)
val epcQrCodeBuilder = StringBuilder()
epcQrCodeBuilder.appendLine(epcQrCode.serviceTag)
epcQrCodeBuilder.appendLine(epcQrCode.version.code)
epcQrCodeBuilder.appendLine(epcQrCode.coding.code)
epcQrCodeBuilder.appendLine(epcQrCode.function)
epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.bic))
epcQrCodeBuilder.appendLine(epcQrCode.receiverName)
epcQrCodeBuilder.appendLine(epcQrCode.iban)
epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.amount?.let { (epcQrCode.currencyCode ?: EpcQrCode.CurrencyCodeDefaultValue) + convert(it) }))
epcQrCodeBuilder.appendLine(epcQrCode.purposeCode)
epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.remittanceReference))
if (epcQrCode.remittanceText != null || epcQrCode.originatorInformation != null) {
epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.remittanceText))
}
if (epcQrCode.originatorInformation != null) {
epcQrCodeBuilder.appendLine(epcQrCode.originatorInformation)
}
return epcQrCodeBuilder.toString()
}
protected open fun convert(amount: Double): String {
return amount.toString() // TODO: ensure that it's converted to the correct format
}
protected open fun mapNullable(value: String?): String {
return value ?: ""
}
}

View File

@ -1,7 +0,0 @@
package net.codinux.banking.epcqrcode
enum class EpcQrCodeEncoding {
Utf8
}

View File

@ -0,0 +1,10 @@
package net.codinux.banking.epcqrcode
enum class EpcQrCodeVersion(val code: String) {
Version1("001"), // cannot name it '1'
Version2("002")
}

View File

@ -12,7 +12,7 @@ class QrCodeGenerator {
fun generateQrCode(informationToEncode: String, config: EncodeToQrCodeConfig = EncodeToQrCodeConfig()): ByteArray {
val hints = mutableMapOf<EncodeHintType, Any>()
hints[EncodeHintType.CHARACTER_SET] = config.encoding.name
hints[EncodeHintType.CHARACTER_SET] = map(config.encoding)
val bitMatrix = QRCodeWriter().encode(informationToEncode, BarcodeFormat.QR_CODE, config.width, config.height, hints)
@ -23,4 +23,12 @@ class QrCodeGenerator {
return outputStream.toByteArray()
}
private fun map(encoding: EpcQrCodeCharacterSet): String {
return when (encoding) {
EpcQrCodeCharacterSet.UTF_8 -> "UTF8"
else -> encoding.name.replace("ISO_8859", "ISO8859")
}
}
}

View File

@ -17,7 +17,8 @@ class MainActivity : AppCompatActivity() {
txtMessage.text = MppTest().showMessage()
val imageBytes = QrCodeGenerator().generateQrCode(MppTest().getTestEpcQrCodeContent())
val qrCodeContent = EpcQrCodeCreator().generateAsString(CreatorParam("Mahatma Gandhi", "IN00123456789876543210", null, 1234.56, "Struggle for independence"))
val imageBytes = QrCodeGenerator().generateQrCode(qrCodeContent)
imgGeneratedQrCode.setImageBitmap(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size))
}

View File

@ -4,8 +4,7 @@ import javafx.beans.property.SimpleObjectProperty
import javafx.scene.image.Image
import tornadofx.*
import java.io.ByteArrayInputStream
import net.codinux.banking.epcqrcode.MppTest
import net.codinux.banking.epcqrcode.QrCodeGenerator
import net.codinux.banking.epcqrcode.*
import org.slf4j.LoggerFactory
@ -16,9 +15,11 @@ class MainWindow : View(FX.messages["application.title"]) {
}
private val qrCodeContent = EpcQrCodeCreator().generateAsString(CreatorParam("Mahatma Gandhi", "IN00123456789876543210", null, 1234.56, "Struggle for independence")) // TODO: remove again
private val qrCodeGenerator = QrCodeGenerator()
private val qrCode = SimpleObjectProperty<Image>(generateQrCode(MppTest().getTestEpcQrCodeContent()))
private val qrCode = SimpleObjectProperty<Image>(generateQrCode(qrCodeContent))
override val root = vbox {