Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FastQRGenerator

Maven Central License Java

A fast, dependency-free Java library for generating QR Codes. It implements the ISO/IEC 18004 pipeline from scratch — Reed-Solomon error correction, matrix construction, mask selection and rendering — with zero runtime dependencies.

Project page: fineiasantonio.github.io/FastQRGenerator

Sample QR code

Features

  • No runtime dependencies — pure Java on top of the JDK only.
  • Full version range — QR versions 1 through 40.
  • All error-correction levels — L, M, Q, H.
  • Numeric mode — pure digit payloads are auto-detected and packed at ~2.4x byte-mode density, often fitting a smaller symbol.
  • Automatic mask selection following the ISO 18004 penalty rules.
  • Styled rendering — custom colors, border thickness and rounded modules.
  • Multiple output formats — PNG, JPG, JPEG, BMP, SVG, plus ANSI terminal printing.

Requirements

  • Java 8 or newer.

Installation

Maven

<dependency>
  <groupId>io.github.fineiasantonio</groupId>
  <artifactId>fastqrgenerator</artifactId>
  <version>1.0.0-beta</version>
</dependency>

Gradle

implementation 'io.github.fineiasantonio:fastqrgenerator:1.0.0-beta'

Quick start

import com.qrlib.QRCode;
import com.qrlib.QRCodeGenerator;
import com.qrlib.QRCodeGeneratorBuilder;
import com.qrlib.config.ImageExtensions;

import java.io.FileOutputStream;

// No version or ECC level needed: the smallest fitting version is chosen
// automatically, with error-correction level M by default.
QRCodeGenerator generator = new QRCodeGeneratorBuilder().build();

QRCode qr = generator.generate("https://github.com/FineiasAntonio/FastQRGenerator");

try (FileOutputStream out = new FileOutputStream("qr.png")) {
    qr.writeImage(out, ImageExtensions.PNG);
}

Usage

Choosing the symbol size

By default the smallest version that fits the payload is selected automatically, so you usually don't need to set one. To pin an explicit version (V1V40)…

new QRCodeGeneratorBuilder().version(QRCodeVersion.V10).build();

…or a named QRCodeSize preset:

Preset Version
TINY V1
SMALL V2
MEDIUM V5
LARGE V10
HUGE V20
MAX V40
new QRCodeGeneratorBuilder().size(QRCodeSize.MEDIUM).build();

When you pin a version, it must hold the payload — otherwise generate(...) throws IllegalArgumentException. Higher versions and higher error-correction levels reduce the data capacity.

Error-correction level

new QRCodeGeneratorBuilder()
        .version(QRCodeVersion.V5)
        .eccLevel(ECCLevel.H) // L, M (default), Q, H
        .build();

Output formats and saving to a file

writeImage(...) writes the rendered image to any OutputStream; toImageBytes(...) returns it as a byte[]:

// write straight to a stream (file, HTTP response, ...)
try (FileOutputStream out = new FileOutputStream("qr.png")) {
    qr.writeImage(out, ImageExtensions.PNG);
}

// default: PNG, module size 10px, default style
byte[] png = qr.toImageBytes();

// pick a format
byte[] jpg = qr.toImageBytes(ImageExtensions.JPG);

// pick a format and module size (pixels per module)
byte[] scaled = qr.toImageBytes(ImageExtensions.PNG, 8);

Styling

QRCodeStyleDefinitions style = QRCodeStyleDefinitions.builder()
        .moduleColor("#1A1A2E")  // #RRGGBB or shorthand #RGB
        .backgroundColor("#FFF")
        .borderThickness(4)      // quiet-zone width, in modules
        .cornerRadius(0.4)       // 0 (square) to 0.5 (fully round), as a fraction of the module
        .build();

qr.toImageBytes(ImageExtensions.PNG, 10, style);

Notes:

  • Colors accept #RRGGBB or shorthand #RGB hex and are validated when set.
  • borderColor(...) tints the quiet zone; when not set it follows the background color.
  • cornerRadius(...) implies rounded modules; roundedCorners(true) uses the maximum radius. Rounded modules are drawn antialiased, and connected runs of modules merge into a single smooth shape rounded only at its ends.
  • Keep enough contrast between module and background colors — low-contrast symbols may not scan reliably.

Center image (logo)

Overlay an image on the center of the symbol. It is drawn over a small background-colored pad and scaled — preserving its aspect ratio — to the configured fraction of the symbol width (default 0.2, maximum 0.3):

BufferedImage logo = ImageIO.read(new File("logo.png"));

QRCodeStyleDefinitions style = QRCodeStyleDefinitions.builder()
        .centerImage(logo)
        .centerImageRatio(0.2)
        .centerImagePadShape(CenterImagePadShape.ROUNDED) // SQUARE (default), ROUNDED or CIRCLE
        .build();

qr.toImageBytes(ImageExtensions.PNG, 10, style);

The pad behind the image can be SQUARE (default), ROUNDED (rounded corners) or CIRCLE — with CIRCLE the image itself is also cropped to a circle, scaled to cover it fully.

The covered modules are lost to the reader and must be recovered by error correction, so pair a center image with a high error-correction level:

new QRCodeGeneratorBuilder().eccLevel(ECCLevel.H).build();

As a rule of thumb: the default ratio (0.2) scans reliably at level M and above, the maximum ratio (0.3) requires Q or H, and level L should not be combined with a center image at all.

SVG output

getAsSVG(...) renders the symbol as a standalone SVG document string — plain text built directly from the matrix, with no java.awt rasterization involved, so it also works on runtimes without AWT (e.g. Android):

String svg = qr.getAsSVG(); // default style, 10px per module

// with a custom pixel size and style (same styling options as raster output)
String styled = qr.getAsSVG(8, style);

Files.write(Paths.get("qr.svg"), svg.getBytes(StandardCharsets.UTF_8));

The viewBox is laid out in module units, so the symbol scales losslessly to any size — the module size only sets the document's default width/height. SVG is the natural choice for the web: browsers render it directly, files are compact, and it stays sharp at every zoom level.

The one exception to the no-AWT guarantee: a style carrying a center image embeds it as a base64 PNG data URI, which requires javax.imageio.

Printing to the terminal

qr.print();                     // renders the symbol with ANSI background blocks on System.out
qr.print(System.err);           // or on any PrintStream

String ansi = qr.getAsTerminalString(); // the same output as a String

Accessing the raw matrix

If you only need the module data (no AWT), read it directly:

int size = qr.getSize();                          // side length, in modules
boolean dark = qr.isDark(row, col);               // read a single module

byte[][] matrix = qr.getMatrixData().getMatrix(); // snapshot copy, 1 = dark, 0 = light

getMatrixData() returns a snapshot: modifying it (or the array from getMatrix()) never affects the generated symbol.

Sample output

The samples/ directory contains generated symbols from version 2 up to version 40.

Building from source

./mvnw clean test     # compile and run the test suite
./mvnw clean package  # build the jar

Limitations

This library is in beta. Notable constraints:

  • Text is encoded in byte mode (UTF-8), which accepts any payload; pure digit payloads are automatically packed in numeric mode. There is no alphanumeric/kanji mode optimization yet, so uppercase-only payloads are not encoded at maximum density.
  • Image rendering depends on java.awt, which is unavailable on some runtimes (e.g. Android).

License

Licensed under the Apache License 2.0.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages