0.9.0
🎉 Overview
v0.9.0 is a major update that includes significant performance improvements, API redesign, and the introduction of a more user-friendly Builder pattern.
⚡ Performance Improvements
This release dramatically improves QR code generation speed and memory efficiency:
Performance for several data types.
Memory Allocation Reduction
- Redesigned QRCodeData implementation from
List<BitArray>to 1Dbyte[]array (#233, #186) - Used
stackallocfor small datasets to reduce allocations (#236, #209, #212) - Leveraged ArrayPool for large datasets (#228, #237)
- Reused temporary QRCode objects during mask pattern selection (#207, #234)
- Removed allocations during FinderPattern placement (#243)
- Reduced re-allocations when adding masks by including QuietZone in constructor (#252)
Algorithm Optimization
- Replaced LINQ linear search O(n) with lookup table O(1) (#173)
- Removed LINQ from hot paths (#184, #198, #202)
- Eliminated Reflection usage (MaskCode) (#191)
- Executed penalty calculations in a single pass (#231, #241)
- Optimized Penalty3 calculation with sliding window 11-bit masking (#232)
- Optimized QR code module placement with bitmask (#244)
- Pre-calculated mod/div for mask pattern selection (#248)
- Wrote multiple bits at once (#225)
- Single-pass text analysis with TextAnalyzer (#229)
Data Structure Improvements
- Changed QR Code data tables from instance to Lazy static, initializing once (#171)
- Changed Point & Rectangle from class to readonly record struct (#166)
- Made Vector2Slim immutable (#196)
- Changed CodewordBlock to readonly struct (#199)
- Replaced string format/version operations with uint/ushort (#208)
Other Optimizations
- Changed char array access to range check for Numeric/AlphaNumeric (#168, #169)
- Used StringBuilder with capacity (#172)
- Specified List capacity (#185)
- Faster ISO-8859-1 validation with range check (#180)
- Removed unnecessary modulo in Galois multiplication (#247)
- Removed temporary collections with collection expressions (#211)
💥 Breaking Changes
API Changes
1. QrCode Class Deprecation and Migration to QRCodeImageBuilder
The QrCode class is now obsolete. Please use the new QRCodeImageBuilder instead. See detail #266
Before (Old API):
var qrCode = new QrCode(content, new Vector2Slim(512, 512), SKEncodedImageFormat.Png);
using (var output = new FileStream(path, FileMode.OpenOrCreate))
{
qrCode.GenerateImage(output);
}After (New API):
Simple QR code generation with static method:
var pngBytes = QRCodeImageBuilder.GetPngBytes(content);
File.WriteAllBytes(path, pngBytes);Advanced usage with builder pattern:
using var stream = File.OpenWrite(path);
var pngBytes = new QRCodeImageBuilder(content)
.WithSize(512, 512)
.WithErrorCorrection(ECCLevel.H)
.SaveTo(stream);2. IDisposable Removal
- Removed IDisposable from QRCodeData (#214)
- Removed IDisposable from QRCodeRenderer and changed to static class (#216, #220)
Remove using statements for these classes if you were using them.
// 0.8.0 and before
using var qrCodeData = QRCodeGenerator.CreateQrCode("Hello, World!", ECCLevel.L);
// 0.9.0 and after
var qrCodeData = QRCodeGenerator.CreateQrCode("Hello, World!", ECCLevel.L);// 0.8.0 and before
using var renderer = new QRCodeRenderer();
renderer.Render(...);
// 0.9.0 and after
QRCodeRenderer.Render(...);3. Stricter Null Checking
QRCodeRenderer.Render now throws ArgumentNullException when null data is passed (#218)
4. IconData Namespace Move
IconData moved to SkiaSharp.QrCode.Image namespace (#239)
Update your using directives:
using SkiaSharp.QrCode.Image;5. QuietZone Size Specification
QRCodeData(byte[] rawData) now accepts QuietZoneSize specification (#253)
Removed Features
- Removed
forceUtf8parameter (#177) - Removed ISO-8859-2 encoding support (#178)
- Removed compression feature (#256)
- Removed Kanji encoding mode (#269)
Encoding Changes
- Fixed empty data encoding from Numeric to Byte (#240)
✨ New Features
QRCodeImageBuilder - New Builder Pattern
Introduced a new API that provides static QR code image generation with a fluent builder pattern:
using var image = QRCodeImageBuilder.Create()
.WithContent("Hello, World!")
.WithECCLevel(ECCLevel.H)
.WithSize(pixelsPerModule: 10)
.WithColors(SKColors.Black, SKColors.White)
.WithIcon(iconData, iconSizePercent: 15)
.Build();Related PR: #264
Enhanced Rendering Features
- Gradient color support (#263)
- Enhanced QR code rendering customization options (#261)
- Consolidated rendering methods and batch rendering (#259, #260)
Binary Data Support
- Added binary data encoding for QR codes (#204)
- Changed Binary CreateQrCode to receive
ReadOnlySpan<char>(#205)
New APIs
🐛 Bug Fixes
- Fixed invalid QR code generation when upgraded version (EciMode.Default UTF8 fallback) (#179)
- Fixed ECC encoding to ensure the remainder always produces the expected number of ECC words (#183)
- Fixed Penalty3 calculation to execute for rows and columns separately (#242)
- Fixed GetVersion not considering UTF8 BOM header bytes (#250)
🔧 Refactoring & Internal Improvements
Encoding Redesign
- Replaced QR code generation with QREncoder and ECCEncoder (#176)
- Pipelined CreateQrCode (#197)
- QRCodeGenerator.CreateQrCode text API now forwards to binary API (#258)
Module Placement Improvements
- Internalized ModulePlacer (#190)
- Changed ModulePlacer receiver from
ref QRCodeDatatoSpan<byte>(#235) - Used span instead of static field header signature (#201)
Code Quality
- Enabled ImplicitUsings (#181)
- Enabled Nullable (#182)
- Refactored and optimized QR code constants (#167)
🛠️ Development Environment
- .NET 9.0 support (#170)
- Added .NET 8.0, handling .NET 5 or greater (#227)
- NativeAOT support (#267)
- Added benchmarks (#163, #226)
- Added README to NuGet (#162)
- Updated README (#270)
🔗 Links
Full Changelog: 0.8.0...0.9.0