alexzhirkevich/custom-qr-generator

Generated QR not scan-able

Closed this issue ยท 6 comments

I asked for Java sample and I got some code that works and generates the QR I want but the generated Qr is not scannable. I am not sure what I missed. I tried it on multiple devices.

here is my code

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

import androidx.core.content.ContextCompat;

import com.github.alexzhirkevich.customqrgenerator.HighlightingType;
import com.github.alexzhirkevich.customqrgenerator.QrData;
import com.github.alexzhirkevich.customqrgenerator.QrErrorCorrectionLevel;
import com.github.alexzhirkevich.customqrgenerator.QrHighlighting;
import com.github.alexzhirkevich.customqrgenerator.QrHighlightingKt;
import com.github.alexzhirkevich.customqrgenerator.vector.QrCodeDrawableKt;
import com.github.alexzhirkevich.customqrgenerator.vector.QrVectorOptions;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QVectorShapeUtilsKt;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorBackground;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorBallShape;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorColor;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorColors;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorFrameShape;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorLogo;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorLogoPadding;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorLogoShape;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorPixelShape;
import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorShapes;
import com.github.yohannestz.cberemix.R;
import com.google.android.material.elevation.SurfaceColors;

import java.nio.charset.StandardCharsets;

public class QRCodeGenerator {
    private final Context context;

    public QRCodeGenerator(Context context) {
        this.context = context;
    }

    public Drawable drawableFromText(String data) {
        if (Utils.isHex(data)) {
            data = data.toUpperCase();
        }
        QrData qrData = new QrData.Text(data);
        return QrCodeDrawableKt.QrCodeDrawable(qrData, getQrVectorOptions(data), StandardCharsets.UTF_8);
    }

    private QrVectorOptions getQrVectorOptions(String data) {
        if (data.length() < 140)
            return getDesignQrVectorOptions(data);
        else
            return getCompatibilityQrVectorOptions();
    }

    private QrVectorOptions getDesignQrVectorOptions(String data) {
        QrVectorLogo.Builder qrVectorLogoBuilder = new QrVectorLogo.Builder();
        qrVectorLogoBuilder.setDrawable(ContextCompat.getDrawable(context, R.drawable.cbe_vector));
        qrVectorLogoBuilder.setShape(new QrVectorLogoShape.RoundCorners(0.5f));
        qrVectorLogoBuilder.setPadding(new QrVectorLogoPadding.Natural(.5f));
        qrVectorLogoBuilder.setSize(0.1f);
        QrVectorLogo qrVectorLogo = qrVectorLogoBuilder.build();

        QrVectorOptions.Builder optionsBuilder = getDefaultOptionsBuilder()
                .setShapes(
                        new QrVectorShapes(
                                new QrVectorPixelShape.Rect(.75f),
                                new QrVectorPixelShape.Rect(.75f),
                                new QrVectorBallShape.RoundCorners(.15f, true, true, true, true),
                                new QrVectorFrameShape.RoundCorners(.15f, 1f, true, true, true, true, 7),
                                true
                        )
                )
                .setColors(
                        new QrVectorColors(
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)),
                                new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary)),
                                new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary)),
                                new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary))
                        )
                )
                .setBackground(
                        new QrVectorBackground(
                                ContextCompat.getDrawable(context, R.drawable.bg_box),
                                (drawable, i, i1) -> Bitmap.createBitmap(i, i1, Bitmap.Config.ARGB_8888),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        )
                )
                .setLogo(qrVectorLogo)
                .setAnchorsHighlighting(new QrHighlighting(
                        new HighlightingType.Styled(
                                QrHighlightingKt.QrVersionEyeShape(
                                        new QrVectorFrameShape.AsPixelShape(new QrVectorPixelShape.Rect(.75f), 5),
                                        QVectorShapeUtilsKt.asBallShape(new QrVectorPixelShape.Rect(.75f))),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)),
                                new QrVectorPixelShape.Rect(.0f),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        ),
                        new HighlightingType.Styled(
                                QrHighlightingKt.QrVersionEyeShape(
                                        new QrVectorFrameShape.AsPixelShape(new QrVectorPixelShape.Rect(.75f), 5),
                                        QVectorShapeUtilsKt.asBallShape(new QrVectorPixelShape.Rect(.75f))),
                                new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary)),
                                new QrVectorPixelShape.Rect(.0f),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        ),
                        new HighlightingType.Styled(
                                new QrVectorPixelShape.Rect(.75f), new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)),
                                new QrVectorPixelShape.Rect(.75f), new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary))),
                        1.0f
                ));


        if (data.length() > 60) {
            optionsBuilder.setErrorCorrectionLevel(QrErrorCorrectionLevel.Low);
        } else {
            optionsBuilder.setErrorCorrectionLevel(QrErrorCorrectionLevel.Medium);
        }

        new HighlightingType.Styled(new QrVectorFrameShape.RoundCorners(.15f, 1f, true, true, true, true, 7), new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)), new QrVectorFrameShape.RoundCorners(.15f, 1f, true, true, true, true, 7), new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary)));
        QrHighlightingKt.QrVersionEyeShape(
                new QrVectorFrameShape.AsPixelShape(
                        new QrVectorPixelShape.Rect(.75f), 5
                ),
                QVectorShapeUtilsKt.asBallShape(new QrVectorPixelShape.Rect(.75f))
        );

        return optionsBuilder.build();
    }

    private QrVectorOptions getCompatibilityQrVectorOptions() {
        return getDefaultOptionsBuilder()
                .setShapes(
                        new QrVectorShapes(
                                new QrVectorPixelShape.RoundCorners(.0f),
                                new QrVectorPixelShape.RoundCorners(.35f),
                                new QrVectorBallShape.RoundCorners(.15f, true, true, true, true),
                                new QrVectorFrameShape.RoundCorners(.15f, 1f, true, true, true, true, 7),
                                true
                        )
                )
                .build();
    }

    private QrVectorOptions.Builder getDefaultOptionsBuilder() {
        return new QrVectorOptions.Builder()
                .setPadding(.15f)
                .setBackground(
                        new QrVectorBackground(
                                ContextCompat.getDrawable(context, R.drawable.bg_box),
                                (drawable, i, i1) -> Bitmap.createBitmap(i, i1, Bitmap.Config.ARGB_8888),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        )
                )
                .setErrorCorrectionLevel(QrErrorCorrectionLevel.Low);
    }

    //for future
    private static Bitmap drawableToBitmap(Drawable drawable, int size) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            if (bitmapDrawable.getBitmap() != null) {
                return bitmapDrawable.getBitmap();
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }
}

and in my fragment I have:

   //onStart
   binding.qrImageView.setImageDrawable(generateQr(qrDataText));
   private Drawable generateQr(String payload) {
        QRCodeGenerator qrCodeGenerator = new QRCodeGenerator(getContext());
        qrDataText = "https://cbe.com/receive?account=100003450&amount=" + payload;
        return qrCodeGenerator.drawableFromText(qrDataText);
    }

Result:
image preview

hi, sorry for the late reply. I tried what the docs recommended but I am still was not able to make it scannable in other apps.

Then try to remove highlighting. Its experimental and is not needed in your case

@YohannesTz remove this part and it will work

  setAnchorsHighlighting(new QrHighlighting(
                        new HighlightingType.Styled(
                                QrHighlightingKt.QrVersionEyeShape(
                                        new QrVectorFrameShape.AsPixelShape(new QrVectorPixelShape.Rect(.75f), 5),
                                        QVectorShapeUtilsKt.asBallShape(new QrVectorPixelShape.Rect(.75f))),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)),
                                new QrVectorPixelShape.Rect(.0f),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        ),
                        new HighlightingType.Styled(
                                QrHighlightingKt.QrVersionEyeShape(
                                        new QrVectorFrameShape.AsPixelShape(new QrVectorPixelShape.Rect(.75f), 5),
                                        QVectorShapeUtilsKt.asBallShape(new QrVectorPixelShape.Rect(.75f))),
                                new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary)),
                                new QrVectorPixelShape.Rect(.0f),
                                new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context))
                        ),
                        new HighlightingType.Styled(
                                new QrVectorPixelShape.Rect(.75f), new QrVectorColor.Solid(SurfaceColors.SURFACE_1.getColor(context)),
                                new QrVectorPixelShape.Rect(.75f), new QrVectorColor.Solid(ContextCompat.getColor(context, R.color.md_theme_light_primary))),
                        1.0f
                ));

also do not use padding at all if not needed or decrease padding to 0.1f
qrVectorLogoBuilder.setPadding(new QrVectorLogoPadding.Natural(.1f));

Hi, I removed the part specified. was still unscannable. changing the color to black did the trick. didn't know contrast really affected the results. so what do you guys recommend me when it comes to branding?

Always test it and search for the most suitable working variant. QR codes aren't magic and not all styles are possible