From f8dcc9daa755b57fe5336a11152f4d6d4224d4bd Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 11:54:27 +0100 Subject: [PATCH 01/23] Adds support for the ITF barcode format. This is commonly used to create barcodes for GTINs with 14 digits used for certain types of packaging (see https://en.wikipedia.org/wiki/ITF-14). Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index b8680a369..06ff48491 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -16,6 +16,7 @@ import com.google.zxing.datamatrix.DataMatrixWriter; import com.google.zxing.oned.Code128Writer; import com.google.zxing.oned.EAN13Writer; +import com.google.zxing.oned.ITFWriter; import com.google.zxing.qrcode.QRCodeWriter; import io.netty.handler.codec.http.HttpResponseStatus; import sirius.kernel.commons.Strings; @@ -79,9 +80,10 @@ private BarcodeFormat determineFormat(String format) { case "qr" -> BarcodeFormat.QR_CODE; case "code128" -> BarcodeFormat.CODE_128; case "ean" -> BarcodeFormat.EAN_13; + case "itf" -> BarcodeFormat.ITF; case "datamatrix" -> BarcodeFormat.DATA_MATRIX; default -> throw new IllegalArgumentException( - "Unsupported barcode type. Supported types are: qr, code128, ean, datamatrix"); + "Unsupported barcode type. Supported types are: qr, code128, ean, itf, datamatrix"); }; } @@ -90,6 +92,7 @@ private Writer determineWriter(BarcodeFormat format) { case QR_CODE -> new QRCodeWriter(); case CODE_128 -> new Code128Writer(); case EAN_13 -> new EAN13Writer(); + case ITF -> new ITFWriter(); case DATA_MATRIX -> new DataMatrixWriter(); default -> throw new IllegalArgumentException("Unsupported barcode type!"); }; From 9b15c59d705c757f2afb9cb666ba12c953a9a8aa Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 12:34:02 +0100 Subject: [PATCH 02/23] Automatically switches the format to ITF, if a GTIN-14 was submitted with format type "ean". Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 06ff48491..67c9a52aa 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -64,6 +64,11 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE return; } + // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given + if(BarcodeFormat.EAN_13 == format && content.length() == 14) { + format = BarcodeFormat.ITF; + } + String fileType = webContext.getFirstFilled("fileType").asString("jpg"); Writer writer = determineWriter(format); BitMatrix matrix = writer.encode(content, format, width, height); From e6ce5fced4991e3fc1f6080e7660306c64cd3061 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 12:34:35 +0100 Subject: [PATCH 03/23] Adds JavaDoc Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 67c9a52aa..fca54f327 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -50,6 +50,16 @@ public void qr(WebContext ctx) throws Exception { barcode(ctx, BarcodeFormat.QR_CODE); } + /** + * Creates a barcode for the given content. + *

+ * The parameter content determines the contents of the barcode. The parameters width and + * height determine its dimensions. + *

+ * + * @param webContext the current request + * @throws Exception in case an error occurred when generating the barcode + */ @Routed(value = "/barcode", priority = 999) public void barcode(WebContext webContext) throws Exception { barcode(webContext, determineFormat(webContext.get("type").asString())); From 64f54edbad9828da191f5ca7a6f8c7b9c031e35e Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 12:34:48 +0100 Subject: [PATCH 04/23] Fixes typos Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index fca54f327..616ffea9f 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -36,10 +36,10 @@ public class BarcodeController extends BasicController { /** - * Creates an QR code for the given content. + * Creates a QR code for the given content. *

- * The parameter content determines the contents of the qr code. The parameters with and - * height its dimensions. + * The parameter content determines the contents of the qr code. The parameters width and + * height determine its dimensions. *

* * @param ctx the current request From 442d636c3270cbee96f9ed3a5ef0582b10180dc3 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 14:29:38 +0100 Subject: [PATCH 05/23] Removes superfluous closing tag from JavaDoc Fixes: SIRI-487 Co-authored-by: Sascha Bieberstein --- src/main/java/sirius/web/util/BarcodeController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 616ffea9f..503bd222c 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -40,7 +40,6 @@ public class BarcodeController extends BasicController { *

* The parameter content determines the contents of the qr code. The parameters width and * height determine its dimensions. - *

* * @param ctx the current request * @throws Exception in case an error occurred when generating the qr code @@ -55,7 +54,6 @@ public void qr(WebContext ctx) throws Exception { *

* The parameter content determines the contents of the barcode. The parameters width and * height determine its dimensions. - *

* * @param webContext the current request * @throws Exception in case an error occurred when generating the barcode From 69a02af485d86ef452a86cf1a9536ee2b4ca4f12 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Thu, 25 Nov 2021 15:08:33 +0100 Subject: [PATCH 06/23] Code Style (reformat and rename) Fixes: SIRI-487 --- .../java/sirius/web/util/BarcodeController.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 503bd222c..1d5419648 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -41,12 +41,12 @@ public class BarcodeController extends BasicController { * The parameter content determines the contents of the qr code. The parameters width and * height determine its dimensions. * - * @param ctx the current request + * @param webContext the current request * @throws Exception in case an error occurred when generating the qr code */ @Routed(value = "/qr", priority = 999) - public void qr(WebContext ctx) throws Exception { - barcode(ctx, BarcodeFormat.QR_CODE); + public void qr(WebContext webContext) throws Exception { + barcode(webContext, BarcodeFormat.QR_CODE); } /** @@ -68,12 +68,13 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE int height = webContext.getFirstFilled("h", "height").asInt(200); String content = webContext.getFirstFilled("c", "content").asString(); if (Strings.isEmpty(content)) { - webContext.respondWith().direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); + webContext.respondWith() + .direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); return; } // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given - if(BarcodeFormat.EAN_13 == format && content.length() == 14) { + if (BarcodeFormat.EAN_13 == format && content.length() == 14) { format = BarcodeFormat.ITF; } @@ -81,9 +82,9 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE Writer writer = determineWriter(format); BitMatrix matrix = writer.encode(content, format, width, height); try (OutputStream out = webContext.respondWith() - .infinitelyCached() - .outputStream(HttpResponseStatus.OK, - MimeHelper.guessMimeType("barcode." + fileType))) { + .infinitelyCached() + .outputStream(HttpResponseStatus.OK, + MimeHelper.guessMimeType("barcode." + fileType))) { MatrixToImageWriter.writeToStream(matrix, fileType, out); } } From 31586bf665ca0a190a5b920ab77b57d060fa0b45 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 10:27:13 +0100 Subject: [PATCH 07/23] Centralizes barcode generation in the BarcodeController for all types except the special interleaved2of5checksummed Fixes: SIRI-487 --- .../handlers/BarcodePdfReplaceHandler.java | 57 ++++++++----------- .../sirius/web/util/BarcodeController.java | 29 +++++++++- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 4c0459d2b..f4d86928b 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -8,17 +8,16 @@ package sirius.web.templates.pdf.handlers; +import com.google.zxing.WriterException; import com.lowagie.text.pdf.Barcode; -import com.lowagie.text.pdf.Barcode128; -import com.lowagie.text.pdf.BarcodeEAN; import com.lowagie.text.pdf.BarcodeInter25; import org.xhtmlrenderer.extend.FSImage; import org.xhtmlrenderer.extend.UserAgentCallback; import org.xhtmlrenderer.pdf.ITextFSImage; import sirius.kernel.commons.Strings; import sirius.kernel.di.std.Register; +import sirius.web.util.BarcodeController; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.Color; import java.awt.Image; @@ -53,10 +52,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c throw new IllegalArgumentException("The URI is required to match the format 'barcode://type/content'"); } - Barcode code = createBarcode(barcodeInfo[0]); - code.setCode(padCodeIfNecessary(code, barcodeInfo[1])); - - Image awtImage = code.createAwtImage(Color.BLACK, Color.WHITE); + Image awtImage = getBarcodeImage(barcodeInfo[0], barcodeInfo[1], cssWidth, cssHeight); int scaleFactor = calculateBarcodeScaleFactor(cssWidth, cssHeight, awtImage); @@ -73,38 +69,33 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c return fsImage; } - private int calculateBarcodeScaleFactor(int cssWidth, int cssHeight, Image awtImage) { - return (int) Math.max(Math.ceil(cssWidth / (float) awtImage.getWidth(null)), - Math.ceil(cssHeight / (float) awtImage.getHeight(null))); - } + private Image getBarcodeImage(String barcodeType, String content, int width, int height) throws WriterException { + assertSupportedBarcodeType(barcodeType); - /** - * Creates an instance of {@link Barcode} that matches the given type descriptor. - * - * @param type the requested type - * @return the barcode - */ - @Nonnull - private Barcode createBarcode(String type) { - if (BARCODE_TYPE_CODE128.equalsIgnoreCase(type)) { - return new Barcode128(); + if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) { + Barcode code = new BarcodeInter25(); + code.setGenerateChecksum(true); + code.setCode(padCodeIfNecessary(code, content)); + return code.createAwtImage(Color.BLACK, Color.WHITE); } - if (BARCODE_TYPE_EAN.equalsIgnoreCase(type)) { - return new BarcodeEAN(); - } + return BarcodeController.getBarcodeImage(barcodeType, content, width, height); + } - if (BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(type)) { - return new BarcodeInter25(); - } + private int calculateBarcodeScaleFactor(int cssWidth, int cssHeight, Image awtImage) { + return (int) Math.max(Math.ceil(cssWidth / (float) awtImage.getWidth(null)), + Math.ceil(cssHeight / (float) awtImage.getHeight(null))); + } - if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(type)) { - Barcode code = new BarcodeInter25(); - code.setGenerateChecksum(true); - return code; + private void assertSupportedBarcodeType(String type) { + if (!BARCODE_TYPE_CODE128.equalsIgnoreCase(type) + && !BARCODE_TYPE_EAN.equalsIgnoreCase(type) + && !BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(type) + && !BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(type)) { + throw new UnsupportedOperationException(Strings.apply( + "Type '%s' is not supported. Supported types are: code128, ean, interleaved2of5, interleaved2of5checksummed.", + type)); } - - throw new UnsupportedOperationException(Strings.apply("Type '%s' is not supported", type)); } /** diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 1d5419648..c7aea1310 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -26,6 +26,7 @@ import sirius.web.http.MimeHelper; import sirius.web.http.WebContext; +import java.awt.Image; import java.io.IOException; import java.io.OutputStream; @@ -89,19 +90,41 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE } } - private BarcodeFormat determineFormat(String format) { + /** + * Gets an image of a barcode + * + * @param type the desired barcode type + * @param content the content of the barcode + * @param width the desired image width + * @param height the desired image height + * @return a barcode of the given data as an image + * @throws WriterException if generating the image fails + */ + public static Image getBarcodeImage(String type, String content, int width, int height) throws WriterException { + BarcodeFormat format = determineFormat(type); + // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given + if (BarcodeFormat.EAN_13 == format && content.length() == 14) { + format = BarcodeFormat.ITF; + } + + Writer writer = determineWriter(format); + BitMatrix matrix = writer.encode(content, format, width, height); + return MatrixToImageWriter.toBufferedImage(matrix); + } + + private static BarcodeFormat determineFormat(String format) { return switch (format) { case "qr" -> BarcodeFormat.QR_CODE; case "code128" -> BarcodeFormat.CODE_128; case "ean" -> BarcodeFormat.EAN_13; - case "itf" -> BarcodeFormat.ITF; + case "itf", "interleaved2of5" -> BarcodeFormat.ITF; case "datamatrix" -> BarcodeFormat.DATA_MATRIX; default -> throw new IllegalArgumentException( "Unsupported barcode type. Supported types are: qr, code128, ean, itf, datamatrix"); }; } - private Writer determineWriter(BarcodeFormat format) { + private static Writer determineWriter(BarcodeFormat format) { return switch (format) { case QR_CODE -> new QRCodeWriter(); case CODE_128 -> new Code128Writer(); From f25b315e24ce31d186e6eb9e0a3594f73cc69930 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 10:31:28 +0100 Subject: [PATCH 08/23] Sets default width and height Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index c7aea1310..498ae592b 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -108,7 +108,7 @@ public static Image getBarcodeImage(String type, String content, int width, int } Writer writer = determineWriter(format); - BitMatrix matrix = writer.encode(content, format, width, height); + BitMatrix matrix = writer.encode(content, format, width != -1 ? width : 200, height != -1 ? height : 200); return MatrixToImageWriter.toBufferedImage(matrix); } From f8864648881b6ab1d5eaac49ba2341bf25f17af2 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 10:36:57 +0100 Subject: [PATCH 09/23] Simplifies code padding Fixes: SIRI-487 --- .../handlers/BarcodePdfReplaceHandler.java | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index f4d86928b..3970fd8fd 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -75,7 +75,8 @@ private Image getBarcodeImage(String barcodeType, String content, int width, int if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) { Barcode code = new BarcodeInter25(); code.setGenerateChecksum(true); - code.setCode(padCodeIfNecessary(code, content)); + // Pads the code if necessary: Length is even but a checksum will be added + code.setCode(BarcodeInter25.keepNumbers(content).length() % 2 == 0 ? "0" + content : content); return code.createAwtImage(Color.BLACK, Color.WHITE); } @@ -97,32 +98,4 @@ private void assertSupportedBarcodeType(String type) { type)); } } - - /** - * Pads the code if necessary. - *

- * Unfortunately padding will not be added automatically when using interleaved2of5 or - * interleaved2of5checksummed. Thus we manually prepend a zero if the code length is uneven. - * - * @param code the instance of the barcode - * @param src the code from the src attribute - * @return the padded code, or the original code if padding was not needed - */ - private String padCodeIfNecessary(Barcode code, String src) { - if (code instanceof BarcodeInter25) { - int length = BarcodeInter25.keepNumbers(src).length(); - - // Length is uneven and no checksum will be added - if (length % 2 != 0 && !code.isGenerateChecksum()) { - return "0" + src; - } - - // Length is even but a checksum will be added - if (length % 2 == 0 && code.isGenerateChecksum()) { - return "0" + src; - } - } - - return src; - } } From 3a780290b69a0b00d22acaeec46ee29fb84579eb Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 10:39:33 +0100 Subject: [PATCH 10/23] Uses null-safe lowercase String for the switch statement Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 498ae592b..de6fb01d5 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -20,6 +20,7 @@ import com.google.zxing.qrcode.QRCodeWriter; import io.netty.handler.codec.http.HttpResponseStatus; import sirius.kernel.commons.Strings; +import sirius.kernel.commons.Value; import sirius.kernel.di.std.Register; import sirius.web.controller.BasicController; import sirius.web.controller.Routed; @@ -113,7 +114,7 @@ public static Image getBarcodeImage(String type, String content, int width, int } private static BarcodeFormat determineFormat(String format) { - return switch (format) { + return switch (Value.of(format).toLowerCase()) { case "qr" -> BarcodeFormat.QR_CODE; case "code128" -> BarcodeFormat.CODE_128; case "ean" -> BarcodeFormat.EAN_13; From 7e9252057198f94007583b98953ae06ed9216f65 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 10:49:02 +0100 Subject: [PATCH 11/23] Extracts method Fixes: SIRI-487 --- .../sirius/web/util/BarcodeController.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index de6fb01d5..f461da75b 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -69,16 +69,8 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE int width = webContext.getFirstFilled("w", "width").asInt(200); int height = webContext.getFirstFilled("h", "height").asInt(200); String content = webContext.getFirstFilled("c", "content").asString(); - if (Strings.isEmpty(content)) { - webContext.respondWith() - .direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); - return; - } - // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given - if (BarcodeFormat.EAN_13 == format && content.length() == 14) { - format = BarcodeFormat.ITF; - } + format = validateContentAndFormat(content, format, webContext); String fileType = webContext.getFirstFilled("fileType").asString("jpg"); Writer writer = determineWriter(format); @@ -103,10 +95,8 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE */ public static Image getBarcodeImage(String type, String content, int width, int height) throws WriterException { BarcodeFormat format = determineFormat(type); - // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given - if (BarcodeFormat.EAN_13 == format && content.length() == 14) { - format = BarcodeFormat.ITF; - } + + format = validateContentAndFormat(content, format, null); Writer writer = determineWriter(format); BitMatrix matrix = writer.encode(content, format, width != -1 ? width : 200, height != -1 ? height : 200); @@ -135,4 +125,18 @@ private static Writer determineWriter(BarcodeFormat format) { default -> throw new IllegalArgumentException("Unsupported barcode type!"); }; } + + private static BarcodeFormat validateContentAndFormat(String content, BarcodeFormat format, WebContext webContext) { + if (Strings.isEmpty(content) && webContext != null) { + webContext.respondWith() + .direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); + } + + // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given + if (BarcodeFormat.EAN_13 == format && content.length() == 14) { + return BarcodeFormat.ITF; + } + + return format; + } } From f50867721d9be02e4b2b1b6a7d90b01f87bb75cd Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 11:04:30 +0100 Subject: [PATCH 12/23] Fixes typo Fixes: SIRI-487 --- .../sirius/web/templates/pdf/ImageReplacedElementFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/templates/pdf/ImageReplacedElementFactory.java b/src/main/java/sirius/web/templates/pdf/ImageReplacedElementFactory.java index aaa19a9b2..4b240d557 100644 --- a/src/main/java/sirius/web/templates/pdf/ImageReplacedElementFactory.java +++ b/src/main/java/sirius/web/templates/pdf/ImageReplacedElementFactory.java @@ -26,7 +26,7 @@ import java.util.Optional; /** - * Used by the XHTMLRenderer (creating PDFs) to replace img elements by their references image. + * Used by the XHTMLRenderer (creating PDFs) to replace img elements by their referenced image. *

* Alongside http different URI protocols are supported. These are handled by classes extending * {@link PdfReplaceHandler}. From 79095bc257c37b4da45e45e95e8c3dc63123aee1 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 11:11:01 +0100 Subject: [PATCH 13/23] Restores code padding for interleaved2of5 without checksum Fixes: SIRI-487 --- .../templates/pdf/handlers/BarcodePdfReplaceHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 3970fd8fd..98f447c04 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -80,6 +80,12 @@ private Image getBarcodeImage(String barcodeType, String content, int width, int return code.createAwtImage(Color.BLACK, Color.WHITE); } + if (BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(barcodeType) + && BarcodeInter25.keepNumbers(content).length() % 2 != 0) { + // Pads the code if necessary: Length is uneven and no checksum will be added + content = "0" + content; + } + return BarcodeController.getBarcodeImage(barcodeType, content, width, height); } From 3f2d4561b62a7f40a1c07ef0e3b84c69f7f76fee Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 11:27:14 +0100 Subject: [PATCH 14/23] Renames method and actually returns in web context Fixes: SIRI-487 --- .../java/sirius/web/util/BarcodeController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index f461da75b..5132289b9 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -69,8 +69,13 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE int width = webContext.getFirstFilled("w", "width").asInt(200); int height = webContext.getFirstFilled("h", "height").asInt(200); String content = webContext.getFirstFilled("c", "content").asString(); + if (Strings.isEmpty(content)) { + webContext.respondWith() + .direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); + return; + } - format = validateContentAndFormat(content, format, webContext); + format = useItfFormatForGtin14(content, format); String fileType = webContext.getFirstFilled("fileType").asString("jpg"); Writer writer = determineWriter(format); @@ -96,7 +101,7 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE public static Image getBarcodeImage(String type, String content, int width, int height) throws WriterException { BarcodeFormat format = determineFormat(type); - format = validateContentAndFormat(content, format, null); + format = useItfFormatForGtin14(content, format); Writer writer = determineWriter(format); BitMatrix matrix = writer.encode(content, format, width != -1 ? width : 200, height != -1 ? height : 200); @@ -126,12 +131,7 @@ private static Writer determineWriter(BarcodeFormat format) { }; } - private static BarcodeFormat validateContentAndFormat(String content, BarcodeFormat format, WebContext webContext) { - if (Strings.isEmpty(content) && webContext != null) { - webContext.respondWith() - .direct(HttpResponseStatus.BAD_REQUEST, "Usage: /barcode?type=qr&content=...&w=200&h=200"); - } - + private static BarcodeFormat useItfFormatForGtin14(String content, BarcodeFormat format) { // Adjust the barcode format, if "type=ean" was submitted with the request and a GTIN-14 was given if (BarcodeFormat.EAN_13 == format && content.length() == 14) { return BarcodeFormat.ITF; From a71ce489ac43a7d04214d7be8acd2e8fa151bf27 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 11:34:10 +0100 Subject: [PATCH 15/23] Renames method Fixes: SIRI-487 --- .../templates/pdf/handlers/BarcodePdfReplaceHandler.java | 7 ++++--- src/main/java/sirius/web/util/BarcodeController.java | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 98f447c04..ad22eb176 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -52,7 +52,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c throw new IllegalArgumentException("The URI is required to match the format 'barcode://type/content'"); } - Image awtImage = getBarcodeImage(barcodeInfo[0], barcodeInfo[1], cssWidth, cssHeight); + Image awtImage = generateBarcodeImage(barcodeInfo[0], barcodeInfo[1], cssWidth, cssHeight); int scaleFactor = calculateBarcodeScaleFactor(cssWidth, cssHeight, awtImage); @@ -69,7 +69,8 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c return fsImage; } - private Image getBarcodeImage(String barcodeType, String content, int width, int height) throws WriterException { + private Image generateBarcodeImage(String barcodeType, String content, int width, int height) + throws WriterException { assertSupportedBarcodeType(barcodeType); if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) { @@ -86,7 +87,7 @@ private Image getBarcodeImage(String barcodeType, String content, int width, int content = "0" + content; } - return BarcodeController.getBarcodeImage(barcodeType, content, width, height); + return BarcodeController.generateBarcodeImage(barcodeType, content, width, height); } private int calculateBarcodeScaleFactor(int cssWidth, int cssHeight, Image awtImage) { diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 5132289b9..2a71cc798 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -89,7 +89,7 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE } /** - * Gets an image of a barcode + * Generates an image of a barcode * * @param type the desired barcode type * @param content the content of the barcode @@ -98,7 +98,8 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * @return a barcode of the given data as an image * @throws WriterException if generating the image fails */ - public static Image getBarcodeImage(String type, String content, int width, int height) throws WriterException { + public static Image generateBarcodeImage(String type, String content, int width, int height) + throws WriterException { BarcodeFormat format = determineFormat(type); format = useItfFormatForGtin14(content, format); From 79074b39abc02c67f6e4bbf2a3c499ff32fc375b Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 14:27:49 +0100 Subject: [PATCH 16/23] Returns a fixed size image. Scaling is done via css. Fixes: SIRI-487 --- .../templates/pdf/handlers/BarcodePdfReplaceHandler.java | 6 +++--- src/main/java/sirius/web/util/BarcodeController.java | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index ad22eb176..97f3a431d 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -52,7 +52,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c throw new IllegalArgumentException("The URI is required to match the format 'barcode://type/content'"); } - Image awtImage = generateBarcodeImage(barcodeInfo[0], barcodeInfo[1], cssWidth, cssHeight); + Image awtImage = generateBarcodeImage(barcodeInfo[0], barcodeInfo[1]); int scaleFactor = calculateBarcodeScaleFactor(cssWidth, cssHeight, awtImage); @@ -69,7 +69,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c return fsImage; } - private Image generateBarcodeImage(String barcodeType, String content, int width, int height) + private Image generateBarcodeImage(String barcodeType, String content) throws WriterException { assertSupportedBarcodeType(barcodeType); @@ -87,7 +87,7 @@ private Image generateBarcodeImage(String barcodeType, String content, int width content = "0" + content; } - return BarcodeController.generateBarcodeImage(barcodeType, content, width, height); + return BarcodeController.generateBarcodeImage(barcodeType, content); } private int calculateBarcodeScaleFactor(int cssWidth, int cssHeight, Image awtImage) { diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 2a71cc798..19ec1fb68 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -93,19 +93,17 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * * @param type the desired barcode type * @param content the content of the barcode - * @param width the desired image width - * @param height the desired image height - * @return a barcode of the given data as an image + * @return a barcode of the given data as a 200x200 px image * @throws WriterException if generating the image fails */ - public static Image generateBarcodeImage(String type, String content, int width, int height) + public static Image generateBarcodeImage(String type, String content) throws WriterException { BarcodeFormat format = determineFormat(type); format = useItfFormatForGtin14(content, format); Writer writer = determineWriter(format); - BitMatrix matrix = writer.encode(content, format, width != -1 ? width : 200, height != -1 ? height : 200); + BitMatrix matrix = writer.encode(content, format, 200, 200); return MatrixToImageWriter.toBufferedImage(matrix); } From da6e2a5d651f7f42fea6ed26d81391025807ca20 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 14:39:30 +0100 Subject: [PATCH 17/23] Renders interleaved2of5checksummed using zxing and calculates the checksum beforehand Fixes: SIRI-487 --- .../pdf/handlers/BarcodePdfReplaceHandler.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 97f3a431d..6d61f3eaf 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -9,7 +9,6 @@ package sirius.web.templates.pdf.handlers; import com.google.zxing.WriterException; -import com.lowagie.text.pdf.Barcode; import com.lowagie.text.pdf.BarcodeInter25; import org.xhtmlrenderer.extend.FSImage; import org.xhtmlrenderer.extend.UserAgentCallback; @@ -69,21 +68,17 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c return fsImage; } - private Image generateBarcodeImage(String barcodeType, String content) - throws WriterException { + private Image generateBarcodeImage(String barcodeType, String content) throws WriterException { assertSupportedBarcodeType(barcodeType); if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) { - Barcode code = new BarcodeInter25(); - code.setGenerateChecksum(true); - // Pads the code if necessary: Length is even but a checksum will be added - code.setCode(BarcodeInter25.keepNumbers(content).length() % 2 == 0 ? "0" + content : content); - return code.createAwtImage(Color.BLACK, Color.WHITE); + content += BarcodeInter25.getChecksum(content); } - if (BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(barcodeType) + if ((BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(barcodeType) + || BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) && BarcodeInter25.keepNumbers(content).length() % 2 != 0) { - // Pads the code if necessary: Length is uneven and no checksum will be added + // Pads the code if the length is uneven content = "0" + content; } From 3b0c2be9c3567d7e1619d9f941d68611a0ca57d4 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 14:45:21 +0100 Subject: [PATCH 18/23] Removes unnecessary scale factor. This was only needed to produce a base image of sufficient size with the previous barcode library. Scaling is done via css. Fixes: SIRI-487 --- .../pdf/handlers/BarcodePdfReplaceHandler.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 6d61f3eaf..bdb37b80d 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -53,12 +53,6 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c Image awtImage = generateBarcodeImage(barcodeInfo[0], barcodeInfo[1]); - int scaleFactor = calculateBarcodeScaleFactor(cssWidth, cssHeight, awtImage); - - awtImage = awtImage.getScaledInstance(awtImage.getWidth(null) * scaleFactor, - awtImage.getHeight(null) * scaleFactor, - Image.SCALE_REPLICATE); - FSImage fsImage = new ITextFSImage(com.lowagie.text.Image.getInstance(awtImage, Color.WHITE, true)); if (cssWidth != -1 || cssHeight != -1) { @@ -85,11 +79,6 @@ private Image generateBarcodeImage(String barcodeType, String content) throws Wr return BarcodeController.generateBarcodeImage(barcodeType, content); } - private int calculateBarcodeScaleFactor(int cssWidth, int cssHeight, Image awtImage) { - return (int) Math.max(Math.ceil(cssWidth / (float) awtImage.getWidth(null)), - Math.ceil(cssHeight / (float) awtImage.getHeight(null))); - } - private void assertSupportedBarcodeType(String type) { if (!BARCODE_TYPE_CODE128.equalsIgnoreCase(type) && !BARCODE_TYPE_EAN.equalsIgnoreCase(type) From a0979c868fdeb727958582201188bbfde3d5c941 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 15:05:12 +0100 Subject: [PATCH 19/23] Moves remaining content preprocessing to BarcodeController, so this behavior is also uniform Fixes: SIRI-487 --- .../handlers/BarcodePdfReplaceHandler.java | 37 +--------------- .../sirius/web/util/BarcodeController.java | 42 +++++++++++++++---- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index bdb37b80d..6271b568c 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -8,8 +8,6 @@ package sirius.web.templates.pdf.handlers; -import com.google.zxing.WriterException; -import com.lowagie.text.pdf.BarcodeInter25; import org.xhtmlrenderer.extend.FSImage; import org.xhtmlrenderer.extend.UserAgentCallback; import org.xhtmlrenderer.pdf.ITextFSImage; @@ -31,11 +29,6 @@ @Register public class BarcodePdfReplaceHandler extends PdfReplaceHandler { - private static final String BARCODE_TYPE_CODE128 = "code128"; - private static final String BARCODE_TYPE_EAN = "ean"; - private static final String BARCODE_TYPE_INTERLEAVED_2_OF_5 = "interleaved2of5"; - private static final String BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED = "interleaved2of5checksummed"; - @Override public boolean accepts(String protocol) { return "barcode".equals(protocol); @@ -51,7 +44,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c throw new IllegalArgumentException("The URI is required to match the format 'barcode://type/content'"); } - Image awtImage = generateBarcodeImage(barcodeInfo[0], barcodeInfo[1]); + Image awtImage = BarcodeController.generateBarcodeImage(barcodeInfo[0], barcodeInfo[1]); FSImage fsImage = new ITextFSImage(com.lowagie.text.Image.getInstance(awtImage, Color.WHITE, true)); @@ -61,32 +54,4 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c return fsImage; } - - private Image generateBarcodeImage(String barcodeType, String content) throws WriterException { - assertSupportedBarcodeType(barcodeType); - - if (BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) { - content += BarcodeInter25.getChecksum(content); - } - - if ((BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(barcodeType) - || BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(barcodeType)) - && BarcodeInter25.keepNumbers(content).length() % 2 != 0) { - // Pads the code if the length is uneven - content = "0" + content; - } - - return BarcodeController.generateBarcodeImage(barcodeType, content); - } - - private void assertSupportedBarcodeType(String type) { - if (!BARCODE_TYPE_CODE128.equalsIgnoreCase(type) - && !BARCODE_TYPE_EAN.equalsIgnoreCase(type) - && !BARCODE_TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(type) - && !BARCODE_TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(type)) { - throw new UnsupportedOperationException(Strings.apply( - "Type '%s' is not supported. Supported types are: code128, ean, interleaved2of5, interleaved2of5checksummed.", - type)); - } - } } diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 19ec1fb68..efb3b55b5 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -18,6 +18,7 @@ import com.google.zxing.oned.EAN13Writer; import com.google.zxing.oned.ITFWriter; import com.google.zxing.qrcode.QRCodeWriter; +import com.lowagie.text.pdf.BarcodeInter25; import io.netty.handler.codec.http.HttpResponseStatus; import sirius.kernel.commons.Strings; import sirius.kernel.commons.Value; @@ -37,6 +38,14 @@ @Register public class BarcodeController extends BasicController { + private static final String TYPE_QR = "qr"; + private static final String TYPE_DATAMATRIX = "datamatrix"; + private static final String TYPE_CODE128 = "code128"; + private static final String TYPE_EAN = "ean"; + private static final String TYPE_ITF = "itf"; + private static final String TYPE_INTERLEAVED_2_OF_5 = "interleaved2of5"; + private static final String TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED = "interleaved2of5checksummed"; + /** * Creates a QR code for the given content. *

@@ -75,6 +84,8 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE return; } + content = alignContentForItfFormat(content, format.name()); + format = useItfFormatForGtin14(content, format); String fileType = webContext.getFirstFilled("fileType").asString("jpg"); @@ -96,10 +107,11 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * @return a barcode of the given data as a 200x200 px image * @throws WriterException if generating the image fails */ - public static Image generateBarcodeImage(String type, String content) - throws WriterException { + public static Image generateBarcodeImage(String type, String content) throws WriterException { BarcodeFormat format = determineFormat(type); + content = alignContentForItfFormat(content, type); + format = useItfFormatForGtin14(content, format); Writer writer = determineWriter(format); @@ -109,13 +121,13 @@ public static Image generateBarcodeImage(String type, String content) private static BarcodeFormat determineFormat(String format) { return switch (Value.of(format).toLowerCase()) { - case "qr" -> BarcodeFormat.QR_CODE; - case "code128" -> BarcodeFormat.CODE_128; - case "ean" -> BarcodeFormat.EAN_13; - case "itf", "interleaved2of5" -> BarcodeFormat.ITF; - case "datamatrix" -> BarcodeFormat.DATA_MATRIX; + case TYPE_QR -> BarcodeFormat.QR_CODE; + case TYPE_CODE128 -> BarcodeFormat.CODE_128; + case TYPE_EAN -> BarcodeFormat.EAN_13; + case TYPE_ITF, TYPE_INTERLEAVED_2_OF_5, TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED -> BarcodeFormat.ITF; + case TYPE_DATAMATRIX -> BarcodeFormat.DATA_MATRIX; default -> throw new IllegalArgumentException( - "Unsupported barcode type. Supported types are: qr, code128, ean, itf, datamatrix"); + "Unsupported barcode type. Supported types are: qr, code128, ean, interleaved2of5, interleaved2of5checksummed, datamatrix"); }; } @@ -138,4 +150,18 @@ private static BarcodeFormat useItfFormatForGtin14(String content, BarcodeFormat return format; } + + private static String alignContentForItfFormat(String content, String format) { + if (TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase(format)) { + content += BarcodeInter25.getChecksum(content); + } + + if ((TYPE_INTERLEAVED_2_OF_5.equalsIgnoreCase(format) || TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED.equalsIgnoreCase( + format)) && BarcodeInter25.keepNumbers(content).length() % 2 != 0) { + // Pads the code if the length is uneven + content = "0" + content; + } + + return content; + } } From a1f95a89eda14643236e9e2c87852b7ce2316e93 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 15:21:30 +0100 Subject: [PATCH 20/23] Returns an empty image for barcodes containing invalid characters Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index efb3b55b5..4a0e1a4b4 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -29,8 +29,10 @@ import sirius.web.http.WebContext; import java.awt.Image; +import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; +import java.util.regex.Pattern; /** * Used to generate barcodes by responding to "/qr" or "/barcode". @@ -46,6 +48,8 @@ public class BarcodeController extends BasicController { private static final String TYPE_INTERLEAVED_2_OF_5 = "interleaved2of5"; private static final String TYPE_INTERLEAVED_2_OF_5_CHECKSUMMED = "interleaved2of5checksummed"; + private static final Pattern NUMERIC = Pattern.compile("[0-9]+"); + /** * Creates a QR code for the given content. *

@@ -108,6 +112,11 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * @throws WriterException if generating the image fails */ public static Image generateBarcodeImage(String type, String content) throws WriterException { + if (!NUMERIC.matcher(content).matches()) { + // contains characters other than digits 0-9 -> directly return a blank image to prevent running into exception + return new BufferedImage(200, 200, BufferedImage.TYPE_BYTE_GRAY); + } + BarcodeFormat format = determineFormat(type); content = alignContentForItfFormat(content, type); From af4e5b68dadc291902d2e84a924f307af9da8bf1 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 15:38:46 +0100 Subject: [PATCH 21/23] Compares format against the correct parameter for web requests Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 4a0e1a4b4..121a57cb0 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -88,7 +88,7 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE return; } - content = alignContentForItfFormat(content, format.name()); + content = alignContentForItfFormat(content, webContext.get("type").asString()); format = useItfFormatForGtin14(content, format); From 43f15b7039f40925bb2a775d7ad27400f3b41bf5 Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 15:49:51 +0100 Subject: [PATCH 22/23] Only checks 1-dimensional barcodes for numeric contents Fixes: SIRI-487 --- src/main/java/sirius/web/util/BarcodeController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index 121a57cb0..e8c3a2c15 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -112,13 +112,13 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * @throws WriterException if generating the image fails */ public static Image generateBarcodeImage(String type, String content) throws WriterException { - if (!NUMERIC.matcher(content).matches()) { + BarcodeFormat format = determineFormat(type); + + if (!NUMERIC.matcher(content).matches() && format != BarcodeFormat.QR_CODE) { // contains characters other than digits 0-9 -> directly return a blank image to prevent running into exception return new BufferedImage(200, 200, BufferedImage.TYPE_BYTE_GRAY); } - BarcodeFormat format = determineFormat(type); - content = alignContentForItfFormat(content, type); format = useItfFormatForGtin14(content, format); From b40d50dbc7b7067240de76815fb3a7ae7381fffe Mon Sep 17 00:00:00 2001 From: Christian Schierle Date: Mon, 29 Nov 2021 16:08:15 +0100 Subject: [PATCH 23/23] Restores the css width/height parameters to provide a suitable base resolution for scaling. Fixes: SIRI-487 --- .../pdf/handlers/BarcodePdfReplaceHandler.java | 2 +- .../java/sirius/web/util/BarcodeController.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java index 6271b568c..26843c85e 100644 --- a/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java +++ b/src/main/java/sirius/web/templates/pdf/handlers/BarcodePdfReplaceHandler.java @@ -44,7 +44,7 @@ public FSImage resolveUri(String uri, UserAgentCallback userAgentCallback, int c throw new IllegalArgumentException("The URI is required to match the format 'barcode://type/content'"); } - Image awtImage = BarcodeController.generateBarcodeImage(barcodeInfo[0], barcodeInfo[1]); + Image awtImage = BarcodeController.generateBarcodeImage(barcodeInfo[0], barcodeInfo[1], cssWidth, cssHeight); FSImage fsImage = new ITextFSImage(com.lowagie.text.Image.getInstance(awtImage, Color.WHITE, true)); diff --git a/src/main/java/sirius/web/util/BarcodeController.java b/src/main/java/sirius/web/util/BarcodeController.java index e8c3a2c15..f880973bd 100644 --- a/src/main/java/sirius/web/util/BarcodeController.java +++ b/src/main/java/sirius/web/util/BarcodeController.java @@ -108,15 +108,20 @@ private void barcode(WebContext webContext, BarcodeFormat format) throws WriterE * * @param type the desired barcode type * @param content the content of the barcode - * @return a barcode of the given data as a 200x200 px image + * @param width the desired width + * @param height the desired height + * @return a barcode of the given data as an image * @throws WriterException if generating the image fails */ - public static Image generateBarcodeImage(String type, String content) throws WriterException { + public static Image generateBarcodeImage(String type, String content, int width, int height) + throws WriterException { BarcodeFormat format = determineFormat(type); if (!NUMERIC.matcher(content).matches() && format != BarcodeFormat.QR_CODE) { // contains characters other than digits 0-9 -> directly return a blank image to prevent running into exception - return new BufferedImage(200, 200, BufferedImage.TYPE_BYTE_GRAY); + return new BufferedImage(width != -1 ? width : 200, + height != -1 ? height : 200, + BufferedImage.TYPE_BYTE_GRAY); } content = alignContentForItfFormat(content, type); @@ -124,7 +129,7 @@ public static Image generateBarcodeImage(String type, String content) throws Wri format = useItfFormatForGtin14(content, format); Writer writer = determineWriter(format); - BitMatrix matrix = writer.encode(content, format, 200, 200); + BitMatrix matrix = writer.encode(content, format, width != -1 ? width : 200, height != -1 ? height : 200); return MatrixToImageWriter.toBufferedImage(matrix); }