Library / SDK
nayuki/QR-Code-generator avatar
nayuki/QR-Code-generator

nayuki/QR-Code-generator: A Library That Returns Modules, Not Images

High-quality QR Code generator library in Java, TypeScript/JavaScript, Python, Rust, C++, C.

6,783 stars1,289 forksJavaLicense varies

At a glance

What is it?
Six language ports of one QR Code Model 2 encoder, judged on correctness and encoder control rather than on prettiness. Here is what it does, how to run it, and where it stops being the right tool.
Who is it for?
Adopt nayuki/QR-Code-generator when you need an offline, embeddable encoder, precise control over version, error correction level and mask, or identical output across several languages. Do not adopt it if you want a finished PNG or SVG with a logo, colours and a tracking redirect: the library emits a boolean module grid and nothing else, and the README lists no image export.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: an encoder that hands you modules instead of a picture

Most tools that call themselves QR code generators are products: you paste a URL, pick a colour, and a service returns an image, often behind a redirect that lets the vendor change the destination later. nayuki/QR-Code-generator is the opposite kind of object. It is a library, and its stated output format is raw modules or pixels of the QR symbol. It does not write files for you, and it does not host anything.

That distinction decides who the project is for. If you are building a ticketing system, a label printer, a firmware updater, or a test suite that has to emit a QR symbol inside a larger canvas, you want an encoder you can call from your own code and paint yourself. The README describes the primary goals as flexible options and absolute correctness, with compact implementation size and documentation comments as secondary goals. The audience is therefore developers, not marketers. Anyone who wants a downloadable image with a logo should look elsewhere; the README does not mention logos, colours, or SVG output at all.

How the encoder works: segments, version search, and mask evaluation

The data flow visible in the README is short. Text goes in, and the library decides how to represent it, which QR version to use, and which mask pattern produces the best symbol.

Text is split into segments. The README states that the library encodes numeric and special-alphanumeric text in less space than general text, so a string of digits does not cost the same as a string of letters. You can also build the segment list yourself and add ECI segments, which is the escape hatch for character set control. Then the library chooses a version: you may set a minimum and maximum version number, and, per the README, it will automatically choose the smallest version in the range that fits the data. Error correction is either an absolute level you specify or a level the library boosts if doing so does not increase the version number. Finally, mask selection: unless you name a mask pattern yourself, the README says the library evaluates all 8 masks and picks the optimal one. The README also claims the implementation detects finder-like penalty patterns more accurately than other implementations, which is a correctness claim about the scoring step rather than a feature you configure.

The advanced options are narrower than the feature list first suggests. Kanji mode encoding for Japanese text and optimal segment mode switching for mixed numeric, alphanumeric, general and kanji text are marked as Java only. If you are working in Python, Rust, C++, C or TypeScript, you get the core encoder and the manual parameters, not the Java-only segmentation intelligence. The repository layout reinforces this: there are separate java and java-fast directories, plus rust and rust-no-heap variants, so the ports are not one interchangeable build.

Installing it and generating your first symbol in Java

There is no package registry step in the README. The project points to its home page for descriptions and competitor comparisons, and the code lives in per-language directories in the repository, so you obtain the source from there and compile it with your own toolchain. The README does not give Maven coordinates, a pip command, or a cargo add line.

The README's own example is Java. It imports the demo class, encodes a string at medium error correction, and converts the result to a BufferedImage before writing a PNG:

java
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import io.nayuki.qrcodegen.*;

QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
BufferedImage img = toImage(qr0, 4, 10);  // See QrCodeGeneratorDemo
ImageIO.write(img, "png", new File("qr-code.png"));

Note what the call to toImage does and does not do. It is a helper from the demo, not part of the library's stated output contract, and the README points you to QrCodeGeneratorDemo for it. The library itself gives you modules. The second half of the README example shows the manual path: build segments, then encode with an explicit version range and mask.

java
List<QrSegment> segs = QrSegment.makeSegments("3141592653589793238462643383");
QrCode qr1 = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 5, 5, 2, false);
for (int y = 0; y < qr1.size; y++) {
    for (int x = 0; x < qr1.size; x++) {
        (... paint qr1.getModule(x, y) ...)
    }
}

Here the version range is pinned to 5 through 5, the mask is fixed at 2, and the last argument is false. The README does not explain that final flag, so read the source before relying on it. The loop is the whole rendering story: getModule returns a boolean per coordinate, and you decide what a module looks like. That is why the library fits printers and canvas code, and why it will not produce a file on its own.

Where it stops: no renderer, no logo, no redirect

The most important limitation is stated plainly in the feature list. Output format is raw modules or pixels of the QR symbol. There is no image encoder, no SVG writer, no colour handling and no logo overlay anywhere in the README. If your requirement is a branded code with a centre image, this library gives you the grid and leaves the composition to you, which is more work than a hosted generator and more work than a drawing library that already knows how to export.

A second limit is language parity. The README says the six ports have nearly equal functionality, then carves out kanji mode and optimal segment mode switching as Java only. A team standardising on Python for a Japanese-language product should read that line twice before assuming the ports are drop-in equivalents.

Third, the release history is thin. The most recent release listed is v1.8.0 from 2022-04-17, with v1.7.0 and v1.6.0 before it. The repository is not archived and the last push was on 2026-08-31, so work continues, but there is no long train of tagged versions to lean on. If your process requires frequent versioned releases with changelogs, this project does not offer that rhythm. The README also does not document rollback behaviour or a deprecation policy, so upgrading means diffing the source yourself.

The alternative: a full imaging library such as ZXing

The realistic alternative for JVM and Android work is ZXing, which is a barcode processing library rather than a pure encoder. The difference in approach matters more than the feature checklist. ZXing covers scanning and decoding as well as generation, and it includes writers that produce images directly, so a ZXing-based pipeline can go from string to PNG without you writing a pixel loop.

nayuki/QR-Code-generator goes the other way. It does one direction, encoding, and stops at the module matrix. That makes it smaller to read and easier to port, and the README explicitly claims significantly shorter code but more documentation comments compared to competing libraries. The trade is that every presentation concern becomes yours. If you need to read QR codes as well as write them, or if you need an out-of-the-box image writer, ZXing covers ground this library deliberately does not. If you need the same encoder logic in C, C++, Rust, Python, TypeScript and Java, or you want to tune version, error correction and mask yourself, the narrower library is the better fit.

Licence, maintenance and the cost of upgrading

The README carries the full MIT License text, copyright Project Nayuki, permitting use, copying, modification, merging, publishing, distribution, sublicensing and sale provided the copyright notice and permission notice are included in all copies or substantial portions. It is a permissive licence with no copyleft obligation. One inconsistency is worth flagging: the README states the MIT License, while the repository metadata shows the licence field as unknown. Check the licence file in the repository before you rely on it, and treat this as a due-diligence item rather than legal advice.

Upgrade cost is low in absolute terms because the library is small and self-contained, but the release cadence means you will not be upgrading often. Between v1.8.0 and the current source there may be unversioned changes, since the last push was on 2026-08-31. The practical approach is to vendor the source for the language you use, keep your rendering code separate from the encoder calls, and re-run your own symbol tests after any pull. Because the API is deliberately close across ports, a test that checks the module matrix for a fixed input is portable between them, which is the cheapest regression net this project allows.

Choosing between the java, java-fast and rust-no-heap directories

The repository layout is itself a decision point that the README does not walk through. There are java and java-fast directories, rust and rust-no-heap, and a single typescript-javascript directory covering both languages. The README does not explain what java-fast or rust-no-heap trade away, so the naming is the only signal: one variant suggests a performance-oriented implementation, the other a variant that avoids heap allocation, which matters in embedded or no-allocator Rust contexts.

Before adopting, open the directory you intend to use and read its source and comments rather than assuming the ports are identical. The README's claim of nearly equal functionality is about features, not about internal constraints, and a no-heap port will have a different API surface by necessity. If your target is a microcontroller or a constrained runtime, that directory is the one to evaluate first, and the Java-only advanced features are irrelevant to you anyway.

Editorial conclusion

Adopt nayuki/QR-Code-generator when you need an offline, embeddable encoder, precise control over version, error correction level and mask, or identical output across several languages. Do not adopt it if you want a finished PNG or SVG with a logo, colours and a tracking redirect: the library emits a boolean module grid and nothing else, and the README lists no image export. Before committing, check the licence file in the repository, because the README states the MIT License while the repository metadata shows the licence as unknown, and confirm the language port you need by listing the java, java-fast, typescript-javascript, python, rust, rust-no-heap, cpp and c directories.

Frequently asked questions

Is nayuki/QR-Code-generator really free?

The README states the code is open source under the permissive MIT License, and includes the full licence text permitting use, modification, distribution and sale provided the copyright and permission notices are kept. Note that the repository metadata shows the licence as unknown, so confirm the licence file in the repository.

What output does nayuki/QR-Code-generator produce?

Raw modules or pixels of the QR symbol, according to the feature list. The README's Java example converts the result to a BufferedImage and writes a PNG, but that conversion is a demo helper, not part of the library's output contract.

Can nayuki/QR-Code-generator add a logo or colours to the QR code?

No. The README does not mention logos, colours or image styling, and the stated output format is the raw module matrix. Any branding or composition has to be applied by your own rendering code on top of getModule.

Does nayuki/QR-Code-generator work offline?

It is a library you compile into your own program, so nothing in the encoding path calls a network service. The README describes no hosting, no API endpoint and no account, which is the opposite of a hosted generator that returns an image over HTTP.

Which languages does nayuki/QR-Code-generator support?

Six, per the README: Java, TypeScript/JavaScript, Python, Rust, C++ and C, all with nearly equal functionality. Kanji mode encoding and optimal segment mode switching are marked Java only, and the repository also contains java-fast and rust-no-heap variants.

Official sources

  1. Issues
  2. nayuki/QR-Code-generator on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nayuki-qr-code-generator.svg)](https://hysenlabs.com/projects/nayuki-qr-code-generator)