Skip to content

Commit

Permalink
Add support for UPN QR, fixes #57
Browse files Browse the repository at this point in the history
  • Loading branch information
gredler committed Feb 28, 2024
1 parent 5b491dd commit 148095f
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ and data.
### Recent Releases

#### Okapi Barcode 0.4.3
- Add support for UPN QR
- Add support for DPD Code
- Add support for Swiss QR Code
- Add support for specifying ECI mode explicitly
Expand Down
32 changes: 20 additions & 12 deletions src/main/java/uk/org/okapibarcode/backend/QrCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
* <p>Implements QR Code bar code symbology According to ISO/IEC 18004:2015.
Expand Down Expand Up @@ -169,6 +170,8 @@ private enum QrMode {
protected int minVersion = 1;
protected int preferredVersion;
protected EccLevel preferredEccLevel = EccLevel.L;
protected boolean improveEccLevelIfPossible = true;
protected boolean forceByteCompaction;

/**
* Sets the preferred symbol size / version. This value may be ignored if the data
Expand Down Expand Up @@ -288,11 +291,11 @@ protected void encode() {
}

QrMode[] inputMode = new QrMode[inputData.length];
defineMode(inputMode, inputData);
defineMode(inputMode, inputData, forceByteCompaction);
est_binlen = getBinaryLength(40, inputMode, inputData, gs1, eciMode);

ecc_level = this.preferredEccLevel;
switch (this.preferredEccLevel) {
switch (ecc_level) {
case L:
default:
max_cw = 2956;
Expand Down Expand Up @@ -435,14 +438,16 @@ protected void encode() {
}

/* Ensure maximum error correction capacity */
if (est_binlen <= (QR_DATA_CODEWORDS_M[version - 1] * 8)) {
ecc_level = EccLevel.M;
}
if (est_binlen <= (QR_DATA_CODEWORDS_Q[version - 1] * 8)) {
ecc_level = EccLevel.Q;
}
if (est_binlen <= (QR_DATA_CODEWORDS_H[version - 1] * 8)) {
ecc_level = EccLevel.H;
if (improveEccLevelIfPossible) {
if (est_binlen <= (QR_DATA_CODEWORDS_M[version - 1] * 8)) {
ecc_level = EccLevel.M;
}
if (est_binlen <= (QR_DATA_CODEWORDS_Q[version - 1] * 8)) {
ecc_level = EccLevel.Q;
}
if (est_binlen <= (QR_DATA_CODEWORDS_H[version - 1] * 8)) {
ecc_level = EccLevel.H;
}
}

targetCwCount = QR_DATA_CODEWORDS_L[version - 1];
Expand Down Expand Up @@ -511,9 +516,12 @@ protected void encode() {
}

/** Place Kanji / Binary / Alphanumeric / Numeric values in inputMode. */
private static void defineMode(QrMode[] inputMode, int[] inputData) {
private static void defineMode(QrMode[] inputMode, int[] inputData, boolean forceByteCompaction) {

int mlen;
if (forceByteCompaction) {
Arrays.fill(inputMode, 0, inputData.length, QrMode.BINARY);
return;
}

for (int i = 0; i < inputData.length; i++) {
if (inputData[i] > 0xff) {
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/uk/org/okapibarcode/backend/UpnQr.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2024 Daniel Gredler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.org.okapibarcode.backend;

/**
* UPN QR is a specialized type of QR Code symbol used by the Bank Association of Slovenia for their
* Universal Payment Order. It is mostly a spec-compliant QR Code, but it must use error correction
* level M, it must use version 15 (size 77x77), it must use ECI 4 (ISO-8859-2), and data must be
* encoded in byte mode.
*
* @author Daniel Gredler
* @see <a href="https://upn-qr.si/uploads/files/EN_Tehnicni%20standard%20UPN%20QR.pdf">UPN QR Form Specification, Section 5</a>
*/
public class UpnQr extends QrCode {

public UpnQr() {
eciMode = 4;
preferredVersion = 15;
preferredEccLevel = EccLevel.M;
improveEccLevelIfPossible = false;
forceByteCompaction = true;
}

@Override
public void setEciMode(int eciMode) {
if (eciMode != 4) {
throw new OkapiInputException("UPN QR requires ECI mode 4");
}
super.setEciMode(eciMode);
}

@Override
public void setPreferredVersion(int version) {
if (version != 15) {
throw new OkapiInputException("UPN QR requires version 15");
}
super.setPreferredVersion(version);
}

@Override
public void setPreferredEccLevel(EccLevel preferredEccLevel) {
if (preferredEccLevel != EccLevel.M) {
throw new OkapiInputException("UPN QR requires ECC level M");
}
super.setPreferredEccLevel(preferredEccLevel);
}
}
2 changes: 1 addition & 1 deletion src/main/java/uk/org/okapibarcode/util/EciMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
return Integer.valueOf(mode).hashCode();
return Integer.hashCode(mode);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PROPERTIES

preferredEccLevel=Q
content=test

ERROR

UPN QR requires ECC level M
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PROPERTIES

eciMode=3
content=test

ERROR

UPN QR requires ECI mode 4
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
@@ -0,0 +1,107 @@
PROPERTIES

content=UPNQR\n\n\n\n\nTestni uporabnik\nSlikarjeva ulica 1\n1000 Ljubljana\n00000000100\n\n\nTAXS\nAkontacija davka iz dejavnosti\n06.03.2024\nSI56011008881000030\nSI1911111119-40002\nPDP Prora\u010Dun dr\u017Eave\nGregor\u010Di\u010Deva ulica 20\n1000 Ljubljana\n218\n

eciMode=4
preferredVersion=15
preferredEccLevel=M
content=UPNQR\n\n\n\n\nTestni uporabnik\nSlikarjeva ulica 1\n1000 Ljubljana\n00000000100\n\n\nTAXS\nAkontacija davka iz dejavnosti\n06.03.2024\nSI56011008881000030\nSI1911111119-40002\nPDP Prora\u010Dun dr\u017Eave\nGregor\u010Di\u010Deva ulica 20\n1000 Ljubljana\n218\n

LOG

ECI Mode: 4
ECI Charset: ISO-8859-2
Encoding: BYTE 85 80 78 81 82 10 10 10 10 10 84 101 115 116 110 105 32 117 112 111 114 97 98 110 105 107 10 83 108 105 107 97 114 106 101 118 97 32 117 108 105 99 97 32 49 10 49 48 48 48 32 76 106 117 98 108 106 97 110 97 10 48 48 48 48 48 48 48 48 49 48 48 10 10 10 84 65 88 83 10 65 107 111 110 116 97 99 105 106 97 32 100 97 118 107 97 32 105 122 32 100 101 106 97 118 110 111 115 116 105 10 48 54 46 48 51 46 50 48 50 52 10 83 73 53 54 48 49 49 48 48 56 56 56 49 48 48 48 48 51 48 10 83 73 49 57 49 49 49 49 49 49 49 57 45 52 48 48 48 50 10 80 68 80 32 80 114 111 114 97 232 117 110 32 100 114 190 97 118 101 10 71 114 101 103 111 114 232 105 232 101 118 97 32 117 108 105 99 97 32 50 48 10 49 48 48 48 32 76 106 117 98 108 106 97 110 97 10 50 49 56 10
Codewords: 112 68 0 222 85 80 78 81 82 10 10 10 10 10 84 101 115 116 110 105 32 117 112 111 114 97 98 110 105 107 10 83 108 105 107 97 114 106 101 118 97 32 117 108 105 99 97 32 49 10 49 48 48 48 32 76 106 117 98 108 106 97 110 97 10 48 48 48 48 48 48 48 48 49 48 48 10 10 10 84 65 88 83 10 65 107 111 110 116 97 99 105 106 97 32 100 97 118 107 97 32 105 122 32 100 101 106 97 118 110 111 115 116 105 10 48 54 46 48 51 46 50 48 50 52 10 83 73 53 54 48 49 49 48 48 56 56 56 49 48 48 48 48 51 48 10 83 73 49 57 49 49 49 49 49 49 49 57 45 52 48 48 48 50 10 80 68 80 32 80 114 111 114 97 232 117 110 32 100 114 190 97 118 101 10 71 114 101 103 111 114 232 105 232 101 118 97 32 117 108 105 99 97 32 50 48 10 49 48 48 48 32 76 106 117 98 108 106 97 110 97 10 50 49 56 10 0 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17 236 17
Version: 15
ECC Level: M
Mask 000 Penalties: 1250 3254 4174 4174
Mask 001 Penalties: 1373 3809 4569 EXIT
Mask 010 Penalties: 986 2786 3506 3506
Mask 011 Penalties: 581 2801 3601 EXIT
Mask 100 Penalties: 676 2785 3625 EXIT
Mask 101 Penalties: 821 2819 3539 EXIT
Mask 110 Penalties: 763 2776 3496 3496
Mask 111 Penalties: 815 2993 3833 EXIT
Mask Pattern: 110
Blocks Merged: 1515 -> 1343

CODEWORDS

711111211113251213131122112113131212247
15113112221111521411413411142321111111151
11311142141311512312412212125211321111311
11311264133114121311141211313222131111311
113111131211<2122343511121255111311
151211421112333312111312136111211133151
71111111111111111111111111111111111111111111111111111111111111117
09111261432111213331131112151528
1271311112315211111212127124312242113
111123113212221111111111141314113133114222123
31321121323232212411112112154212112361
031113223121212215211318114112133211142
1122132111125221213115133314133134123
25111233313111241221121211115321161121211
11315121111161132111341132411111412111131211
0215114112211331121111111111111221331119111111111
8111215123111113122211211111141311111221111231
11423122342619211232211213211212231
1345111311211241212113124281313112213
0113113111321221112211134231211211131212121441
1112212111322141123471132131721212151
1121131332111511111322131311422313143111111
223212181111121131311323115222111321121112
02112313316211113223431113281221112311
038141<13212311281212131=
21231123213313111113512123421121116311111
1311113222112131114121124111111131212122511141
113311112121322311531331131111111933221
3161215191119112:12121146121
6121122172313215311121311115111122512
011211211111113411513311311111618111111122311
012113351122142111125211312512114322114
142113241154321112522132123343241
01212212111111111131111231312224131213221343111
12121221121211111111221112521121134121122121311112
0122113111211111413132111362222122232134111
01313311312311243131122213111121122111121111321
011811142112114111124112111129214912
01315112114322521113151211123111224333
05131111223531413131112123131511112162
0231312223211111112212542543115711111
021125211:31321112631325114151131
121243111112111214313172111111311161311114
13211131211111252132212121115421123124411
03112114711113131211612211314511214114
0413133151122133324331111111323132421
21851121215312311141612411111112531
0211132515211311131112512311342311111332
0231111211421411111131322221111132122314111132
0111231332251334521111131331111121211314
13512122519211215262542282
0221144111116111142111761431811223
021111143111231141213211111213112711153211111
0214311121311111121351112121141611321113511
124112112341113321112121311151321111111141212
0154112123231312215112111214111311122122122
01111121243225112112223212411163211111512
0212151121151117343131132241317123
21722211115112515121152214133312122
02211123411111423211211516112352;11
01111155111113221211262121;21311615
01113122112112141131122342411111221211122212131
11115122611623121311221211511331822
04211321232421131112113123121211313111512111
1421111123131212221223111222111223412111212211
1121131352321312116311111222212212226111
01124136531312<13212211131113122112
0414314311133231221111726236122111
01412231322111622243911114211111631
08111122144315121314132131613113311
711413332111112411123121112112;111111211
151113121111213323114112112313214412131112
113111311425541311312151122522722
11311112141321321211243521521162141112
113114121111121122112141112121311212111221122211122
15141211121273222111222132231311144121
712311311111114211241221494113111223
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PROPERTIES

preferredVersion=16
content=test

ERROR

UPN QR requires version 15

0 comments on commit 148095f

Please sign in to comment.