You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7.7 KiB
7.7 KiB
Porting Summary: Java → C# QR Code Generator
Scope
- Ported the core QR Code generator from the Java implementation (
java/src/main/java/io/nayuki/qrcodegen/) to C#. - Implemented a class library
QrCodeGenand a minimal console demoQrCodeGen.Demo.
Goals
- Maintain functional parity with the Java reference (encoding pipeline, EC levels, masking, penalties, Reed–Solomon ECC, layout drawing).
- Provide idiomatic and safe C# while preserving algorithmic behavior and outputs.
Note
- This PR is 100% generated by JetBrains Junie Pro AI code assistant.
- QR Code Generate Demo console app is a minimal port of the Java demo and working.
Repository Layout (Relevant to this PR)
csharp/QR-Code-generator.sln— Solution file containing two projects.csharp/QrCodeGen/— Class library (C# port of the Java library):BitBuffer.csDataTooLongException.csQrSegment.csQrSegmentAdvanced.cs(simplified vs. Java; see Feature Parity section)QrCode.cs
csharp/QrCodeGen.Demo/— Console demo app (depends onQrCodeGen).
Class-by-Class Mapping
-
Java
BitBuffer→ C#BitBuffer- API preserved: append bits, append buffer, length, get bit, cloning.
- Implementation uses
List<bool>and explicit bounds checks like Java’sBitSet/length pair.
-
Java
DataTooLongException→ C#DataTooLongException- Extends
ArgumentException(close analog to Java’sIllegalArgumentException).
- Extends
-
Java
QrSegment→ C#QrSegment- Static factories:
MakeBytes,MakeNumeric,MakeAlphanumeric,MakeEci. - Helpers:
IsNumeric,IsAlphanumericvia regexes mirroring Java patterns. - Mode enum and character-count bits mapping provided via extension methods.
GetTotalBits()faithfully ported.
- Static factories:
-
Java
QrSegmentAdvanced→ C#QrSegmentAdvanced- Included as an optional module. Current implementation mirrors the default segmentation path (numeric/alphanumeric/byte) and returns reasonably optimal segments for common inputs, but does not implement full DP-based optimal segmentation and Kanji mode. See Feature Parity and Future Work.
-
Java
QrCode→ C#QrCode- High-level APIs:
EncodeText,EncodeBinary. - Mid-level API:
EncodeSegmentswithminVersion,maxVersion,mask, andboostEclparameters. - Constructor path builds function patterns, computes ECC, interleaves, draws codewords, applies mask, and computes penalties identically.
- Tables
ECC_CODEWORDS_PER_BLOCKandNUM_ERROR_CORRECTION_BLOCKSported exactly. Signedsbyteused to allow-1sentinels. - All penalty and mask rules implemented verbatim.
- High-level APIs:
Feature Parity
-
Achieved parity:
- Version selection by capacity.
- Error correction level boosting (when it doesn’t increase version).
- Data stream building, terminator and padding, interleaving across ECC blocks.
- Drawing: finder, timing, alignment patterns; format and version information.
- Mask application and penalty scoring (N1–N4 rules) with identical logic.
- Reed–Solomon divisor/remainder algorithms and multiplication over GF(2^8/0x11D).
-
Intentional differences / limitations:
QrSegmentAdvanceddoes not implement:- Full dynamic-programming optimal segmentation across all modes.
- Kanji segment encoding.
- The default path still matches Java’s
QrSegment.makeSegments()selection (numeric/alphanumeric/byte) and therefore preserves functional outputs for typical text.
-
Behavioral equivalence expectations:
- For inputs limited to numeric/alphanumeric/byte, outputs should match Java for the same chosen mask (or mask-agnostic when mask=-1) and ECL.
Notable C#-Specific Decisions
sbyte[][]tables for ECC metadata to accommodate-1sentinel (Java byte is signed; C# byte is unsigned).- Enum helpers via extension methods for mapping to mode bits and character-count bits.
BitBuffercloning implemented to maintain immutability of exposed data as in Java.- Exceptions aligned to .NET conventions (e.g.,
ArgumentException,ArgumentOutOfRangeException).
Build and Run Instructions
- Target frameworks:
net8.0(both projects). If your machine only has .NET 9, either install .NET 8 or retarget both projects tonet9.0.
Commands from repo root:
dotnet restore csharp/QR-Code-generator.sln
dotnet build csharp/QR-Code-generator.sln -c Debug
# Run demo
dotnet run --project csharp/QrCodeGen.Demo
Rider/VS:
- Open
csharp/QR-Code-generator.slnand build. Ensure your IDE uses the Microsoft .NET SDK (not Homebrew’s) and that the installed SDK matchesnet8.0or update TFM tonet9.0.
Verification Performed
- Build succeeded locally after addressing initial compile issues (sbyte tables, enum constructor, finder pattern drawing, bit-buffer bounds).
- Demo run prints QR metadata and ASCII rendering for “Hello, world!”.
- Corrected a runtime bug where data bytes were read beyond
BitBufferlength; now we readnumDataBytes = bb.BitLength / 8and then apply 0xEC/0x11 padding.
Reviewer Checklist
- API Parity:
- QrCode: factory methods, mid-level encode, mask selection, ECC boosting.
- QrSegment: mode mapping, regex correctness, bit-length calculations.
- BitBuffer: bounds checks, append semantics, cloning.
- Tables: Verify ECC and block count tables match Java constants exactly.
- Masking/Penalties: Confirm penalty
N1..N4and zigzag codeword placement logic mirror Java. - Error Paths: Proper exceptions for out-of-range versions/masks/lengths.
- Padding: Verify 0xEC/0x11 alternating pad applied after real bytes from
BitBuffer. - Public API surface: Namespaces and visibility appropriate for a library; no leaking internals.
Known Gaps / Future Work
- Implement full
QrSegmentAdvanced:- DP-based optimal segmentation across modes.
- Kanji mode encoding per the Java version.
- Add unit tests:
- Cross-verify bitwise outputs vs. Java for a fixed mask across sample inputs.
- Randomized round-trips using known test vectors.
- Add simple image renderer (PNG/SVG) for easier visual verification.
- Performance: Consider bit-packing in
BitBufferto reduce allocations for very large payloads.
Migration Risks and Mitigations
- SDK Mismatch (net8.0 vs installed SDK): Documented; either install .NET 8 or retarget to
net9.0in both.csprojfiles. - Environment: Ensure the IDE uses Microsoft’s SDK at
/usr/local/share/dotnet; avoid Homebrew’s SDK confusion. - Behavior Drift: The simplified
QrSegmentAdvancedmay produce larger bitstreams for mixed-content strings vs. Java’s optimal splitter. This does not affect correctness, only compactness.
File List (Added/Modified)
- Added:
csharp/QR-Code-generator.slncsharp/QrCodeGen/QrCodeGen.csprojcsharp/QrCodeGen/BitBuffer.cscsharp/QrCodeGen/DataTooLongException.cscsharp/QrCodeGen/QrSegment.cscsharp/QrCodeGen/QrSegmentAdvanced.cscsharp/QrCodeGen/QrCode.cscsharp/QrCodeGen.Demo/QrCodeGen.Demo.csprojcsharp/QrCodeGen.Demo/Program.cs
How Reviewers Can Reproduce
- Build and run demo as above.
- Optionally compare module patterns vs. Java output with a fixed mask (pass
maskinEncodeSegments) over several sample strings.
License Alignment
- The C# port continues to follow the MIT License consistent with the Java version and includes the original copyright attribution.
Appendix: Usage Example
using Io.Nayuki.QrCodeGen;
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.MEDIUM);
for (int y = 0; y < qr.Size; y++) {
for (int x = 0; x < qr.Size; x++) {
bool dark = qr.GetModule(x, y);
// render module
}
}