Search code examples
javagluongluon-mobile

How to generate qr code with Image overlay in Gluon?


I want to generate QR CODE which have to put logo in the center. I have check the zxing library and I did it with a Java application by reading this code (How to generate QR code with logo inside it?). But as I know we can't use swing in android/ios. So how to deal with this ?


Solution

  • Based on the link you are referring, the accepted answer pointed to this post, where you can see that the trick to generate a QR that allows hiding its center part without affecting its readability by a QR scanner, can be done by increasing the error level:

    30% (H) of error correction were a error correction of level H should result in a QRCode that is still valid even when it’s 30% obscured

    As a follow-up of this question, you can just include a hint when encoding the text:

    public Image generateQR(int width, int height) {
        File root = Services.get(StorageService.class)
                .flatMap(StorageService::getPrivateStorage)
                .orElseThrow(() -> new RuntimeException("Storage Service not found"));
    
        String uuid = Services.get(DeviceService.class)
                .map(DeviceService::getUuid)
                .orElse("123456789");
    
        MultiFormatWriter codeWriter = new MultiFormatWriter();
    
        // Add maximum correction
        Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    
        try {
            BarcodeFormat format = BarcodeFormat.QR_CODE;
            BitMatrix bitMatrix = codeWriter.encode(uuid, format, 
                   width, height, hints);  // <--- add hints
            ...
            return writableImage;
        }
    }
    

    You will be getting a QR code image, without overlay.

    The next step is to combine this image with your logo image, without using Swing. But we actually don't need to do that: we can just use two ImageView nodes!

    ImageView imageView = new ImageView();
    imageView.setFitWidth(256);
    imageView.setFitHeight(256);
    imageView.setImage(service.generateQR(256, 256));
    
    ImageView overlay = new ImageView(
         new Image(getClass().getResourceAsStream("/icon.png")));
    overlay.setFitWidth(80);
    overlay.setFitHeight(80);
    
    StackPane combinedQR = new StackPane(imageView, overlay);
    ...
    

    The resulting code is still readable.

    You can also play with the result, adding a blend effect to the images, like:

    overlay.setBlendMode(BlendMode.ADD);
    

    but this will depend on how your logo image blends with the QR.

    Finally, if you still need a single combined image, you can create a snapshot of the stack pane:

    WritableImage snapshot = combinedQR.snapshot(new SnapshotParameters(), null);