Skip to content

Commit

Permalink
New output size: payment part only
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelbl committed May 31, 2024
1 parent d70b10c commit ec38f91
Show file tree
Hide file tree
Showing 7 changed files with 352 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class BillLayout {
private double textAscender;
private double lineSpacing;
private double extraSpacing;
private final double paymentPartHoriOffset;


BillLayout(Bill bill, Canvas graphics) {
Expand All @@ -71,6 +72,7 @@ class BillLayout {
this.formatter = new BillTextFormatter(bill, true);
this.additionalLeftMargin = Math.min(Math.max(bill.getFormat().getMarginLeft(), 5.0), 12.0) - MARGIN;
this.additionalRightMargin = Math.min(Math.max(bill.getFormat().getMarginRight(), 5.0), 12.0) - MARGIN;
this.paymentPartHoriOffset = bill.getFormat().getOutputSize() == OutputSize.PAYMENT_PART_ONLY ? 0 : RECEIPT_WIDTH;
}

void draw() throws IOException {
Expand All @@ -97,6 +99,9 @@ void draw() throws IOException {
}
drawPaymentPart();

if (bill.getFormat().getOutputSize() == OutputSize.PAYMENT_PART_ONLY)
return;

// receipt

final int RC_LABEL_PREF_FONT_SIZE = 6; // pt
Expand Down Expand Up @@ -128,12 +133,12 @@ private void drawPaymentPart() throws IOException {
final double QR_CODE_BOTTOM = 42; // mm

// title section
graphics.setTransformation(RECEIPT_WIDTH + MARGIN, 0, 0, 1, 1);
graphics.setTransformation(paymentPartHoriOffset + MARGIN, 0, 0, 1, 1);
yPos = SLIP_HEIGHT - MARGIN - graphics.getAscender(FONT_SIZE_TITLE);
graphics.putText(getText(MultilingualText.KEY_PAYMENT_PART), 0, yPos, FONT_SIZE_TITLE, true);

// Swiss QR code section
qrCode.draw(graphics, RECEIPT_WIDTH + MARGIN, QR_CODE_BOTTOM);
qrCode.draw(graphics, paymentPartHoriOffset + MARGIN, QR_CODE_BOTTOM);

// amount section
drawPaymentPartAmountSection();
Expand All @@ -151,7 +156,7 @@ private void drawPaymentPartAmountSection() throws IOException {
final double AMOUNT_BOX_WIDTH_PP = 40; // mm
final double AMOUNT_BOX_HEIGHT_PP = 15; // mm

graphics.setTransformation(RECEIPT_WIDTH + MARGIN, 0, 0, 1, 1);
graphics.setTransformation(paymentPartHoriOffset + MARGIN, 0, 0, 1, 1);

// currency
double y = AMOUNT_SECTION_TOP - labelAscender;
Expand All @@ -177,7 +182,7 @@ private void drawPaymentPartAmountSection() throws IOException {

private void drawPaymentPartInformationSection() throws IOException {

graphics.setTransformation(SLIP_WIDTH - PP_INFO_SECTION_WIDTH - MARGIN, 0, 0, 1, 1);
graphics.setTransformation(paymentPartHoriOffset + PP_AMOUNT_SECTION_WIDTH + 2 * MARGIN, 0, 0, 1, 1);
yPos = SLIP_HEIGHT - MARGIN - labelAscender;

// account and creditor
Expand Down Expand Up @@ -211,7 +216,7 @@ private void drawFurtherInformationSection() throws IOException {
if (bill.getAlternativeSchemes() == null || bill.getAlternativeSchemes().length == 0)
return;

graphics.setTransformation(RECEIPT_WIDTH + MARGIN, 0, 0, 1, 1);
graphics.setTransformation(paymentPartHoriOffset + MARGIN, 0, 0, 1, 1);
double y = FURTHER_INFORMATION_SECTION_TOP - graphics.getAscender(FONT_SIZE);
double maxWidth = PAYMENT_PART_WIDTH - 2 * MARGIN - additionalRightMargin;

Expand Down Expand Up @@ -441,6 +446,7 @@ private void drawScissors(double x, double y, double angle) throws IOException {
drawScissorsBlade(x, y, 3, angle, true);
}

@SuppressWarnings("SameParameterValue")
private void drawScissorsBlade(double x, double y, double size, double angle, boolean mirrored) throws IOException {
double scale = size / 476.0;
double xOffset = 0.36 * size;
Expand Down Expand Up @@ -482,6 +488,7 @@ private void drawLabel(String labelKey) throws IOException {

// Draws a label and a single line of text at (0, yPos) and advances vertically.
// yPos is taken as the baseline for the text.
@SuppressWarnings("SameParameterValue")
private void drawLabelAndText(String labelKey, String text) throws IOException {
drawLabel(labelKey);
graphics.putText(text, 0, yPos, textFontSize, false);
Expand Down Expand Up @@ -550,6 +557,7 @@ private void drawCorners(double x, double y, double width, double height) throws
graphics.strokePath(CORNER_STROKE_WIDTH, 0, Canvas.LineStyle.Solid, false);
}

@SuppressWarnings("SameParameterValue")
private String truncateText(String text, double maxWidth, int fontSize) {

final double ELLIPSIS_WIDTH = 0.3528; // mm * font size
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public enum OutputSize {
*/
A4_PORTRAIT_SHEET,
/**
* QR bill only (about 105 by 210 mm).
* QR bill only (about 210 by 105 mm).
* <p>
* This size is suitable if the QR bill has not horizontal line.
* This size is suitable if the QR bill has no horizontal line.
* If the horizontal line is needed and the A4 sheet size is not
* suitable, use {@link #QR_BILL_EXTRA_SPACE} instead.
* </p>
Expand All @@ -44,5 +44,14 @@ public enum OutputSize {
* This format applies a white background (as opposed to a transparent one).
* </p>
*/
QR_CODE_WITH_QUIET_ZONE
QR_CODE_WITH_QUIET_ZONE,
/**
* Payment part only (about 148 by 105 mm).
* <p>
* This size does not include separator lines. It is suitable for displaying the QR bill in online channels.
* See <i>Implementation Guidelines QR Bill v2.3</i>, ch. <i>3.8 Layout rules for the online use of the QR-bill</i>
* for additional requirements when using this size.
* </p>
*/
PAYMENT_PART_ONLY,
}
19 changes: 19 additions & 0 deletions generator/src/main/java/net/codecrete/qrbill/generator/QRBill.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ public class QRBill {
*/
public static final double QR_CODE_WITH_QUIET_ZONE_HEIGHT = 56;

/**
* The width of the payment part, in mm
*
* @see OutputSize#PAYMENT_PART_ONLY
*/
public static final double PAYMENT_PART_WDITH = 148;

/**
* The height of the payment part, in mm
*
* @see OutputSize#PAYMENT_PART_ONLY
*/
public static final double PAYMENT_PART_HEIGHT = 105;


private QRBill() {
// do not instantiate
}
Expand Down Expand Up @@ -292,6 +307,10 @@ private static Canvas createCanvas(Bill bill) throws IOException {
drawingWidth = QR_BILL_WITH_HORI_LINE_WIDTH;
drawingHeight = QR_BILL_WITH_HORI_LINE_HEIGHT;
break;
case PAYMENT_PART_ONLY:
drawingWidth = PAYMENT_PART_WDITH;
drawingHeight = PAYMENT_PART_HEIGHT;
break;
case QR_CODE_ONLY:
drawingWidth = QR_CODE_WIDTH;
drawingHeight = QR_CODE_HEIGHT;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Swiss QR Bill Generator
// Copyright (c) 2024 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
package net.codecrete.qrbill.generator;

import net.codecrete.qrbill.testhelper.FileComparison;
import net.codecrete.qrbill.testhelper.SampleData;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
* Unit tests for generation of payment part only (PDF, PNG and SVG)
* <p>
* Resulting output is compared byte by byte.
* </p>
*/
@DisplayName("Generation of payment part only")
class PaymentPartTest {

@Test
void createQRBill1() {
Bill bill = SampleData.getExample1();
bill.getFormat().setOutputSize(OutputSize.PAYMENT_PART_ONLY);
bill.getFormat().setGraphicsFormat(GraphicsFormat.SVG);
byte[] svg = QRBill.generate(bill);
FileComparison.assertFileContentsEqual(svg, "payment_part1.svg");
}

@Test
void createQRBill2() {
Bill bill = SampleData.getExample2();
bill.getFormat().setOutputSize(OutputSize.PAYMENT_PART_ONLY);
bill.getFormat().setGraphicsFormat(GraphicsFormat.PDF);
byte[] pdf = QRBill.generate(bill);
FileComparison.assertFileContentsEqual(pdf, "payment_part2.pdf");
}

@Test
void createQRBill3() {
Bill bill = SampleData.getExample3();
bill.getFormat().setOutputSize(OutputSize.PAYMENT_PART_ONLY);
bill.getFormat().setGraphicsFormat(GraphicsFormat.PNG);
byte[] png = QRBill.generate(bill);
FileComparison.assertFileContentsEqual(png, "payment_part2.png");
}
}
Loading

0 comments on commit ec38f91

Please sign in to comment.