Recently I was working on a project and we needed a service that create QrCodes with user profile image on top of it, something like the twitter QRCode. We had 2 option: Using a paid existing web service, or make our own.I went with the second option.

After a quick google search, I found zxing. At heart is it a pure Java library for decoding barcodes (the core/ and javase/ modules). It also contains several applications for Android, Google Glass, a JavaEE web application, and a GWT-based encoder application.

After 2 days playing with it, I was able to create a small Rest service, using Spring boot, that generate QrCodes for our user! Crazy.

Below a small java class that generate the same thing. It generate a QRCode 300x300 png image, that contains some content, and overly an image on top of it. The class also contains an Enumeration of 6 colors to play with Qrcode foreground and background colors (I use orange and white on this example). The class contains also a method to generate random title for generated QrCodes images.

public class QrCode { private final String DIR = "/directory/to/save/images"; private final String ext = ".png"; private final String LOGO = "logo_url"; private final String CONTENT = "some content here"; private final int WIDTH = 300; private final int HEIGHT = 300; public void generate() { // Create new configuration that specifies the error correction Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); QRCodeWriter writer = new QRCodeWriter(); BitMatrix bitMatrix = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { // init directory cleanDirectory(DIR); initDirectory(DIR); // Create a qr code with the url as content and a size of WxH px bitMatrix = writer.encode(CONTENT, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints); // Load QR image BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix, getMatrixConfig()); // Load logo image BufferedImage overly = getOverly(LOGO); // Calculate the delta height and width between QR code and logo int deltaHeight = qrImage.getHeight() - overly.getHeight(); int deltaWidth = qrImage.getWidth() - overly.getWidth(); // Initialize combined image BufferedImage combined = new BufferedImage(qrImage.getHeight(), qrImage.getWidth(), BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) combined.getGraphics(); // Write QR code to new image at position 0/0 g.drawImage(qrImage, 0, 0, null); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f)); // Write logo into combine image at position (deltaWidth / 2) and // (deltaHeight / 2). Background: Left/Right and Top/Bottom must be // the same space for the logo to be centered g.drawImage(overly, (int) Math.round(deltaWidth / 2), (int) Math.round(deltaHeight / 2), null); // Write combined image as PNG to OutputStream ImageIO.write(combined, "png", os); // Store Image Files.copy( new ByteArrayInputStream(os.toByteArray()), Paths.get(DIR + generateRandoTitle(new Random(), 9) +ext), StandardCopyOption.REPLACE_EXISTING); } catch (WriterException e) { e.printStackTrace(); //LOG.error("WriterException occured", e); } catch (IOException e) { e.printStackTrace(); //LOG.error("IOException occured", e); } } private BufferedImage getOverly(String LOGO) throws IOException { URL url = new URL(LOGO); return ImageIO.read(url); } private void initDirectory(String DIR) throws IOException { Files.createDirectories(Paths.get(DIR)); } private void cleanDirectory(String DIR) { try { Files.walk(Paths.get(DIR), FileVisitOption.FOLLOW_LINKS) .sorted(Comparator.reverseOrder()) .map(Path::toFile) .forEach(File::delete); } catch (IOException e) { // Directory does not exist, Do nothing } } private MatrixToImageConfig getMatrixConfig() { // ARGB Colors // Check Colors ENUM return new MatrixToImageConfig(QrCode.Colors.WHITE.getArgb(), QrCode.Colors.ORANGE.getArgb()); } private String generateRandoTitle(Random random, int length) { return random.ints(48, 122) .filter(i -> (i < 57 || i > 65) && (i < 90 || i > 97)) .mapToObj(i -> (char) i) .limit(length) .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); } public enum Colors { BLUE(0xFF40BAD0), RED(0xFFE91C43), PURPLE(0xFF8A4F9E), ORANGE(0xFFF4B13D), WHITE(0xFFFFFFFF), BLACK(0xFF000000); private final int argb; Colors(final int argb){ this.argb = argb; } public int getArgb(){ return argb; } } }

If you execute this script, you'll get something like:



The full version of the code is available on github ;)