Added porting documentation for code review

pull/235/head
Ye Wang 2 weeks ago
parent 65d4a70081
commit f9e64ba41e

@ -0,0 +1,173 @@
### 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 `QrCodeGen` and a minimal console demo `QrCodeGen.Demo`.
#### Goals
- Maintain functional parity with the Java reference (encoding pipeline, EC levels, masking, penalties, ReedSolomon 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.cs`
- `DataTooLongException.cs`
- `QrSegment.cs`
- `QrSegmentAdvanced.cs` (simplified vs. Java; see Feature Parity section)
- `QrCode.cs`
- `csharp/QrCodeGen.Demo/` — Console demo app (depends on `QrCodeGen`).
---
### 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 Javas `BitSet`/length pair.
- Java `DataTooLongException` → C# `DataTooLongException`
- Extends `ArgumentException` (close analog to Javas `IllegalArgumentException`).
- Java `QrSegment` → C# `QrSegment`
- Static factories: `MakeBytes`, `MakeNumeric`, `MakeAlphanumeric`, `MakeEci`.
- Helpers: `IsNumeric`, `IsAlphanumeric` via regexes mirroring Java patterns.
- Mode enum and character-count bits mapping provided via extension methods.
- `GetTotalBits()` faithfully ported.
- 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: `EncodeSegments` with `minVersion`, `maxVersion`, `mask`, and `boostEcl` parameters.
- Constructor path builds function patterns, computes ECC, interleaves, draws codewords, applies mask, and computes penalties identically.
- Tables `ECC_CODEWORDS_PER_BLOCK` and `NUM_ERROR_CORRECTION_BLOCKS` ported exactly. Signed `sbyte` used to allow `-1` sentinels.
- All penalty and mask rules implemented verbatim.
---
### Feature Parity
- Achieved parity:
- Version selection by capacity.
- Error correction level boosting (when it doesnt 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 (N1N4 rules) with identical logic.
- ReedSolomon divisor/remainder algorithms and multiplication over GF(2^8/0x11D).
- Intentional differences / limitations:
- `QrSegmentAdvanced` does not implement:
- Full dynamic-programming optimal segmentation across all modes.
- Kanji segment encoding.
- The default path still matches Javas `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 `-1` sentinel (Java byte is signed; C# byte is unsigned).
- Enum helpers via extension methods for mapping to mode bits and character-count bits.
- `BitBuffer` cloning 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 to `net9.0`.
Commands from repo root:
```sh
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.sln` and build. Ensure your IDE uses the Microsoft .NET SDK (not Homebrews) and that the installed SDK matches `net8.0` or update TFM to `net9.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 `BitBuffer` length; now we read `numDataBytes = bb.BitLength / 8` and 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..N4` and 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 `BitBuffer` to 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.0` in both `.csproj` files.
- Environment: Ensure the IDE uses Microsofts SDK at `/usr/local/share/dotnet`; avoid Homebrews SDK confusion.
- Behavior Drift: The simplified `QrSegmentAdvanced` may produce larger bitstreams for mixed-content strings vs. Javas optimal splitter. This does not affect correctness, only compactness.
---
### File List (Added/Modified)
- Added:
- `csharp/QR-Code-generator.sln`
- `csharp/QrCodeGen/QrCodeGen.csproj`
- `csharp/QrCodeGen/BitBuffer.cs`
- `csharp/QrCodeGen/DataTooLongException.cs`
- `csharp/QrCodeGen/QrSegment.cs`
- `csharp/QrCodeGen/QrSegmentAdvanced.cs`
- `csharp/QrCodeGen/QrCode.cs`
- `csharp/QrCodeGen.Demo/QrCodeGen.Demo.csproj`
- `csharp/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 `mask` in `EncodeSegments`) 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
```csharp
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
}
}
```
Loading…
Cancel
Save