← Playground

FeatherQR API

2.0.0.0 · 70 types · source 09bbc48

namespace FeatherQR

#enum DecodeStatus

public enum DecodeStatus : int

Result status of a decode attempt, shared by the Standard QR, Micro QR and rMQR decoders.

Success = 0,

Decoding succeeded.

InvalidMatrix = 1,

The input is not a valid module matrix (invalid size or no dark modules).

FormatInformationInvalid = 2,

Both format information copies are corrupted beyond BCH correction capacity.

DataUncorrectable = 3,

One or more Reed-Solomon blocks contain more errors than the ECC level can correct.

InvalidBitstream = 4,

The data bitstream is malformed (invalid segment values or truncated data).

UnsupportedContent = 5,

The bitstream is well-formed but uses a feature this decoder does not support: an ECI assignment it does not map to a charset (it reads 1, 3 and 27 as ISO-8859-1, 26 as UTF-8 and 20 as Shift_JIS). A property of the symbol's structure, not of its text. See UnmappedCharacter for the per-character case.

DestinationTooSmall = 6,

The destination buffer is too small for the decoded text.

NotDetected = 7,

No symbol was detected in the image (finder patterns not found or inconsistent).

UnmappedCharacter = 8,

The symbol was read correctly, but one character has no mapping under the charset this decoder applies, so no text is produced.

Notes

Today this means a Kanji mode cell outside JIS X 0208, in practice one of the 83 characters Microsoft CP932 adds in NEC row 13 (circled digits, roman numerals, unit ligatures). It is deliberately distinct from UnsupportedContent : that says the symbol uses a feature this library does not implement, and no reader choice changes it, whereas this says the symbol is well formed and a CP932-capable reader would read it. A caller that wants to fall back to such a reader should branch on exactly this status.

#enum EciMode

public enum EciMode : int

The character encoding declared in the symbol, as an ECI assignment.

Default = 0,

Picks the encoding from the content, which is what you want unless a reader demands otherwise.

Notes

Pure ASCII is sent with no ECI header at all, which is both smallest and most widely readable. Anything ISO-8859-1 can represent becomes Iso8859_1 , and the rest becomes Utf8 . With the generator's AllowKanji option, text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) is written in Kanji mode instead, with no ECI header, at 13 bits a character, and under Optimal segmentation text JIS X 0208 holds apart from its ASCII characters can be written as Kanji runs beside runs of that ASCII, again with no ECI header, where that is the smaller symbol. Seven JIS X 0208 characters that Windows code page 932 reads differently, among them the wave dash γ€œ and the minus sign βˆ’, keep a text in UTF-8, since a reader using that code page would show other characters. The header is the whole cost, 12 bits in Standard QR and 11 in rMQR, and it is what can push the content into a larger version. Two characters in Byte mode at version 1-9, where the count indicator is 8 bits wide: "HE" no header 4 + 8 + 16 = 28 bits "Ca" ECI 3 12 + 4 + 8 + 16 = 40 bits "πŸŽ‰" ECI 26 12 + 4 + 8 + 32 = 56 bits

Iso8859_1 = 3,

ISO-8859-1, covering ASCII plus Western European letters such as Γ€, Γ‡, Γ‘, Γ© and ΓΌ.

Notes

The ECI header costs 12 bits in Standard QR and 11 in rMQR. Emoji, CJK and Cyrillic cannot be encoded. Use Utf8 for those.

Utf8 = 26,

UTF-8, which covers every Unicode character: emoji, CJK, Cyrillic, Arabic, Hebrew and the rest.

Notes

The ECI header costs 12 bits in Standard QR and 11 in rMQR, and each character takes 1 to 4 bytes. For Western European text Iso8859_1 is denser, and for Japanese text the Kanji mode Default writes with the generator's AllowKanji option is. Asking for UTF-8 keeps such text in UTF-8 whatever that option says.

#struct Fnc1Mode

public readonly struct Fnc1Mode : IEquatable<Fnc1Mode>

The FNC1 mode a Standard QR or rMQR symbol carries (ISO/IEC 18004:2006 6.4.8, ISO/IEC 23941 7.4.8): written through Fnc1 and Fnc1 , read on Fnc1 and Fnc1 .

Notes

FNC1 in first position ( FirstPosition ) marks GS1 data: an element string of application identifiers and their values, with the group separator (GS, U+001D) after each variable-length value that another follows. FNC1 in second position ( SecondPosition , SecondPosition ) marks data in an industry format registered with AIM, named by an 8-bit application indicator ( ApplicationIndicator ): 00 to 99 as its value, or one letter A-Z or a-z as its ASCII value plus 100. None , the default, writes no indicator. The mode changes how the text reads. In an Alphanumeric segment a lone % is the separator and comes back as U+001D, and %% is one literal %, read left to right within the segment. A Byte segment carries the separator as the byte 0x1D. The encoder takes the text with U+001D as the separator and writes it under that rule, so the text given to the generator is the text the decoder returns. The decoded text is the data alone, the element string in first position. It holds neither a symbology identifier nor the application indicator. A reader transmits such a symbol as the AIM symbology identifier, then in second position the application indicator as two digits or one letter, then the data. The identifier is ]Q3 for first position and ]Q5 for second, one higher (]Q4, ]Q6) when the reader transmits under the ECI protocol (ISO/IEC 18004:2006 Annex F), and ]Q1 or ]Q2 without FNC1. The indicator n is written n < 100 ? n.ToString("D2") : ((char)(n - 100)).ToString(). A symbol without FNC1 reports default, on which IsFirstPosition and IsSecondPosition are both false and ApplicationIndicator is null, as it is in first position. A decoded mode is the value the generator takes, so a symbol can be written again from its decode info. Micro QR has no FNC1 mode.

property IsFirstPosition

public bool IsFirstPosition { get; }

true when the symbol carries FNC1 in first position: its text is a GS1 element string.

property IsSecondPosition

public bool IsSecondPosition { get; }

true when the symbol carries FNC1 in second position: its text follows the industry format ApplicationIndicator names.

property ApplicationIndicator

public int? ApplicationIndicator { get; }

The application indicator as on the wire in second position (0-99 as its value, or a letter's ASCII value plus 100), and null in first position and without FNC1. 00 is the value 0, so a missing indicator is null rather than a number.

property FirstPosition

public static Fnc1Mode FirstPosition { get; }

FNC1 in first position: GS1 data, an element string with U+001D as the separator.

property None

public static Fnc1Mode None { get; }

No FNC1, the default: the symbol's text is read as it is.

method SecondPosition

public static Fnc1Mode SecondPosition(char letter);

FNC1 in second position with a one-letter application indicator, A to Z or a to z, carried as its ASCII value plus 100.

method SecondPosition

public static Fnc1Mode SecondPosition(int number);

FNC1 in second position with a two-digit application indicator, 00 to 99. A letter indicator is given to SecondPosition .

#struct ImagePoint

public readonly struct ImagePoint : IEquatable<ImagePoint>

A position in an image, in continuous pixel coordinates: (0, 0) is the top-left corner of the top-left pixel and (width, height) the bottom-right corner of the image, so the value plots directly in SkiaSharp, a canvas or System.Drawing.

Notes

Produced by the image decoders as the corners of a located symbol ( SymbolCorners ). Module-space geometry, such as ModuleRect , is a different coordinate system: this one is pixels of the input image.

property X

public float X { get; }

Horizontal position in pixels, increasing to the right.

property Y

public float Y { get; }

Vertical position in pixels, increasing downward.

#struct MicroQRCodeCalculatedSize

public readonly struct MicroQRCodeCalculatedSize : IEquatable<MicroQRCodeCalculatedSize>

Result of TryGetRequiredBufferSize : buffer size, matrix side length and selected version for a pending Micro QR encode.

property Version

public MicroQRVersion Version { get; }

The Micro QR version that will be produced.

property BufferSize

public int BufferSize { get; }

Required destination buffer size in bytes (one byte per module, quiet zone included).

property Size

public int Size { get; }

Matrix side length in modules, quiet zone included.

#class MicroQRCodeData

public sealed class MicroQRCodeData

A Micro QR code as a module matrix, ready to render, serialize or decode.

Notes

The matrix is bit-packed and sized by version, from 11 Γ— 11 at M1 to 17 Γ— 17 at M4, plus the quiet zone. Serialization writes a "QRX" header carrying the symbology and dimensions, then the packed modules.

constructor MicroQRCodeData

public MicroQRCodeData(MicroQRVersion version, int quietZoneSize);

Creates an empty matrix sized for the given version.

constructor MicroQRCodeData

public MicroQRCodeData(ReadOnlySpan<byte> rawData, int quietZoneSize);

constructor MicroQRCodeData

public MicroQRCodeData(byte[] rawData, int quietZoneSize);

Restores a Micro QR code from bytes written by GetRawData .

Notes

The serialized form is a "QRX" header (3 bytes), the symbology (1 byte), the width and height (1 byte each), then the bit-packed modules. It holds the core modules only, so the quiet zone is chosen again here and need not match the one the code was serialized with.

property Version

public MicroQRVersion Version { get; }

The Micro QR code version, M1 to M4.

indexer this[int row, int col]

public bool this[int row, int col] { get; }

The module at the given position.

Notes

Quiet zone positions always read false: the quiet zone is light by definition and is not stored.

property Size

public int Size { get; }

Side length in modules, quiet zone included.

method GetModuleRectangles

public ModuleRect[] GetModuleRectangles();

The dark modules as merged rectangles, for drawing the Micro QR code with any graphics API: SVG paths, draw calls, vector output.

Notes

Coordinates match the indexer: one unit is one module, the origin is the top-left corner including the quiet zone, X is the column and Y the row. Scale by the pixel size of one module. Size gives the total extent in modules. The three guarantees above are contractual, but the shape and order of the decomposition are not, and may change between versions. Currently they are maximal horizontal runs in row-major order, the same merge the built-in renderer draws for an unstyled symbol. A styled one draws its finder patterns as whole patterns instead.

method TryGetModuleRectangles

public bool TryGetModuleRectangles(Span<ModuleRect> destination, out int written);

Writes the rectangles of GetModuleRectangles into the buffer you provide, without allocating.

method GetRawData

public byte[] GetRawData();

Serializes the Micro QR code so it can be stored, sent or cached.

Notes

Writes a "QRX" header (3 bytes), the symbology (1 byte), the width and height (1 byte each), then the bit-packed modules. The quiet zone is not written, so pick its width again when restoring.

method GetModuleRectanglesMaxCount

public int GetModuleRectanglesMaxCount();

Gets an upper bound on the number of rectangles GetModuleRectangles can return, suitable for sizing a pooled buffer for TryGetModuleRectangles . O(1), no matrix scan.

method GetRawData

public int GetRawData(IBufferWriter<byte> writer);

Serializes the Micro QR code into a buffer writer, without allocating a byte array.

method GetRawDataSize

public int GetRawDataSize();

How many bytes GetRawData produces for this Micro QR code.

#struct MicroQRCodeDecodeInfo

public readonly struct MicroQRCodeDecodeInfo : IEquatable<MicroQRCodeDecodeInfo>

Diagnostic information produced by a Micro QR code decode attempt.

Notes

Statuses are shared with the Standard QR decoder ( DecodeStatus ). Version, ECC level and mask pattern use the Micro QR domains.

property Status

public DecodeStatus Status { get; }

Decode result status. Success when decoding succeeded.

property EccLevel

public MicroQREccLevel EccLevel { get; }

Error correction level read from the format information.

property Version

public MicroQRVersion Version { get; }

Micro QR version (M1-M4), or default (0) when the matrix was invalid.

property Corners

public SymbolCorners Corners { get; }

Where the symbol sits in the image, when decoded from one. See SymbolCorners . Empty for a matrix-level decode or a failed one.

property ErrorsCorrected

public int ErrorsCorrected { get; }

Number of codeword errors corrected by Reed-Solomon decoding.

property MaskPattern

public int MaskPattern { get; }

Mask pattern (0-3) read from the format information, or -1 when unknown.

#class MicroQRCodeDecoder

public static class MicroQRCodeDecoder

Micro QR code decoder based on ISO/IEC 18004. Decodes Micro QR module matrices back into text, including Reed-Solomon error correction.

Notes

Reads Numeric, Alphanumeric and Byte mode across M1 to M4, and Kanji in M3 and M4. Micro QR has no ECI, so a Byte segment is read as UTF-8 when the bytes are valid UTF-8, as Shift_JIS when they are well formed Shift_JIS that ISO-8859-1 text would not hold and hold no C0 control character but tab, CR and LF, and as ISO-8859-1 otherwise. Kanji is mapped through JIS X 0208, so a cell outside that repertoire fails the whole Micro QR code with UnmappedCharacter rather than substituting a replacement character. Image scanning reads screen images, scans and camera photographs, including rotation, mirroring, inverted colors, scaling and mild perspective. It is a separate entry point, and QRCodeDecoder keeps scanning Standard QR only.

method TryDecode

public static bool TryDecode(MicroQRCodeData data, out string text);

Decodes the text from a Micro QR code.

method TryDecode

public static bool TryDecode(MicroQRCodeData data, out string text, out MicroQRCodeDecodeInfo info);

Decodes the text from a Micro QR code and reports what it found.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int size, Span<char> destination, out int charsWritten, out MicroQRCodeDecodeInfo info);

Decodes the text into the buffer you provide, without allocating.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int size, out string text, out MicroQRCodeDecodeInfo info);

Decodes the text from a module matrix.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, Span<char> destination, out int charsWritten, out MicroQRCodeDecodeInfo info);

Finds and decodes a Micro QR code in a grayscale image, writing into the buffer you provide without allocating.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, out string text, out MicroQRCodeDecodeInfo info);

Finds and decodes a Micro QR code in a grayscale image.

method GetMaxDecodedLength

public static int GetMaxDecodedLength(MicroQRVersion version);

The most characters a Micro QR code of this version can decode to, across every error correction level and mode. Use it to size the destination of the allocation-free overloads.

#class MicroQRCodeGenerator

public static class MicroQRCodeGenerator

Encodes text into a Micro QR code (ISO/IEC 18004), versions M1 to M4.

Notes

What each version accepts differs, and a combination it does not offer throws rather than quietly falling back: M1: Numeric only, at ErrorDetectionOnly .M2: Numeric and Alphanumeric, at L or M.M3: adds Byte and Kanji, at L or M.M4: adds level Q. Micro QR has no ECI. Text outside ISO-8859-1 goes out as raw UTF-8 in Byte mode, which a reader has to recognise as UTF-8. With AllowKanji , text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) goes out in Kanji mode instead, at 13 bits a character, which is the standard's own way to carry it. Under Optimal , such text with ASCII in it can be written as Kanji runs beside runs of the ASCII, where that is the smaller symbol.

method Create

public static MicroQRCodeData Create(ReadOnlySpan<char> textSpan, MicroQREccLevel eccLevel, in MicroQRCodeGeneratorOptions options = null);

Encodes text into a Micro QR code.

method TryGetRequiredBufferSize

public static bool TryGetRequiredBufferSize(ReadOnlySpan<char> text, MicroQREccLevel eccLevel, out MicroQRCodeCalculatedSize size, in MicroQRCodeGeneratorOptions options = null);

Reports how large the Micro QR code will be, or false when the content does not fit.

Notes

false means that and only that. Bad arguments still throw. Since the text picks the mode, it also covers a mode the version or level does not offer, and M1 holds 5 digits, so not fitting is an ordinary answer here. Pass the options you will encode with, since segmentation can pick a different version and a buffer sized for one can be too small for the other.

method Create

public static int Create(ReadOnlySpan<char> textSpan, MicroQREccLevel eccLevel, Span<byte> destination, in MicroQRCodeGeneratorOptions options = null);

Encodes text into the buffer you provide, without allocating.

Notes

One byte per module, 0 light and 1 dark, row-major with the quiet zone included, so the module at (row, col) is destination[row * size + col].

#struct MicroQRCodeGeneratorOptions

public struct MicroQRCodeGeneratorOptions : IEquatable<MicroQRCodeGeneratorOptions>

Optional settings for MicroQRCodeGenerator . default is the complete default configuration (automatic version, 2-module quiet zone), so set only what you need: new MicroQRCodeGeneratorOptions { Version = MicroQRVersion.M3, QuietZoneSize = 0 }.

Notes

The smallest option set of the three symbologies: Micro QR has no ECI, and no fit strategy because M1-M4 are totally ordered by capacity. A plain value a caller may assign to and copy with with, for the reasons on QRCodeGeneratorOptions .

property Segmentation

public MicroQRSegmentation Segmentation { get; set; }

How the content is split into encoding-mode segments (see MicroQRSegmentation ). Defaults to Optimal . Optimal never selects a larger version, and emits the identical bit stream when a split would not shrink the symbol. Size a destination buffer with the same value you encode with.

property Version

public MicroQRVersionRange Version { get; set; }

The versions the generator may choose from. Defaults to Any . A MicroQRVersion or its nullable converts implicitly, so a null means automatic.

property AllowKanji

public bool AllowKanji { get; set; }

Write text in Kanji mode where it can be: 13 bits a character, where UTF-8 takes 24 bits a kana or kanji. Off by default.

Notes

Text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) is one Kanji segment, and under Optimal text that is so apart from its ASCII can be Kanji runs beside runs of that ASCII, where that is the smaller symbol. Seven JIS X 0208 characters that Windows code page 932 reads differently, among them the wave dash γ€œ, keep a text in UTF-8, as does any character outside the table. Kanji mode exists from M3, and nearly doubles what Japanese text fits: M4-L holds 9 characters in Kanji mode and 5 in UTF-8. Micro QR has no ECI, so its UTF-8 bytes read as UTF-8 only in a reader that recognises them, where Kanji mode declares itself. Off by default, as on the other two symbologies, because not every reader reads Kanji mode: in Standard QR an Android 17 phone's own QR scanner and Google Lens on it show nothing readable for it. Neither phone's own scanner reads Micro QR at all. The dedicated readers tried read it in Kanji mode and in UTF-8 alike.

property QuietZoneSize

public int QuietZoneSize { get; set; }

Quiet zone width in modules. Defaults to 2, the ISO/IEC 18004 value for Micro QR. 0 is valid.

property MaskPattern

public int? MaskPattern { get; set; }

Pin one of the four Micro QR data mask patterns (0-3, ISO/IEC 18004 Table 10) instead of the automatic edge-score selection. null (the default) selects the highest-scoring pattern. Any pattern yields a valid, decodable symbol. The automatic choice merely optimizes scan reliability.

Notes

For reproducing a symbol produced elsewhere byte-for-byte (the pattern another encoder chose is reported by MaskPattern ), and for exercising a decoder against all four patterns. Micro QR numbers its patterns 0-3, but they are not the Standard QR patterns of the same index. Like Version , an invalid value is an argument error and is rejected here rather than when a generator reads it.

property Default

public static MicroQRCodeGeneratorOptions Default { get; }

The default configuration, identical to default.

#enum MicroQREccLevel

public enum MicroQREccLevel : int

Micro QR Code error correction level (ISO/IEC 18004). Micro QR levels differ from Standard QR QREccLevel : version M1 supports error detection only, and level H does not exist.

ErrorDetectionOnly = 0,

Error detection only, no correction capacity. Valid only for version M1.

L = 1,

~7% recovery capacity. Valid for versions M2-M4.

M = 2,

~15% recovery capacity. Valid for versions M2-M4.

Q = 3,

~25% recovery capacity. Valid for version M4 only.

#enum MicroQRSegmentation

public enum MicroQRSegmentation : int

How MicroQRCodeGenerator splits the content into encoding-mode segments. Micro QR capacities are tiny (5 digits at M1, 15 Byte-mode characters at M4-L), so mixing modes (for example a short prefix followed by a numeric tail) can drop the symbol a version, or encode content no single mode fits at all.

Optimal = 0,

The default: the mixed-mode split with the fewest total bits. Text JIS X 0208 holds apart from its ASCII characters can be written as Kanji runs beside runs of that ASCII, when AllowKanji is set and that is the smaller symbol. Never selects a larger version than Single , emits the Single bit stream verbatim when a split would not shrink the symbol, and additionally encodes content that overflows every version in a single mode, unless the minimal-bit plan would be misread on decode (a Latin-1 run the charset heuristic would read as UTF-8 or Shift_JIS), in which case it reports "does not fit" rather than emitting a stream that decodes differently. A U+FEFF inside UTF-8 content never opens a Byte run, where a reader would drop it as a byte order mark: the run opens a character early and keeps it interior.

Notes

The search prices candidate versions and allocates nothing (Micro QR content never exceeds 35 characters). Single skips it. The plan respects each version's mode set (M1 is Numeric-only and M2 has no Byte mode), so a version is never selected for a plan whose runs it cannot carry. Size buffers with the same segmentation you encode with, the two can select different versions.

Single = 1,

One segment in the single mode that can represent the whole content (Numeric, else Alphanumeric, else Byte, or Kanji for text JIS X 0208 holds entirely when AllowKanji is set). The cheapest to encode: one pass over the content and no version search, and the bit stream every release before 2.0.0 emitted.

#enum MicroQRVersion

public enum MicroQRVersion : int

Micro QR version (ISO/IEC 18004), which fixes the size: M1 is 11 Γ— 11 modules, M2 13 Γ— 13, M3 15 Γ— 15 and M4 17 Γ— 17.

M1 = 1,

11Γ—11 modules. Numeric mode only, error detection only.

M2 = 2,

13Γ—13 modules. Numeric and Alphanumeric modes, ECC L/M.

M3 = 3,

15Γ—15 modules. Numeric, Alphanumeric and Byte modes, ECC L/M.

M4 = 4,

17Γ—17 modules. Numeric, Alphanumeric and Byte modes, ECC L/M/Q.

#struct MicroQRVersionRange

public readonly struct MicroQRVersionRange : IEquatable<MicroQRVersionRange>

The Micro QR versions a generator may choose from: the smallest one in the range that holds the content is used. The Micro QR counterpart of QRVersionRange .

Notes

M1-M4 differ in the modes and ECC levels they offer, not only in capacity, so a range can leave nothing usable for two reasons. No version offering the requested ECC level is a contradiction and throws. None carrying the mode the text needs is a poor fit and returns false, since the text is what picks the mode.

constant MaxVersion

public const MicroQRVersion MaxVersion;

The highest Micro QR version, M4.

constant MinVersion

public const MicroQRVersion MinVersion;

The lowest Micro QR version, M1.

constructor MicroQRVersionRange

public MicroQRVersionRange(MicroQRVersion min, MicroQRVersion max);

An inclusive range from min to max .

property Max

public MicroQRVersion Max { get; }

The highest permitted version (M4 when unbounded above).

property Min

public MicroQRVersion Min { get; }

The lowest permitted version (M1 when unbounded below).

property IsAny

public bool IsAny { get; }

Whether this range constrains nothing (the default).

property IsExact

public bool IsExact { get; }

Whether this range pins a single version.

property Any

public static MicroQRVersionRange Any { get; }

Every version, M1 to M4. Identical to default.

method Contains

public bool Contains(MicroQRVersion version);

Whether version falls inside this range.

method ToString

public override string ToString();

method AtLeast

public static MicroQRVersionRange AtLeast(MicroQRVersion version);

version or larger.

method AtMost

public static MicroQRVersionRange AtMost(MicroQRVersion version);

version or smaller.

method Between

public static MicroQRVersionRange Between(MicroQRVersion min, MicroQRVersion max);

An inclusive range from min to max .

method Exactly

public static MicroQRVersionRange Exactly(MicroQRVersion version);

Exactly version , with no automatic selection.

operator op_Implicit

public static MicroQRVersionRange op_Implicit(MicroQRVersion version);

A single version, as Exactly .

operator op_Implicit

public static MicroQRVersionRange op_Implicit(MicroQRVersion? version);

A single version, or Any when there is none, so an optional version needs no branch.

#struct ModuleRect

public readonly struct ModuleRect : IEquatable<ModuleRect>

An axis-aligned rectangle of dark modules, in module coordinates. Produced by the GetModuleRectangles family on QRCodeData , MicroQRCodeData , and RmQRCodeData .

Notes

Coordinates use the same space as the matrix indexer: one unit is one module, origin at the top-left corner of the symbol including its quiet zone, X growing right and Y growing down. The module at column c, row r read via data[r, c] corresponds to the unit rectangle at X = c, Y = r. Renderers map to pixels by multiplying all four values by the pixel size of one module. No scale or pixel size is baked in, so the same value works for SVG path data (viewBox in module units), draw calls, and any other coordinate transform the consumer applies.

constructor ModuleRect

public ModuleRect(int X, int Y, int Width, int Height);

An axis-aligned rectangle of dark modules, in module coordinates. Produced by the GetModuleRectangles family on QRCodeData , MicroQRCodeData , and RmQRCodeData .

Notes

Coordinates use the same space as the matrix indexer: one unit is one module, origin at the top-left corner of the symbol including its quiet zone, X growing right and Y growing down. The module at column c, row r read via data[r, c] corresponds to the unit rectangle at X = c, Y = r. Renderers map to pixels by multiplying all four values by the pixel size of one module. No scale or pixel size is baked in, so the same value works for SVG path data (viewBox in module units), draw calls, and any other coordinate transform the consumer applies.

property Height

public int Height { get; init; }

Height in modules (always positive).

property Width

public int Width { get; init; }

Width in modules (always positive).

property X

public int X { get; init; }

Column of the left edge (0-based, including the quiet zone if present).

property Y

public int Y { get; init; }

Row of the top edge (0-based, including the quiet zone if present).

#struct QRCodeCalculatedSize

public readonly struct QRCodeCalculatedSize : IEquatable<QRCodeCalculatedSize>

Result of TryGetRequiredBufferSize : buffer size, matrix side length and selected version for a pending QR code encode.

property BufferSize

public int BufferSize { get; }

Required destination buffer size in bytes (one byte per module, quiet zone included).

property Size

public int Size { get; }

Matrix side length in modules, quiet zone included.

property Version

public int Version { get; }

The QR code version (1-40) that will be produced.

#class QRCodeData

public sealed class QRCodeData

A Standard QR code as a module matrix, ready to render, serialize or decode.

Notes

The matrix is bit-packed and sized by version, from 21 Γ— 21 at version 1 to 177 Γ— 177 at version 40, plus the quiet zone. Serialization writes a "QRR" header, the size, then the packed modules.

constructor QRCodeData

public QRCodeData(ReadOnlySpan<byte> rawDataSpan, int quietZoneSize);

Restores a QR code from bytes written by GetRawData , without copying them into an array first.

Notes

The serialized form is a "QRR" header (3 bytes), the base size (1 byte), then the bit-packed modules. It holds the core modules only, so the quiet zone is chosen again here and need not match the one the code was serialized with.

constructor QRCodeData

public QRCodeData(byte[] rawData, int quietZoneSize);

Restores a QR code from bytes written by GetRawData .

Notes

The serialized form is a "QRR" header (3 bytes), the base size (1 byte), then the bit-packed modules. It holds the core modules only, so the quiet zone is chosen again here and need not match the one the code was serialized with.

constructor QRCodeData

public QRCodeData(int version, int quietZoneSize);

Creates an empty matrix sized for the given version.

indexer this[int row, int col]

public bool this[int row, int col] { get; }

The module at the given position.

Notes

Quiet zone positions always read false: the quiet zone is light by definition and is not stored.

property Size

public int Size { get; }

Side length in modules, quiet zone included.

property Version

public int Version { get; }

The QR code version, 1 to 40.

method GetModuleRectangles

public ModuleRect[] GetModuleRectangles();

The dark modules as merged rectangles, for drawing the QR code with any graphics API: SVG paths, draw calls, vector output.

Notes

Coordinates match the indexer: one unit is one module, the origin is the top-left corner including the quiet zone, X is the column and Y the row. Scale by the pixel size of one module. Size gives the total extent in modules. The three guarantees above are contractual, but the shape and order of the decomposition are not, and may change between versions. Currently they are maximal horizontal runs in row-major order, the same merge the built-in renderer draws for an unstyled symbol. A styled one draws its finder patterns as whole patterns instead.

method IsFinderPattern

public bool IsFinderPattern(int row, int col);

Tells whether a module belongs to one of the three finder patterns, so a renderer can style them apart.

method TryGetModuleRectangles

public bool TryGetModuleRectangles(Span<ModuleRect> destination, out int written);

Writes the rectangles of GetModuleRectangles into the buffer you provide, without allocating.

method GetRawData

public byte[] GetRawData();

Serializes the QR code so it can be stored, sent or cached.

Notes

Writes a "QRR" header (3 bytes), the base size (1 byte), then the bit-packed modules. The quiet zone is not written, so pick its width again when restoring through #ctor .

method GetFinderPatternIndex

public int GetFinderPatternIndex(int row, int col);

Tells which finder pattern a module belongs to, so each corner can be styled separately.

method GetModuleRectanglesMaxCount

public int GetModuleRectanglesMaxCount();

Gets an upper bound on the number of rectangles GetModuleRectangles can return, suitable for sizing a pooled buffer for TryGetModuleRectangles . O(1), no matrix scan.

method GetRawData

public int GetRawData(IBufferWriter<byte> writer);

Serializes the QR code into a buffer writer, without allocating a byte array.

Notes

The quiet zone is not written, so pick its width again when restoring.

method GetRawDataSize

public int GetRawDataSize();

How many bytes GetRawData produces for this QR code.

#struct QRCodeDecodeInfo

public readonly struct QRCodeDecodeInfo : IEquatable<QRCodeDecodeInfo>

Diagnostic information produced by a QR code decode attempt.

property Status

public DecodeStatus Status { get; }

Decode result status. Success when decoding succeeded.

property Fnc1

public Fnc1Mode Fnc1 { get; }

The FNC1 mode, when the symbol carries one (GS1 data, or an industry format with its application indicator). See Fnc1Mode . default, neither position, for a symbol that carries none or a failed decode.

property EccLevel

public QREccLevel EccLevel { get; }

Error correction level read from the format information.

property StructuredAppend

public QRStructuredAppend StructuredAppend { get; }

The Structured Append header, when the symbol is one of a set. See QRStructuredAppend . Empty for a symbol that carries none, or a failed decode.

property Corners

public SymbolCorners Corners { get; }

Where the symbol sits in the image, when decoded from one. See SymbolCorners . Empty for a matrix-level decode or a failed one.

property ErrorsCorrected

public int ErrorsCorrected { get; }

Total number of codeword errors corrected by Reed-Solomon decoding.

property MaskPattern

public int MaskPattern { get; }

Mask pattern (0-7) read from the format information, or -1 when unknown.

property Version

public int Version { get; }

QR code version (1-40), or 0 when the matrix was invalid.

#class QRCodeDecoder

public static class QRCodeDecoder

Decodes a Standard QR code (ISO/IEC 18004) back into text, correcting errors as it goes.

Notes

Reads Numeric, Alphanumeric, Byte and Kanji mode across all versions and error correction levels. A Byte segment is read as its ECI header declares, for ISO-8859-1, UTF-8 and Shift_JIS. With no ECI header it is read as UTF-8 when the bytes are valid UTF-8 (or carry a BOM), as Shift_JIS when they are well formed Shift_JIS that ISO-8859-1 text would not hold and hold no C0 control character but tab, CR, LF and, under FNC1, the separator 0x1D, and as ISO-8859-1 otherwise. Shift_JIS is read through JIS X 0208, as Kanji mode is. Kanji is mapped through JIS X 0208, so a cell outside that repertoire, such as the circled digits CP932 adds, fails the whole QR code with UnmappedCharacter rather than substituting a replacement character. That status is distinct from UnsupportedContent , which marks a feature this library does not implement, such as an ECI assignment other than 1, 3 and 27 (ISO-8859-1), 26 (UTF-8) and 20 (Shift_JIS). FNC1 in first position (GS1 data) and in second position (an industry format with its application indicator) are read: the text is the data with each separator as U+001D, the element string in first position, a %% in an Alphanumeric segment is one %, and the mode is reported on Fnc1 .

method TryDecode

public static bool TryDecode(QRCodeData data, out string text);

Decodes the text from a QR code.

method TryDecode

public static bool TryDecode(QRCodeData data, out string text, out QRCodeDecodeInfo info);

Decodes the text from a QR code and reports what it found.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int size, Span<char> destination, out int charsWritten, out QRCodeDecodeInfo info);

Decodes the text into the buffer you provide, without allocating.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int size, out string text, out QRCodeDecodeInfo info);

Decodes the text from a module matrix.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, Span<char> destination, out int charsWritten, out QRCodeDecodeInfo info);

Finds and decodes a QR code in a grayscale image, writing into the buffer you provide without allocating.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, out string text, out QRCodeDecodeInfo info);

Finds and decodes a QR code in a grayscale image.

method GetMaxDecodedLength

public static int GetMaxDecodedLength(int version);

The most characters a QR code of this version can decode to, across every error correction level and mode. Use it to size the destination of the allocation-free overloads.

#class QRCodeGenerator

public static class QRCodeGenerator

Encodes text into a Standard QR code (ISO/IEC 18004), versions 1 to 40.

Notes

Writes Numeric, Alphanumeric and Byte mode, the last as ISO-8859-1 or UTF-8 with an ECI header, and Kanji mode. Kanji mode carries text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) at 13 bits a character with no ECI header, where UTF-8 would take 16 or 24. It is written only when the caller sets AllowKanji , the charset is left at Default and no byte order mark is asked for, and that option is off by default because an Android phone's own scanners read none of it. Under Optimal such text with ASCII in it can be written as Kanji runs beside Numeric, Alphanumeric and Byte runs of the ASCII, where that is the smaller symbol. A Structured Append set of such text is written in Kanji mode too, with the XOR of the text's Shift_JIS bytes as its parity: under both segmentations when every character is in the table, and under Optimal with ASCII in it where that set needs fewer symbols than the UTF-8 set, or as many at a lower version.

method Create

public static QRCodeData Create(ReadOnlySpan<char> textSpan, QREccLevel eccLevel, in QRCodeGeneratorOptions options = null);

Encodes text into a QR code.

method CreateStructuredAppend

public static QRCodeData[] CreateStructuredAppend(ReadOnlySpan<char> textSpan, QREccLevel eccLevel, in QRCodeGeneratorOptions options = null);

Encodes text as a Structured Append set: up to sixteen QR codes that a reader reassembles into one message.

Notes

The symbol count comes from Version : the text is split across the fewest symbols whose version stays within the range, so QRVersionRange.AtMost(n) is how to say how large a symbol may be. Every symbol of the set shares one version, and the split is balanced so the fullest symbol is as empty as it can be, rather than filling each symbol and leaving the remainder to the last one. Text that fits one symbol within the range returns that one symbol, exactly as Create would, with no Structured Append header. An FNC1 mode in Fnc1 is refused, for text that fits one symbol too, since no reader is known to read FNC1 across a set. The charset is decided once for the whole text and declared in every symbol, and the parity every symbol carries is the XOR of the whole text's bytes in that charset. With AllowKanji , text that Kanji mode carries (see the class remarks) makes a Kanji set instead: no symbol declares a charset, a chunk is one Kanji segment under Single or its mix of Kanji and ASCII runs under Optimal , and the parity is the XOR of the whole text's Shift_JIS bytes. With ASCII in the text the set is a Kanji set only under Optimal , and only where it needs fewer symbols than the UTF-8 set, or as many at a lower version. Utf8 keeps the UTF-8 set. A byte order mark, when Utf8Bom asks for one, is written in the first symbol only, and only when that symbol is in Byte mode: the mark heads the byte stream, and a first symbol of digits or alphanumerics has none to head, so the set then carries no mark and the parity counts none. BoostEccLevel raises the whole set to the level every symbol can take. Splits never fall inside a surrogate pair, nor, in UTF-8, before a U+FEFF: a reader takes one at the head of a symbol for a byte order mark and drops it, which is also what becomes of one at the head of the text, as it does in a single symbol. Reassembly is described on QRStructuredAppend . Each symbol decodes to its own part of the text.

method TryGetRequiredBufferSize

public static bool TryGetRequiredBufferSize(ReadOnlySpan<char> text, QREccLevel eccLevel, out QRCodeCalculatedSize size, in QRCodeGeneratorOptions options = null);

Reports how large the QR code will be, or false when the content does not fit.

Notes

false means that and only that. Bad arguments still throw. With a narrowed Version it means no version in that range holds the content, not that it exceeds version 40. Pass the options you will encode with, since segmentation and ECI can pick different versions and a buffer sized for one can be too small for the other. BoostEccLevel makes no difference here, as the boost never changes the version.

method Create

public static int Create(ReadOnlySpan<char> textSpan, QREccLevel eccLevel, Span<byte> destination, in QRCodeGeneratorOptions options = null);

Encodes text into the buffer you provide, without allocating.

Notes

One byte per module, 0 light and 1 dark, row-major with the quiet zone included, so the module at (row, col) is destination[row * size + col]. Every byte up to BufferSize is written, so a dirty pooled buffer is fine, and anything past that is left alone. if (!QRCodeGenerator.TryGetRequiredBufferSize(text, QREccLevel.M, out var calculated)) return; // does not fit version 40 at this level var buffer = ArrayPool<byte>.Shared.Rent(calculated.BufferSize); var written = QRCodeGenerator.Create(text, QREccLevel.M, buffer); // ... consume buffer.AsSpan(0, written) ... ArrayPool<byte>.Shared.Return(buffer);

#struct QRCodeGeneratorOptions

public struct QRCodeGeneratorOptions : IEquatable<QRCodeGeneratorOptions>

Optional settings for QRCodeGenerator . default is the complete default configuration, so set only what you need: new QRCodeGeneratorOptions { EciMode = EciMode.Utf8, QuietZoneSize = 0 }.

Notes

Standard QR specific rather than shared: the three generators agree on almost nothing. Version is a different type in each, QuietZoneSize defaults to 4 here and to 2 in the other two, Micro QR has no ECI, and rMQR carries fit options that mean nothing here. A plain value: write it with an object initializer, assign a member afterwards (options.QuietZoneSize = 0;), or copy it with with, and the three give equal values. Each variable holds its own value: assigning it to another variable, or passing it to a method by value, copies it, so an assignment changes one variable and no copy of it. A method or a callback that takes the options by value and assigns to them therefore changes only its own copy, and has to return them or take them by ref. The generators take the options by in, a reference: they read it during the call and do not keep a reference to it afterwards, so do not assign to that variable from another thread while a call is running. The members have set accessors, not init: an object initializer over them compiles at C# 7.3, where init needs C# 9, so no constructor has to list the options and an option added later is one more property.

property EciMode

public EciMode EciMode { get; set; }

Character encoding declaration. The default auto-detects ASCII (no ECI), ISO-8859-1 (assignment 3) or UTF-8 (assignment 26) from the content, and with AllowKanji Kanji mode (no ECI) for text JIS X 0208 holds.

property Fnc1

public Fnc1Mode Fnc1 { get; set; }

The FNC1 mode to write (ISO/IEC 18004:2006 6.4.8): FirstPosition for GS1 data, or second position with an application indicator for an industry format registered with AIM. Defaults to None .

Notes

The content is the data as a reader returns it, with U+001D as the separator and without a symbology identifier or the application indicator. In first position it is a GS1 element string, with the separator after each variable-length value another follows. The indicator is written after any ECI header and before the data, and in an Alphanumeric segment the separator is written as % and a literal % as %%, so the content reads back as given. A separator followed by a separator or a literal % cannot share an Alphanumeric segment, since a reader takes the %% first: such content takes Byte mode under Single , and Optimal breaks the run or uses Byte mode, whichever is smaller. The mode costs 4 bits in first position and 12 in second, which can move content at a version's edge to the next version. Size a destination buffer with the same value you encode with. A Structured Append set refuses FNC1 ( CreateStructuredAppend throws ArgumentException ), as no reader is known to read FNC1 across a set. Whether the data is valid GS1 data is not checked here. The FeatherQR.Gs1 package checks element strings and builds them from (AI) text.

property Segmentation

public QRSegmentation Segmentation { get; set; }

How the content is split into encoding-mode segments (see QRSegmentation ). Defaults to Optimal . Optimal never selects a larger version, emits the identical bit stream when a split would not shrink the symbol, and defers to the single-mode stream when Utf8Bom would actually write a byte order mark. Size a destination buffer with the same value you encode with.

property Version

public QRVersionRange Version { get; set; }

The versions the generator may choose from. Defaults to Any . An int or int? converts implicitly, so Version = 15 pins one and a null means automatic.

property AllowKanji

public bool AllowKanji { get; set; }

Write text in Kanji mode where it can be: 13 bits a character and no ECI header, where UTF-8 takes 24 bits a kana or kanji behind a 12-bit ECI header. Off by default.

Notes

Applies only where the charset is the library's choice ( Default ) and no byte order mark is asked for ( Utf8Bom ). A charset the caller names is written as named. Then text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) is one Kanji segment, and under Optimal text that is so apart from its ASCII can be Kanji runs beside runs of that ASCII, where that is the smaller symbol. Seven JIS X 0208 characters that Windows code page 932 reads differently, among them the wave dash γ€œ, keep a text in UTF-8, as does any character outside the table. A Structured Append set made with this option can be a Kanji set: no symbol carries an ECI header, and the parity is the XOR of the whole text's Shift_JIS bytes. Off by default because not every reader reads Kanji mode. An Android 17 phone's own QR scanner and Google Lens on it show nothing readable for it, where they read UTF-8 behind ECI 26. The iPhone camera, Google Lens on iPhone and the dedicated readers tried read it. Turn it on where the readers are known to read it, an industrial scanner for example, or where the symbol has to be smaller.

property BoostEccLevel

public bool BoostEccLevel { get; set; }

Raise the error correction level above the requested one when the chosen version's capacity allows it, without changing the version. The requested level becomes the minimum. The version is still chosen for it, so boosting never produces a larger symbol, only spends padding that would otherwise be wasted. Recommended when an icon or custom module shape overlays the symbol.

Notes

Off by default: a raised level rewrites the format information and can change the chosen mask, so a default of on would silently change every existing symbol. Sizing is unaffected either way, the buffer size depends only on the version.

property Utf8Bom

public bool Utf8Bom { get; set; }

Include a UTF-8 byte order mark. Ignored unless the content is written as UTF-8 in Byte mode. Asking for one keeps text that AllowKanji would write in Kanji mode in UTF-8. When a BOM would be written, Optimal emits the single-mode stream instead of a split (the BOM is a stream-level prefix, and a split would relocate it into the middle of the decoded text).

property QuietZoneSize

public int QuietZoneSize { get; set; }

Quiet zone width in modules. Defaults to 4, the ISO/IEC 18004 value, and 0 is valid.

property MaskPattern

public int? MaskPattern { get; set; }

Pin one of the eight ISO/IEC 18004 data mask patterns (0-7) instead of the automatic penalty-scored selection. null (the default) selects the lowest-penalty pattern. Any pattern yields a valid, decodable symbol. The automatic choice merely optimizes scan reliability.

Notes

For reproducing a symbol produced elsewhere byte-for-byte (the pattern another encoder chose is reported by MaskPattern ), and for exercising a decoder against all eight patterns. Like Version , an invalid value is an argument error and is rejected here rather than when a generator reads it.

property Default

public static QRCodeGeneratorOptions Default { get; }

The default configuration, identical to default.

#enum QREccLevel

public enum QREccLevel : int

The error correction level: how much of a symbol can be damaged, dirty or covered while the code still scans. Higher levels leave less room for content, so the same text may need a larger symbol.

L = 0,

7% may be lost before recovery is not possible

M = 1,

15% may be lost before recovery is not possible

Q = 2,

25% may be lost before recovery is not possible

H = 3,

30% may be lost before recovery is not possible

#enum QRSegmentation

public enum QRSegmentation : int

How QRCodeGenerator splits the content into encoding-mode segments. Mixed content (for example a URL prefix followed by a long numeric identifier) packs into fewer bits when each run is encoded in its densest mode, which can drop the symbol by one or more versions.

Optimal = 0,

The default: the mixed-mode split with the fewest total bits. Text JIS X 0208 holds apart from its ASCII characters can be written as Kanji runs beside runs of that ASCII, with no ECI header, when AllowKanji is set, the charset is left to the library and that is the smaller symbol. Never selects a larger version than Single , emits the Single bit stream verbatim when a split would not shrink the symbol, and additionally encodes content that overflows every version in a single mode. A U+FEFF inside UTF-8 content never opens a Byte run, where a reader would drop it as a byte order mark: the run opens a character early and keeps it interior.

Notes

The search prices candidate versions; it allocates nothing for typical content and rents pooled buffers for long content. Single skips it. When Utf8Bom would actually write a byte order mark (a UTF-8 Byte-mode stream), the split is disabled and the Single stream is emitted: the BOM is a stream-level prefix, and a split would relocate it into the middle of the decoded text. Content whose single mode is Numeric or Alphanumeric never carries a BOM and still splits. Size buffers with the same segmentation you encode with, the two can select different versions.

Single = 1,

One segment in the single mode that can represent the whole content (Numeric, else Alphanumeric, else Byte, or Kanji for text JIS X 0208 holds entirely when AllowKanji is set and the charset is left to the library). The cheapest to encode: one pass over the content and no version search, and the bit stream every release before 2.0.0 emitted.

#struct QRStructuredAppend

public readonly struct QRStructuredAppend : IEquatable<QRStructuredAppend>

The Structured Append header a Standard QR symbol carries when it is one of a set of up to sixteen symbols that together hold one message (ISO/IEC 18004 Structured Append). Micro QR and rMQR do not define it.

Notes

Each symbol of a set decodes on its own and yields its own part of the text, and the header says where that part goes. To reassemble a set: every symbol must report the same Count and the same Parity , the indices 0 to Count - 1 must each be present exactly once, and the parts are concatenated in Index order. A part is text, so this holds for sets whose encoder cut the message between characters, as QRCodeGenerator.CreateStructuredAppend does. An encoder that cuts the byte stream inside a multi-byte character leaves U+FFFD at the edges of the two parts when its symbols declare UTF-8, and when they declare no charset the Byte segment on each side of the cut, no longer valid UTF-8, is read as ISO-8859-1, which is how such a set shows itself. Parity identifies the set, not the content. It is the XOR of the bytes of the whole message as the encoder wrote them, in whatever charset the set carries (Shift_JIS for a set written in Kanji mode), so a reader can tell that two symbols belong to different sets. It is not a checksum a caller can recompute from the reassembled text. Reported only when the decode succeeded. A symbol with no header, or a failed decode, leaves the value at its default, which IsEmpty reports.

property IsEmpty

public bool IsEmpty { get; }

true when the symbol carried no Structured Append header, or the decode did not succeed.

property Parity

public byte Parity { get; }

The set's parity byte, the same on every symbol of one set.

property Count

public int Count { get; }

How many symbols the set has, 1 to 16.

property Index

public int Index { get; }

This symbol's position in the set, 0-based, as on the wire. Less than Count whenever the value is not empty. Both are 0 on the empty value.

#struct QRVersionRange

public readonly struct QRVersionRange : IEquatable<QRVersionRange>

The Standard QR versions a generator may choose from: the smallest one in the range that holds the content is used. A fixed version is Exactly , the degenerate case, rather than a separate setting.

Notes

Both bounds are inclusive, unlike Range whose end is exclusive. That is why 1..40 is not usable here: it would read as 1 to 40 and mean 1 to 39.

constant MaxVersion

public const int MaxVersion;

The highest version defined by ISO/IEC 18004.

constant MinVersion

public const int MinVersion;

The lowest version defined by ISO/IEC 18004.

constructor QRVersionRange

public QRVersionRange(int min, int max);

An inclusive range from min to max .

property IsAny

public bool IsAny { get; }

Whether this range constrains nothing (the default).

property IsExact

public bool IsExact { get; }

Whether this range pins a single version.

property Max

public int Max { get; }

The highest permitted version (40 when unbounded above).

property Min

public int Min { get; }

The lowest permitted version (1 when unbounded below).

property Any

public static QRVersionRange Any { get; }

Every version, 1 to 40. Identical to default.

method Contains

public bool Contains(int version);

Whether version falls inside this range.

method ToString

public override string ToString();

method AtLeast

public static QRVersionRange AtLeast(int version);

version or larger.

method AtMost

public static QRVersionRange AtMost(int version);

version or smaller.

method Between

public static QRVersionRange Between(int min, int max);

An inclusive range from min to max .

method Exactly

public static QRVersionRange Exactly(int version);

Exactly version , with no automatic selection.

operator op_Implicit

public static QRVersionRange op_Implicit(int version);

A single version, as Exactly . Lets an option set read Version = 15.

operator op_Implicit

public static QRVersionRange op_Implicit(int? version);

A single version, or Any when there is none.

Notes

Lets a caller whose version is optional pass it through without branching. -1 is not accepted as a second spelling of Any : a mistyped or defaulted value must fail rather than silently produce an automatically sized symbol.

#struct RmQRCodeCalculatedSize

public readonly struct RmQRCodeCalculatedSize : IEquatable<RmQRCodeCalculatedSize>

Result of TryGetRequiredBufferSize : the byte count of the byte-per-module matrix, its dimensions (quiet zone included) and the version that will be used.

property Version

public RmQRVersion Version { get; }

The rMQR version that will be generated (requested or automatically selected).

property BufferSize

public int BufferSize { get; }

Required destination size in bytes ( Width Γ— Height ).

property Height

public int Height { get; }

Matrix height in modules, quiet zone included.

property Width

public int Width { get; }

Matrix width in modules, quiet zone included.

#class RmQRCodeData

public sealed class RmQRCodeData

An rMQR code as a module matrix, ready to render, serialize or decode.

Notes

The matrix is bit-packed and rectangular, 7 to 17 modules high and 27 to 139 wide depending on version, plus the quiet zone. Serialization writes a "QRX" header carrying the symbology and dimensions, then the packed modules.

constructor RmQRCodeData

public RmQRCodeData(ReadOnlySpan<byte> rawData, int quietZoneSize);

constructor RmQRCodeData

public RmQRCodeData(RmQRVersion version, int quietZoneSize);

Creates an empty matrix sized for the given version.

constructor RmQRCodeData

public RmQRCodeData(byte[] rawData, int quietZoneSize);

Restores an rMQR code from bytes written by GetRawData .

Notes

The serialized form is a "QRX" header (3 bytes), the symbology (1 byte), the width and height (1 byte each), then the bit-packed modules. It holds the core modules only, so the quiet zone is chosen again here and need not match the one the code was serialized with.

property Version

public RmQRVersion Version { get; }

The rMQR code version.

indexer this[int row, int col]

public bool this[int row, int col] { get; }

The module at the given position.

Notes

Quiet zone positions always read false: the quiet zone is light by definition and is not stored.

property Height

public int Height { get; }

Height in modules, quiet zone included.

property Width

public int Width { get; }

Width in modules, quiet zone included.

method GetModuleRectangles

public ModuleRect[] GetModuleRectangles();

The dark modules as merged rectangles, for drawing the rMQR code with any graphics API: SVG paths, draw calls, vector output.

Notes

Coordinates match the indexer: one unit is one module, the origin is the top-left corner including the quiet zone, X is the column and Y the row. Scale by the pixel size of one module. Width and Height give the total extent in modules. The three guarantees above are contractual, but the shape and order of the decomposition are not, and may change between versions. Currently they are maximal horizontal runs in row-major order, the same merge the built-in renderer draws for an unstyled symbol. A styled one draws its finder patterns as whole patterns instead.

method TryGetModuleRectangles

public bool TryGetModuleRectangles(Span<ModuleRect> destination, out int written);

Writes the rectangles of GetModuleRectangles into the buffer you provide, without allocating.

method GetRawData

public byte[] GetRawData();

Serializes the rMQR code so it can be stored, sent or cached.

Notes

Writes a "QRX" header (3 bytes), the symbology (1 byte), the width and height (1 byte each), then the bit-packed modules. The quiet zone is not written, so pick its width again when restoring.

method GetModuleRectanglesMaxCount

public int GetModuleRectanglesMaxCount();

Gets an upper bound on the number of rectangles GetModuleRectangles can return, suitable for sizing a pooled buffer for TryGetModuleRectangles . O(1), no matrix scan.

method GetRawData

public int GetRawData(IBufferWriter<byte> writer);

Serializes the rMQR code into a buffer writer, without allocating a byte array.

method GetRawDataSize

public int GetRawDataSize();

How many bytes GetRawData produces for this rMQR code.

#struct RmQRCodeDecodeInfo

public readonly struct RmQRCodeDecodeInfo : IEquatable<RmQRCodeDecodeInfo>

Diagnostic information from an rMQR decode attempt ( RmQRCodeDecoder ): status, and when the format information could be read, the version and ECC level plus the number of Reed-Solomon codeword corrections applied, and on success the FNC1 mode when the symbol carries one. rMQR has a single data mask, so there is no mask pattern to report, and it does not define Structured Append.

property Status

public DecodeStatus Status { get; }

Decode outcome. Success when text was produced.

property Fnc1

public Fnc1Mode Fnc1 { get; }

The FNC1 mode, when the symbol carries one (GS1 data, or an industry format with its application indicator). See Fnc1Mode . default, neither position, for a symbol that carries none or a failed decode.

property EccLevel

public RmQREccLevel EccLevel { get; }

The ECC level read from the format information (valid once the format decoded).

property Version

public RmQRVersion Version { get; }

The symbol version (from the physical dimensions), or 0 when the input is not an rMQR matrix.

property Corners

public SymbolCorners Corners { get; }

Where the symbol sits in the image, when decoded from one. See SymbolCorners . Empty for a matrix-level decode or a failed one.

property ErrorsCorrected

public int ErrorsCorrected { get; }

Total Reed-Solomon codeword corrections across all blocks (0 for a clean symbol).

#class RmQRCodeDecoder

public static class RmQRCodeDecoder

Decodes an rMQR code (ISO/IEC 23941) back into text, correcting errors as it goes.

Notes

Reads Numeric, Alphanumeric, Byte and Kanji mode across all 32 versions and both error correction levels. A Byte segment is read as its ECI header declares, for ISO-8859-1, UTF-8 and Shift_JIS. With no ECI header it is read as UTF-8 when the bytes are valid UTF-8, as Shift_JIS when they are well formed Shift_JIS that ISO-8859-1 text would not hold and hold no C0 control character but tab, CR, LF and, under FNC1, the separator 0x1D, and as ISO-8859-1 otherwise. Kanji is mapped through JIS X 0208, so a cell outside that repertoire fails the whole rMQR code with UnmappedCharacter rather than substituting a replacement character. Reed-Solomon runs at full block strength, correcting up to ⌊ecc/2βŒ‹ codewords per block, and reports the count in ErrorsCorrected . FNC1 in first position (GS1 data) and in second position (an industry format with its application indicator) are read: the text is the data with each separator as U+001D, the element string in first position, a %% in an Alphanumeric segment is one %, and the mode is reported on Fnc1 . Both a plain matrix and one with a quiet zone are accepted. The border is located and stripped automatically. Image scanning is a separate entry point, and QRCodeDecoder keeps scanning Standard QR only.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int width, int height, Span<char> destination, out int charsWritten, out RmQRCodeDecodeInfo info);

Decodes the text into the buffer you provide, without allocating.

method TryDecode

public static bool TryDecode(ReadOnlySpan<byte> modules, int width, int height, out string text, out RmQRCodeDecodeInfo info);

Decodes the text from a module matrix.

method TryDecode

public static bool TryDecode(RmQRCodeData data, out string text);

Decodes the text from an rMQR code.

method TryDecode

public static bool TryDecode(RmQRCodeData data, out string text, out RmQRCodeDecodeInfo info);

Decodes the text from an rMQR code and reports what it found.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, Span<char> destination, out int charsWritten, out RmQRCodeDecodeInfo info);

Finds and decodes an rMQR code in a grayscale image, writing into the buffer you provide without allocating.

method TryDecodeImage

public static bool TryDecodeImage(ReadOnlySpan<byte> luminance, int width, int height, out string text, out RmQRCodeDecodeInfo info);

Finds and decodes an rMQR code in a grayscale image.

method GetMaxDecodedLength

public static int GetMaxDecodedLength(RmQRVersion version);

The most characters an rMQR code of this version can decode to, across every error correction level and mode. Use it to size the destination of the allocation-free overloads.

#class RmQRCodeGenerator

public static class RmQRCodeGenerator

Encodes text into a rectangular rMQR code (ISO/IEC 23941), versions R7x43 to R17x139.

Notes

Pick a version outright, or let RmQRFitStrategy choose among those that hold the content, optionally within one height. The default MinimizeArea takes the fewest modules, which can mean a taller and narrower code: 12 digits at level M give R11x27 (297 modules) rather than R7x43 (301). Use MinimizeHeight or a fixed RmQRHeight when you want the flattest code instead. Writes Numeric, Alphanumeric and Byte mode, the last with ECI assignment 3 for ISO-8859-1 or 26 for UTF-8, and Kanji mode. Kanji mode carries text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) at 13 bits a character with no ECI header. It is written only when the caller sets AllowKanji and the charset is left at Default . Under Optimal such text with ASCII in it can be written as Kanji runs beside Numeric, Alphanumeric and Byte runs of the ASCII, where that is the smaller symbol. The quiet zone defaults to the 2 modules ISO/IEC 23941 asks for.

method Create

public static RmQRCodeData Create(ReadOnlySpan<char> textSpan, RmQREccLevel eccLevel, in RmQRCodeGeneratorOptions options = null);

Encodes text into an rMQR code.

method TryGetRequiredBufferSize

public static bool TryGetRequiredBufferSize(ReadOnlySpan<char> text, RmQREccLevel eccLevel, out RmQRCodeCalculatedSize size, in RmQRCodeGeneratorOptions options = null);

Reports how large the rMQR code will be, or false when the content does not fit.

Notes

false means that and only that. Bad arguments still throw. rMQR holds 5 to 150 bytes, so not fitting is an ordinary answer here, which is why sizing is only offered in this form. Pass the options you will encode with, since segmentation and ECI can pick different versions and a buffer sized for one can be too small for the other.

method Create

public static int Create(ReadOnlySpan<char> textSpan, RmQREccLevel eccLevel, Span<byte> destination, in RmQRCodeGeneratorOptions options = null);

Encodes text into the buffer you provide, without allocating.

Notes

One byte per module, 0 light and 1 dark, row-major over the full width with the quiet zone included, so the module at (row, col) is destination[row * width + col].

#struct RmQRCodeGeneratorOptions

public struct RmQRCodeGeneratorOptions : IEquatable<RmQRCodeGeneratorOptions>

Optional settings for RmQRCodeGenerator . default is the complete default configuration and is what an omitted argument sends, so the shortest correct call is Create(text, eccLevel).

Notes

rMQR specific rather than shared: Version is a different type in each symbology, QuietZoneSize has a different specified default, and FitStrategy , Height and Segmentation have no meaning outside rMQR. Fnc1 is the same type as Standard QR's, with rMQR's costs. There is no version range here because rMQR's 32 versions are not totally ordered. Fit is constrained by strategy and height instead. A plain value a caller may assign to and copy with with, for the reasons on QRCodeGeneratorOptions .

property EciMode

public EciMode EciMode { get; set; }

Character encoding declaration. The default auto-detects ASCII (no ECI), ISO-8859-1 (assignment 3) or UTF-8 (assignment 26) from the content, and with AllowKanji Kanji mode (no ECI) for text JIS X 0208 holds.

Notes

Only Default , Iso8859_1 and Utf8 are accepted. Declaring Latin-1 over content it cannot represent throws rather than silently re-encoding.

property Fnc1

public Fnc1Mode Fnc1 { get; set; }

The FNC1 mode to write (ISO/IEC 23941 7.4.8, as ISO/IEC 18004:2006 6.4.8): FirstPosition for GS1 data, or second position with an application indicator for an industry format registered with AIM. Defaults to None .

Notes

The content is the data as a reader returns it, with U+001D as the separator and without a symbology identifier or the application indicator. In first position it is a GS1 element string, with the separator after each variable-length value another follows. The indicator is written after any ECI header and before the data, and in an Alphanumeric segment the separator is written as % and a literal % as %%, so the content reads back as given. A separator followed by a separator or a literal % cannot share an Alphanumeric segment, since a reader takes the %% first: such content takes Byte mode under Single , and Optimal breaks the run or uses Byte mode, whichever is smaller. The mode costs 3 bits in first position and 11 in second (the 3-bit indicator and the 8-bit application indicator), which can move content at a version's edge to another version under the fit strategy, or out of a requested version. Size a destination buffer with the same value you encode with. Whether the data is valid GS1 data is not checked here. The FeatherQR.Gs1 package checks element strings and builds them from (AI) text. Few readers read rMQR at all. Of those, zxing-cpp reads both modes, and no other writer is known to write second position in rMQR.

property FitStrategy

public RmQRFitStrategy FitStrategy { get; set; }

How to choose among the versions that hold the content. Defaults to MinimizeArea , the choice both reference encoders make.

property Height

public RmQRHeight? Height { get; set; }

Restrict automatic fitting to one symbol height, or null (the default) to consider every height. Must agree with Version when both are set.

property Segmentation

public RmQRSegmentation Segmentation { get; set; }

Whether to split the content into mixed-mode segments. Defaults to Optimal . Size a destination buffer with the same value you encode with: the two modes can select different versions.

property Version

public RmQRVersion? Version { get; set; }

A specific version, or null (the default) to fit one automatically by FitStrategy and Height .

property AllowKanji

public bool AllowKanji { get; set; }

Write text in Kanji mode where it can be: 13 bits a character and no ECI header, where UTF-8 takes 24 bits a kana or kanji behind an 11-bit ECI header. Off by default.

Notes

Applies only where the charset is the library's choice ( Default ). A charset the caller names is written as named. Then text whose every character is in JIS X 0208 (Japanese, and the Greek, Cyrillic and symbols that table holds) is one Kanji segment, and under Optimal text that is so apart from its ASCII can be Kanji runs beside runs of that ASCII, where that is the smaller symbol. Seven JIS X 0208 characters that Windows code page 932 reads differently, among them the wave dash γ€œ, keep a text in UTF-8, as does any character outside the table. The capacity can matter more than in Standard QR: R7x43-M holds 3 characters in Kanji mode and 1 in UTF-8. Off by default, as on the other two symbologies, because not every reader reads Kanji mode: in Standard QR an Android 17 phone's own QR scanner and Google Lens on it show nothing readable for it. Neither phone's own scanner reads rMQR at all. The dedicated readers tried read it in Kanji mode and in UTF-8 alike.

property QuietZoneSize

public int QuietZoneSize { get; set; }

Quiet zone width in modules. Defaults to 2, the ISO/IEC 23941 value, and 0 is valid.

property Default

public static RmQRCodeGeneratorOptions Default { get; }

The default configuration, identical to default.

#enum RmQREccLevel

public enum RmQREccLevel : int

rMQR Code error correction level (ISO/IEC 23941). rMQR defines only two levels. The numeric value is the ECC bit carried in the format information.

M = 0,

Medium: about 15% of codewords recoverable.

H = 1,

High: about 30% of codewords recoverable.

#enum RmQRFitStrategy

public enum RmQRFitStrategy : int

How RmQRCodeGenerator chooses among the rMQR versions that can hold the content when no exact version is requested. rMQR sizes are two-dimensional, so "smallest" is a policy: fewest modules, narrowest, or shortest.

MinimizeArea = 0,

Fewest modules (height Γ— width). Ties prefer the smaller height, i.e. the wider symbol. The default.

MinimizeWidth = 1,

Smallest width. Ties prefer the smaller height.

MinimizeHeight = 2,

Smallest height. Ties prefer the smaller width.

#enum RmQRHeight

public enum RmQRHeight : int

Fixed rMQR symbol height in modules for automatic width selection ("fixed height, automatic width"): the generator only considers the versions of this height and picks among them by RmQRFitStrategy . Values are the module heights themselves.

H7 = 7,

7 modules high (widths 43-139).

H9 = 9,

9 modules high (widths 43-139).

H11 = 11,

11 modules high (widths 27-139).

H13 = 13,

13 modules high (widths 27-139).

H15 = 15,

15 modules high (widths 43-139).

H17 = 17,

17 modules high (widths 43-139).

#enum RmQRSegmentation

public enum RmQRSegmentation : int

How RmQRCodeGenerator splits the content into encoding-mode segments. rMQR capacities are small, so mixing modes (for example a Byte prefix followed by a Numeric tail) can drop the symbol by one or more versions.

Optimal = 0,

The default: the mixed-mode split with the fewest total bits. Text JIS X 0208 holds apart from its ASCII characters can be written as Kanji runs beside runs of that ASCII, with no ECI header, when AllowKanji is set, the charset is left to the library and that is the smaller symbol. Never selects a symbol with more core modules than Single , emits the Single bit stream verbatim when a split would not shrink it, and additionally encodes content that overflows every version in a single mode. A U+FEFF inside UTF-8 content never opens a Byte run, where a reader would drop it as a byte order mark: the run opens a character early and keeps it interior.

Notes

The search prices candidate versions; it allocates nothing, and content no split can help is ruled out before it starts. Single skips it. Fewer core modules is not the same as a smaller image: RmQRFitStrategy ranks by core modules while the quiet zone adds to each dimension, so a flatter symbol can render onto a larger grid. Size buffers with the same segmentation you encode with.

Single = 1,

One segment in the single mode that can represent the whole content (Numeric, else Alphanumeric, else Byte, or Kanji for text JIS X 0208 holds entirely when AllowKanji is set and the charset is left to the library). The cheapest to encode: one pass over the content and no version search, and the bit stream every release before 2.0.0 emitted.

#enum RmQRVersion

public enum RmQRVersion : int

rMQR Code symbol version (ISO/IEC 23941): 32 rectangular sizes named R{height}x{width}. Values follow the ISO version index (height-major order) plus one, so (int)version - 1 is the 5-bit version index carried in the format information.

R7x43 = 1,

7 Γ— 43 modules.

R7x59 = 2,

7 Γ— 59 modules.

R7x77 = 3,

7 Γ— 77 modules.

R7x99 = 4,

7 Γ— 99 modules.

R7x139 = 5,

7 Γ— 139 modules.

R9x43 = 6,

9 Γ— 43 modules.

R9x59 = 7,

9 Γ— 59 modules.

R9x77 = 8,

9 Γ— 77 modules.

R9x99 = 9,

9 Γ— 99 modules.

R9x139 = 10,

9 Γ— 139 modules.

R11x27 = 11,

11 Γ— 27 modules.

R11x43 = 12,

11 Γ— 43 modules.

R11x59 = 13,

11 Γ— 59 modules.

R11x77 = 14,

11 Γ— 77 modules.

R11x99 = 15,

11 Γ— 99 modules.

R11x139 = 16,

11 Γ— 139 modules.

R13x27 = 17,

13 Γ— 27 modules.

R13x43 = 18,

13 Γ— 43 modules.

R13x59 = 19,

13 Γ— 59 modules.

R13x77 = 20,

13 Γ— 77 modules.

R13x99 = 21,

13 Γ— 99 modules.

R13x139 = 22,

13 Γ— 139 modules.

R15x43 = 23,

15 Γ— 43 modules.

R15x59 = 24,

15 Γ— 59 modules.

R15x77 = 25,

15 Γ— 77 modules.

R15x99 = 26,

15 Γ— 99 modules.

R15x139 = 27,

15 Γ— 139 modules.

R17x43 = 28,

17 Γ— 43 modules.

R17x59 = 29,

17 Γ— 59 modules.

R17x77 = 30,

17 Γ— 77 modules.

R17x99 = 31,

17 Γ— 99 modules.

R17x139 = 32,

17 Γ— 139 modules.

#struct SymbolCorners

public readonly struct SymbolCorners : IEquatable<SymbolCorners>

Where a decoded symbol sits in the image: the four outer corners of its module area, quiet zone excluded, in the input image's continuous pixel coordinates (see ImagePoint ).

Notes

The corners are named in the symbol's own frame, not the image's: TopLeft is the corner beside the finder pattern that defines the symbol's top-left, wherever it landed in the picture. A rotated capture therefore reports rotated corners, and a mirrored capture reports them in reversed winding: seen on screen (y down), the corners of a symbol as printed run clockwise, and those of a mirrored capture run counter-clockwise. The four points form a general quadrilateral under perspective. They are estimates, and how tight depends on how much the decoder had to infer. At 8 pixels per module or more: Standard QR, fitted on three finders and an alignment pattern, holds every corner within half a module, flat, rotated, mirrored or keystoned. Micro QR and rMQR fit from a single finder and match that only flat and at right angles. An oblique rotation takes whichever axis angle still decodes and a keystone comes from a bounded search, so their far corners can be off by about a module, or about two modules on an rMQR symbol foreshortened by 2 % or more. Two things loosen those figures. Below 8 pixels per module, read the bound in pixels: the corners are anchored on pattern centres that resolve to about a pixel at any module size, so the error stays near four pixels while the module shrinks under it (about 0.9 module at 3 pixels per module, on every symbology). And a Standard QR symbol whose bottom-right alignment pattern was not located (version 1 has none, and elsewhere a smudge over one module loses it) is fitted on the finders alone and held to about a module and a half, at any density. Error correction still reports Success , and nothing here says which fit ran. Populated only when the decode succeeded from an image. A matrix-level decode has no image and a failed image decode located nothing worth reporting. Both leave the value at its default, which IsEmpty reports.

property BottomLeft

public ImagePoint BottomLeft { get; }

The corner at the symbol's bottom-left.

property BottomRight

public ImagePoint BottomRight { get; }

The corner at the symbol's bottom-right.

property TopLeft

public ImagePoint TopLeft { get; }

The corner beside the symbol's top-left finder pattern.

property TopRight

public ImagePoint TopRight { get; }

The corner at the symbol's top-right.

property IsEmpty

public bool IsEmpty { get; }

true when no corners were reported: the decode did not succeed, or it ran on a module matrix rather than an image.

namespace FeatherQR.Gs1

#struct Gs1Element

public readonly ref struct Gs1Element

One element of an element string as spans into it: the AI, its value and the AI's offset. The AI is 2 to 4 digits, the value excludes the separator.

property Ai

public ReadOnlySpan<char> Ai { get; }

The application identifier, 2 to 4 digits.

property Value

public ReadOnlySpan<char> Value { get; }

The value, without the separator that may follow it.

property Offset

public int Offset { get; }

Where the AI starts in the element string.

#struct Gs1ElementEnumerator

public ref struct Gs1ElementEnumerator

Enumerates the elements of an element string without allocating, usable in foreach. It splits as a reader does ( EnumerateElements ): an AI of predefined length takes its length, any other value runs to the next separator, an unknown AI with a known length is read, a redundant or trailing separator is skipped, and the enumeration stops at the first element it cannot split. TryValidate says why.

property Current

public Gs1Element Current { get; }

The element last read by MoveNext .

method GetEnumerator

public Gs1ElementEnumerator GetEnumerator();

Returns this enumerator, for foreach.

method MoveNext

public bool MoveNext();

Advances to the next element: false at the end of the text, and at the first element that cannot be split.

#class Gs1ElementString

public static class Gs1ElementString

Conversions between a GS1 element string (AI values with the group separator U+001D after each variable-length value another follows), its (AI) text and a GS1 Digital Link URI, and the checks the GS1 General Specifications define on the data. Every member takes a ReadOnlySpan of Char , so a String converts without an overload, and none throws for its input.

Notes

The checks follow the GS1 Barcode Syntax Dictionary release named by the table in this package (the AI formats, the linters, the requisite and exclusive pairings), which is generated from the dictionary file and updated once a year. Reading members accept an AI newer than the table, since the tables that give an AI's length from its first two digits and the predefined lengths are frozen by the General Specifications (7.8.2, 7.8.3): its value takes the predefined length when its first two digits have one and runs to the next separator otherwise. A two-digit year resolves to the century that puts it within -49 to +50 years of the current year (General Specifications 7.12), so whether 29 February of a two-digit year exists depends on when the check runs. In 2026, 00 to 76 read as 2000 to 2076 and 77 to 99 as 1977 to 1999. The window moves up by one each year, and from 2050 the year 00 reads as 2100.

property DictionaryRelease

public static string DictionaryRelease { get; }

The release of the GS1 Barcode Syntax Dictionary this library's table was generated from, as the dictionary names it (2026-01-27). An AI assigned after that release is read as data but not checked or built, so UnknownAi from a building member means an AI newer than this release or a typo.

method EnumerateElements

public static Gs1ElementEnumerator EnumerateElements(ReadOnlySpan<char> elementString);

Splits an element string into its elements without allocating: foreach (var element in Gs1ElementString.EnumerateElements(text)). Runs what splitting needs and no more: an AI of predefined length (Table 7-6, known to the table or not) takes its length and any other value runs to the next separator, an unknown AI whose first two digits give its length is read, a redundant or trailing separator is skipped, and the enumeration stops at the first element it cannot split. TryValidate says why.

method TryFromDigitalLink

public static bool TryFromDigitalLink(ReadOnlySpan<char> uri, Span<char> destination, out int charsWritten, out Gs1Error error);

Reads the GS1 data out of a Digital Link URI into destination without allocating. TryGetFromDigitalLinkLength gives the length to reserve. See TryFromDigitalLink .

method TryFromDigitalLink

public static bool TryFromDigitalLink(ReadOnlySpan<char> uri, out string elementString, out Gs1Error error);

Reads the GS1 data out of a Digital Link URI with any stem: the primary key and its qualifiers from the end of the path, then the numeric query keys in URI order, percent-decoded. Runs what reading needs, the URI's structure: the scheme and host, the key qualifier order, that a numeric query key is an AI the table knows and a data attribute not already in the path, and that a value decodes. The values' own checks are TryValidate 's.

Notes

A query key that is not numeric (linkType, an extension) is ignored, an AI that appears twice in the URI is refused even with equal values, as the GS1 Syntax Engine refuses it, and a fragment is ignored. A compressed URI is refused with its own kind. The element string is never longer than the URI.

method TryFromHri

public static bool TryFromHri(ReadOnlySpan<char> hri, Span<char> destination, out int charsWritten, out Gs1Error error);

Builds the element string of (AI) text into destination without allocating. TryGetFromHriLength gives the length to reserve. See TryFromHri .

method TryFromHri

public static bool TryFromHri(ReadOnlySpan<char> hri, out string elementString, out Gs1Error error);

Builds the element string of (AI) text, (01)09520123456788(10)ABC: each AI in parentheses and its value after it, up to the next unescaped (, with a literal ( in a value written \( and a \ written \\ (a \ before any other character is itself). Runs every check TryValidate runs, and puts the separator after every value that needs one.

Notes

The text has nothing between its pairs and no blank after a closing parenthesis, so a space in a value is refused as an invalid character. The element string is never longer than the text.

method TryGetFromDigitalLinkLength

public static bool TryGetFromDigitalLinkLength(ReadOnlySpan<char> uri, out int length, out Gs1Error error);

The length of the element string TryFromDigitalLink would read from this URI, after the same reading.

method TryGetFromHriLength

public static bool TryGetFromHriLength(ReadOnlySpan<char> hri, out int length, out Gs1Error error);

The length of the element string TryFromHri would build, after the same checks.

method TryGetReadLength

public static bool TryGetReadLength(ReadOnlySpan<char> text, Fnc1Mode fnc1, out int length, out Gs1Error error);

The length of the (AI) text TryRead would give, after the same reading.

method TryGetToDigitalLinkLength

public static bool TryGetToDigitalLinkLength(ReadOnlySpan<char> elementString, out int length, out Gs1Error error, string? stem = null);

The length of the URI TryToDigitalLink would build for this element string and stem, after the same checks.

method TryGetToHriLength

public static bool TryGetToHriLength(ReadOnlySpan<char> elementString, out int length, out Gs1Error error);

The length of the (AI) text TryToHri would produce, after the same checks.

method TryRead

public static bool TryRead(ReadOnlySpan<char> text, Fnc1Mode fnc1, Span<char> destination, out int charsWritten, out Gs1Error error);

Reads what a decoder returned as GS1 data into destination without allocating. TryGetReadLength gives the length to reserve, and the text is never longer than twice the input. See TryRead .

method TryRead

public static bool TryRead(ReadOnlySpan<char> text, Fnc1Mode fnc1, out string hri, out Gs1Error error);

Reads what a decoder returned as GS1 data: with FNC1 in first position the text is an element string and comes back as (AI) text, as TryToHri gives it, otherwise the text is read as a Digital Link URI, as TryFromDigitalLink reads it, and its element string comes back as (AI) text. false when it is neither. The decode-side mirror of CreateGs1, independent of which decode entry point read the symbol.

method TryToDigitalLink

public static bool TryToDigitalLink(ReadOnlySpan<char> elementString, Span<char> destination, out int charsWritten, out Gs1Error error, string? stem = null);

Builds a GS1 Digital Link URI into destination without allocating. TryGetToDigitalLinkLength gives the length to reserve. See TryToDigitalLink .

method TryToDigitalLink

public static bool TryToDigitalLink(ReadOnlySpan<char> elementString, out string uri, out Gs1Error error, string? stem = null);

Builds a GS1 Digital Link URI (URI Syntax 1.7.0, uncompressed) from an element string: the primary key and its key qualifiers in the path, every other AI as a query parameter in the lexical order of the AIs, each AI once, reserved characters percent-encoded. With no stem the canonical https://id.gs1.org, so the result is the canonical form of section 4.12. Runs every check TryValidate runs, plus what a URI can carry: a primary key must be present and every AI outside the path must be a data attribute.

Notes

The first element whose AI is a primary key leads the path. Where the key has alternative qualifier sequences, the one that matches the most elements is used, preferring a sequence that leaves only data attributes for the query. The URI is never longer than the stem plus three times the element string plus two. A stem that is not an http or https URI prefix with a host and no query or fragment throws ArgumentException , as a malformed option does elsewhere. One trailing slash on it is dropped.

method TryToHri

public static bool TryToHri(ReadOnlySpan<char> elementString, Span<char> destination, out int charsWritten, out Gs1Error error);

Formats an element string as its (AI) text into destination without allocating. TryGetToHriLength gives the length to reserve. See TryToHri .

method TryToHri

public static bool TryToHri(ReadOnlySpan<char> elementString, out string hri, out Gs1Error error);

Formats an element string as its (AI) text, (01)09520123456788(10)ABC: each AI in parentheses and its value after it, a literal ( in a value written \( and a \ written \\. Runs what splitting needs and no more (an unknown AI whose first two digits give its length is read, a redundant or trailing separator is skipped), so a string TryValidate would refuse can still format.

Notes

The text is at most twice as long as the element string.

method TryValidate

public static bool TryValidate(ReadOnlySpan<char> elementString, out Gs1Error error);

Runs every check on an element string: AI lengths and character sets, check digits and check character pairs, dates and the other linters, requisite and exclusive pairings, repeated AIs. true with default error when it passes.

Notes

A separator after a predefined-length element and a trailing separator are tolerated, as the General Specifications ask of a processing routine (7.8.6.3). A separator at the start or two in a row are refused. The pairing rules are checked within this element string alone, although the General Specifications define them over every carrier on the item, so data split across symbols can be refused here.

#struct Gs1Error

public readonly struct Gs1Error : IEquatable<Gs1Error>

Why a conversion or check refused its input: the Kind , and where in the input ( Offset and Length , both 0 when the kind names no place). The default is None . ToString is the message the generator entry points put in their Gs1FormatException .

constructor Gs1Error

public Gs1Error(Gs1ErrorKind kind, int offset, int length);

Creates an error. offset and length are positions in the input the error is about, 0 where the kind names no place.

property Kind

public Gs1ErrorKind Kind { get; }

What was wrong.

property Length

public int Length { get; }

How many characters of the input it covers. 0 when the kind names no place or a missing thing.

property Offset

public int Offset { get; }

Where it starts in the input, in characters. 0 when the kind names no place.

method ToString

public override string ToString();

The kind, the place and a sentence, such as InvalidCheckDigit at 15 (1 character): the check digit is wrong.

#enum Gs1ErrorKind

public enum Gs1ErrorKind : int

The kinds of Gs1Error : why a conversion or check refused its input. Later releases may add members at the end.

None = 0,

No error. The default of Gs1Error .

DestinationTooSmall = 1,

The caller's destination span is shorter than the result. Nothing was written.

InvalidText = 2,

The text has no element where one must be: an empty input, or (AI) text that is malformed, with an unbalanced or empty parenthesis, a non-digit AI, or a stray character outside the elements.

NotAUri = 3,

The input is not an http or https URI with a path.

CompressedUri = 4,

The URI is a compressed GS1 Digital Link URI, which this library does not read.

InvalidPercentEncoding = 5,

A percent escape in the URI is not % and two hexadecimal digits, does not decode to UTF-8, or decodes to a control character.

UnexpectedSeparator = 6,

A separator (U+001D) where no value can end: at the start of the element string, or right after another separator.

UnknownAi = 7,

An AI the table does not know, where building refuses it, or digits that no AI of the General Specifications' length table can start.

AiNotAllowedInUri = 8,

An AI a GS1 Digital Link URI cannot carry: (03), (8014), (8200), or one the table does not flag as a data attribute.

MissingPrimaryKey = 9,

No primary key AI for the path of a GS1 Digital Link URI.

InvalidKeyQualifierSequence = 10,

The key qualifiers after the primary key are not in one of the orders the table allows, or a qualifier of that key is in the query instead of the path.

EmptyValue = 11,

An element with no value.

ValueTooShort = 12,

A value shorter than its AI's format requires.

ValueTooLong = 13,

A value longer than its AI's format allows.

InvalidCharacter = 14,

A character outside the character set of its component (digits, CSET 82, CSET 39 or CSET 64 with its padding rule).

InvalidCheckDigit = 15,

A wrong check digit or check character pair.

InvalidDate = 16,

A date or time component that no calendar or clock holds: month 13, day 31 of a short month, 29 February of a common year, hour 24.

InvalidValue = 17,

A value that another rule of its AI refuses: an ISO 3166 or 4217 code not in the list, a yes/no flag, a zero or non-zero rule, a coordinate out of range, an IBAN, a coupon field, a position in a sequence.

MissingRequiredAi = 18,

An AI the table says this AI requires on the same item is missing.

ExcludedAiPair = 19,

Two AIs the table says cannot appear together.

RepeatedAi = 20,

The same AI twice with different values in an element string, or twice at all in a Digital Link URI.

#class Gs1FormatException

public sealed class Gs1FormatException : FormatException

Thrown by the generator entry points (CreateGs1, CreateGs1DigitalLink) when the data is not valid GS1 data, or is data a Digital Link URI cannot carry. Nothing on Gs1ElementString throws for its input.

Notes

A FormatException , as UriFormatException is, so an existing catch (FormatException) still catches it. Error gives the kind and the place in the text the caller passed, and Message is that error's ToString . Data that is valid and too long for the symbol is not this exception: Create's own is thrown for it. The type is not serializable, so on .NET Framework it does not cross an application domain boundary.

constructor Gs1FormatException

public Gs1FormatException(Gs1Error error);

Creates the exception for an error of the data.

property Error

public Gs1Error Error { get; }

What was wrong, and where in the text the caller passed.

#class Gs1QRCodeGenerator

public static class Gs1QRCodeGenerator

GS1 entry points on QRCodeGenerator : CreateGs1 writes a GS1 QR Code, the data under FNC1 in first position, and CreateGs1DigitalLink a plain QR Code holding the data's GS1 Digital Link URI. With C# 14 they are reachable as QRCodeGenerator.CreateGs1(...). On older language versions call them on this class.

Notes

The text is (AI) text such as (01)09506000134352(17)201225(10)ABC123 or an element string, told apart by the first character: (AI) text starts with ( and an element string with a digit. Text that starts with anything else, such as a blank or a symbology identifier, is read as an element string and refused. Every check of TryValidate runs, pairings included, and data that fails is a Gs1FormatException whose Error names the place in the text passed. (AI) text gets its separators written where the General Specifications require one. An element string is written as given. Use CreateGs1DigitalLink for retail, where a phone opens the URI and a point of sale reads the GTIN out of it, and CreateGs1 elsewhere (healthcare, logistics), where a scanner expects GS1 data under FNC1. Leave EciMode at its default: GS1 data is ASCII and a GS1 QR Code carries no ECI header. A wrong option is reported as Create reports it, and before the data.

method CreateGs1

public static QRCodeData CreateGs1(ReadOnlySpan<char> text, QREccLevel eccLevel, in QRCodeGeneratorOptions options = null);

method CreateGs1DigitalLink

public static QRCodeData CreateGs1DigitalLink(ReadOnlySpan<char> text, QREccLevel eccLevel, in QRCodeGeneratorOptions options = null, string? stem = null);

method CreateGs1DigitalLink

public static QRCodeData CreateGs1DigitalLink(ReadOnlySpan<char> text, QREccLevel eccLevel, in QRCodeGeneratorOptions options);

method TryGetRequiredBufferSizeGs1

public static bool TryGetRequiredBufferSizeGs1(ReadOnlySpan<char> text, QREccLevel eccLevel, out QRCodeCalculatedSize size, in QRCodeGeneratorOptions options = null);

method TryGetRequiredBufferSizeGs1DigitalLink

public static bool TryGetRequiredBufferSizeGs1DigitalLink(ReadOnlySpan<char> text, QREccLevel eccLevel, out QRCodeCalculatedSize size, in QRCodeGeneratorOptions options = null, string? stem = null);

method CreateGs1

public static int CreateGs1(ReadOnlySpan<char> text, QREccLevel eccLevel, Span<byte> destination, in QRCodeGeneratorOptions options = null);

method CreateGs1DigitalLink

public static int CreateGs1DigitalLink(ReadOnlySpan<char> text, QREccLevel eccLevel, Span<byte> destination, in QRCodeGeneratorOptions options = null, string? stem = null);

#class Gs1RmQRCodeGenerator

public static class Gs1RmQRCodeGenerator

GS1 entry points on RmQRCodeGenerator : CreateGs1 writes the data under FNC1 in first position into an rMQR code, and CreateGs1DigitalLink the data's GS1 Digital Link URI as plain text. With C# 14 they are reachable as RmQRCodeGenerator.CreateGs1(...). On older language versions call them on this class.

Notes

The text is (AI) text such as (01)09506000134352(17)201225(10)ABC123 or an element string, told apart by the first character: (AI) text starts with ( and an element string with a digit. Text that starts with anything else, such as a blank or a symbology identifier, is read as an element string and refused. Every check of TryValidate runs, pairings included, and data that fails is a Gs1FormatException whose Error names the place in the text passed. (AI) text gets its separators written where the General Specifications require one. An element string is written as given. GS1 does not list rMQR among its carriers (General Specifications Release 26.0), so a scanner set up for GS1 symbols may not accept one. Readers that read rMQR report this data as they report a GS1 QR Code's. Leave EciMode at its default: GS1 data is ASCII and needs no ECI header. A wrong option is reported as Create reports it, and before the data.

method CreateGs1

public static RmQRCodeData CreateGs1(ReadOnlySpan<char> text, RmQREccLevel eccLevel, in RmQRCodeGeneratorOptions options = null);

method CreateGs1DigitalLink

public static RmQRCodeData CreateGs1DigitalLink(ReadOnlySpan<char> text, RmQREccLevel eccLevel, in RmQRCodeGeneratorOptions options = null, string? stem = null);

method CreateGs1DigitalLink

public static RmQRCodeData CreateGs1DigitalLink(ReadOnlySpan<char> text, RmQREccLevel eccLevel, in RmQRCodeGeneratorOptions options);

method TryGetRequiredBufferSizeGs1

public static bool TryGetRequiredBufferSizeGs1(ReadOnlySpan<char> text, RmQREccLevel eccLevel, out RmQRCodeCalculatedSize size, in RmQRCodeGeneratorOptions options = null);

method TryGetRequiredBufferSizeGs1DigitalLink

public static bool TryGetRequiredBufferSizeGs1DigitalLink(ReadOnlySpan<char> text, RmQREccLevel eccLevel, out RmQRCodeCalculatedSize size, in RmQRCodeGeneratorOptions options = null, string? stem = null);

method CreateGs1

public static int CreateGs1(ReadOnlySpan<char> text, RmQREccLevel eccLevel, Span<byte> destination, in RmQRCodeGeneratorOptions options = null);

method CreateGs1DigitalLink

public static int CreateGs1DigitalLink(ReadOnlySpan<char> text, RmQREccLevel eccLevel, Span<byte> destination, in RmQRCodeGeneratorOptions options = null, string? stem = null);

namespace FeatherQR.SkiaSharp

#class CircleFinderPatternShape

public sealed class CircleFinderPatternShape : FinderPatternShape

Three nested ovals, circles on a square area.

field Default

public static readonly CircleFinderPatternShape Default;

A ready-made instance to use as-is.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

On, so the curves do not come out jagged.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class CircleModuleShape

public sealed class CircleModuleShape : ModuleShape

Draws modules as circles.

field Default

public static readonly CircleModuleShape Default;

A ready-made instance to use as-is.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

On, so the curves do not come out jagged.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class FinderPatternShape

public abstract class FinderPatternShape

How the finder patterns, the large squares in the corners, are drawn: three of them on Standard QR, one on Micro QR and rMQR.

Notes

A shape draws the dark modules only. The light ring between them is left undrawn, so whatever the renderer put beneath the finder pattern, the background at any alpha, shows through it: nothing is painted over and nothing is erased, which is what lets raster and SVG output carry the same drawing. The ring has to survive as a continuous light run: a reader locates the symbol by scanning for the finder pattern's 1:1:3:1:1 run of dark and light, so a shape that fills it, a plain DrawRect over the whole area included, renders a symbol nothing can scan.

constructor FinderPatternShape

protected FinderPatternShape();

property RequiresAntialiasing

public abstract bool RequiresAntialiasing { get; }

Whether the shape needs antialiasing. It decides the finder pattern's antialiasing on its own, so false turns antialiasing off even where the module shape asked for it. Return true for curves, false for straight edges.

method Draw

public abstract void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

Draws the dark modules of a finder pattern. The light ring is left undrawn.

#enum GradientDirection

public enum GradientDirection : int

Defines the direction of gradient flow for symbol rendering.

Notes

Linear gradients flow in a straight line across the entire symbol area. The direction determines the start and end points of the gradient. Common Use Cases: LeftToRight or TopToBottom : Simple horizontal/vertical gradients TopLeftToBottomRight : Diagonal gradients for dynamic appearance None : Use when solid color is desired (disables gradient)

None = 0,

No gradient. Use solid color specified in symbol rendering options. However, if solid is required, it's better to omit gradient options entirely.

LeftToRight = 1,

Gradient flows from left edge to right edge horizontally.

RightToLeft = 2,

Gradient flows from right edge to left edge horizontally.

TopToBottom = 3,

Gradient flows from top edge to bottom edge vertically.

BottomToTop = 4,

Gradient flows from bottom edge to top edge vertically.

TopLeftToBottomRight = 5,

Gradient flows diagonally from top-left corner to bottom-right corner.

TopRightToBottomLeft = 6,

Gradient flows diagonally from top-right corner to bottom-left corner.

BottomLeftToTopRight = 7,

Gradient flows diagonally from bottom-left corner to top-right corner.

BottomRightToTopLeft = 8,

Gradient flows diagonally from bottom-right corner to top-left corner.

#class GradientOptions

public sealed class GradientOptions : IEquatable<GradientOptions>

Gradient configuration for symbol rendering.

Notes

Configures a linear gradient applied across the whole symbol, flowing in one of the directions of GradientDirection . For a simple two-colour gradient pass two colours. For more, add colours and optionally the stops they sit at. An instance is immutable through its API: the constructor copies the arrays it is given and no member hands one back, so a shared instance such as Default cannot be repainted by one caller for everyone else. A with expression varies the direction of an existing gradient, as in GradientOptions.Default with { Direction = GradientDirection.BottomToTop }, and the copy shares the colour array with the original, which is safe for the same reason: neither instance exposes it. Direction is the only init member, which is a rule rather than an omission: Colors and ColorPositions have to agree in length, and with sets one member at a time, so allowing with { Colors = … } would let a caller build a gradient whose stops no longer match its colours and only find out when it is drawn. The pair is therefore set together, through the constructor, where the mismatch is refused immediately.

field Default

public static readonly GradientOptions Default;

A ready-made gradient: dark orange to firebrick, running from the top-left corner to the bottom-right. Use it when you want a gradient without choosing colors.

constructor GradientOptions

public GradientOptions(ReadOnlySpan<SKColor> colors, GradientDirection direction = 1, ReadOnlySpan<float> colorPositions = null);

Initializes a new instance of GradientOptions . Both spans are copied, so the caller keeps ownership of whatever it passed.

Notes

The parameters take the same shapes Colors and ColorPositions hand back, so an existing gradient can be rebuilt with one change and nothing else translated: var recolored = new GradientOptions([SKColors.Red, SKColors.Blue], options.Direction, options.ColorPositions); An array converts implicitly, so new GradientOptions(myColors) still works.

property Direction

public GradientDirection Direction { get; init; }

The gradient direction.

Notes

Determines the start and end points of the gradient across the symbol area. This is the member a with expression varies. The colours are chosen at construction.

property Colors

public ReadOnlySpan<SKColor> Colors { get; }

Gradient colors, in flow order.

Notes

At least 2 colors. The gradient flows from the first color to the last in the direction given by Direction .

property ColorPositions

public ReadOnlySpan<float> ColorPositions { get; }

Color stops (0.0 to 1.0), or empty when the colors are evenly distributed.

Notes

When non-empty the length matches Colors , and the values ascend from 0.0 (start) to 1.0 (end): [0.0f, 0.3f, 1.0f] for three colors.

method Equals

public bool Equals(GradientOptions? other);

method GetHashCode

public override int GetHashCode();

#class IconData

public sealed class IconData : IEquatable<IconData>

The logo or image drawn at the center of a QR code, and its size.

Notes

The icon covers modules, so the QR code relies on error correction to stay readable. Use the highest error correction level ( H ) and keep the icon small. When the size is given in modules, rendering throws if the icon and its border span more than MaxCoreOccupancyPercent percent of the core width. Sizes given as a percentage of the symbol are not checked against the QR code at all. Equality compares the sizing members by value and Icon by reference, so two instances built from the same SKBitmap through separate FromImage calls are not equal. IconShape is an open extension point wrapping an SKBitmap , neither of which defines value equality, so there is nothing to compare element-wise the way GradientOptions compares its colours.

constructor IconData obsolete

public IconData();

Creates an icon whose members are set through an object initializer.

Notes

Declared rather than left implicit, because declaring the constructor below would otherwise remove it and break every new IconData { … } call site.

constructor IconData

public IconData(IconShape icon, int iconSizePercent = 10, int iconBorderWidth = 2, int? iconSizeModules = null, int? iconBorderModules = null, int maxCoreOccupancyPercent = 30);

Creates an icon without an object initializer, for consumers whose language version predates C# 9.

Notes

Prefer the object initializer (new IconData { Icon = shape, IconSizePercent = 15 }) or one of the FromImage factories: they name only what they set and do not depend on this parameter order. This exists because init accessors are unassignable before C# 9, and .NET Framework and netstandard2.0 projects default to C# 7.3 while netstandard2.1 defaults to C# 8.0. Without it the factories are the only route, and both hardcode ImageIconShape , so ImageTextIconShape and any caller-written IconShape would be unreachable there. Pass arguments by name: iconSizePercent , iconBorderWidth and maxCoreOccupancyPercent are all integers, so a positional call can transpose them and still compile. Each default is the value the object initializer leaves the property at, so omitting one changes nothing.

property Icon

public IconShape Icon { get; init; }

What to draw at the center.

property IconBorderWidth

public int IconBorderWidth { get; init; }

Width of the background-colored padding around the icon, in pixels. Ignored once IconSizeModules is set. Being in pixels, it does not shrink with the symbol, so on a symbol only a few pixels across it reaches past the drawing area. Size the icon in modules to keep the padding proportional.

property IconSizePercent

public int IconSizePercent { get; init; }

Icon size as a percentage of the symbol's side, quiet zone included, 1 to 100. Ignored once IconSizeModules is set.

property MaxCoreOccupancyPercent

public int MaxCoreOccupancyPercent { get; init; }

How much of the QR code the icon and its border may cover, as a percentage. 30 by default. Only checked when the size is given in modules. Rendering throws when the icon exceeds it.

property IconBorderModules

public int? IconBorderModules { get; init; }

Width of the padding around the icon, in modules. 1 when omitted.

property IconSizeModules

public int? IconSizeModules { get; init; }

Icon size in modules, which keeps the icon aligned to the grid. Setting it switches sizing to modules, and IconSizePercent and IconBorderWidth stop applying.

method FromImage

public static IconData FromImage(SKBitmap image, int iconSizePercent = 10, int iconBorderWidth = 2);

Creates an icon sized as a percentage of the symbol's side.

method FromImageByModules

public static IconData FromImageByModules(SKBitmap image, int iconSizeModules, int iconBorderModules = 1, int maxCoreOccupancyPercent = 30);

Creates an icon sized in modules, so it lines up with the QR code grid.

Notes

Pair it with WithModulePixelSize so every module lands on a whole number of pixels. WithSize can then give a larger canvas, with the QR code centered and padded. The size is checked against the QR code when it is drawn, not here.

#class IconShape

public abstract class IconShape

How the icon at the center of a symbol is drawn.

constructor IconShape

protected IconShape();

method Draw

public abstract void Draw(SKCanvas canvas, SKRect rect, SKRect borderRect, SKColor backgroundColor);

Draws the icon.

#class ImageIconShape

public sealed class ImageIconShape : IconShape

Draws an image as the icon.

constructor ImageIconShape

public ImageIconShape(SKBitmap image);

Creates an icon from an image.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKRect borderRect, SKColor backgroundColor);

#class ImageTextIconShape

public sealed class ImageTextIconShape : IconShape

Draws an image as the icon, with a caption beside it.

constructor ImageTextIconShape

public ImageTextIconShape(SKBitmap image, string text, SKColor textColor, SKFont font, SKTextAlign horizontalAlign = 1, TextVerticalAlignment verticalAlign = 0, int textPadding = 0);

Creates the icon from an image and a caption.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKRect borderRect, SKColor backgroundColor);

#class MicroQRCodeImageBuilder

public sealed class MicroQRCodeImageBuilder : SymbolImageBuilderBase<MicroQRCodeImageBuilder>

Turns text into a Micro QR image, as PNG, JPEG, WebP or SVG.

Notes

The same shape as QRCodeImageBuilder , with Micro QR versions and levels and the 2-module quiet zone the specification asks for. Icons are not offered here: Micro QR has no error correction headroom to spare. Its one finder pattern can be styled with WithFinderPatternShape .

constructor MicroQRCodeImageBuilder

public MicroQRCodeImageBuilder(MicroQRCodeData microQrCodeData);

Starts a builder that draws a Micro QR code you have already generated. The Micro QR code is drawn exactly as given, so only the appearance options apply and the encoding options throw InvalidOperationException .

constructor MicroQRCodeImageBuilder

public MicroQRCodeImageBuilder(string content);

Starts a builder that will encode content when you ask for an image. Error correction, version and every other option keep their defaults until you set them.

method WithErrorCorrection

public MicroQRCodeImageBuilder WithErrorCorrection(MicroQREccLevel eccLevel);

Sets how much damage the Micro QR code should survive.

Notes

What is available depends on the version: M1 takes ErrorDetectionOnly alone, M2 and M3 take L and M, and M4 adds Q. A combination that does not exist throws when the Micro QR code is generated.

method WithMaskPattern

public MicroQRCodeImageBuilder WithMaskPattern(int? maskPattern);

Pin one of the four Micro QR data mask patterns (0-3) instead of the automatic edge-score selection. See MaskPattern .

method WithSegmentation

public MicroQRCodeImageBuilder WithSegmentation(MicroQRSegmentation segmentation);

Split the content into mixed-mode segments when that lowers the version (see MicroQRSegmentation ). Defaults to Optimal . Never selects a larger version, and produces the identical Micro QR code when a split would not shrink it.

method WithVersion

public MicroQRCodeImageBuilder WithVersion(MicroQRVersion version);

Pins the version instead of letting the content choose it.

Notes

The pinned case of WithVersion .

method WithVersion

public MicroQRCodeImageBuilder WithVersion(MicroQRVersionRange versionRange);

Narrows the versions the generator may choose from, for a Micro QR code that has to reach or stay under a physical size.

method GetImageBytes

public static byte[] GetImageBytes(MicroQRCodeData microQrCodeData, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the Micro QR code and returns an image in the format you choose.

method GetImageBytes

public static byte[] GetImageBytes(string content, SKEncodedImageFormat format, MicroQREccLevel eccLevel = 2, int size = 512, int quality = 100);

Encodes the content and returns an image in the format you choose.

method GetPngBytes

public static byte[] GetPngBytes(MicroQRCodeData microQrCodeData, int size = 512);

Renders the Micro QR code and returns a PNG image.

method GetPngBytes

public static byte[] GetPngBytes(string content, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and returns a PNG image.

method GetSvgBytes

public static byte[] GetSvgBytes(MicroQRCodeData microQrCodeData, int size = 512);

Renders the Micro QR code and returns an SVG document as UTF-8 bytes.

method GetSvgBytes

public static byte[] GetSvgBytes(string content, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and returns an SVG document as UTF-8 bytes.

method GetSvgString

public static string GetSvgString(MicroQRCodeData microQrCodeData, int size = 512);

Renders the Micro QR code and returns an SVG document as a string.

method GetSvgString

public static string GetSvgString(string content, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and returns an SVG document as a string.

method SavePng

public static void SavePng(MicroQRCodeData microQrCodeData, Stream output, int size = 512);

Renders the Micro QR code and writes a PNG to a stream.

method SavePng

public static void SavePng(string content, Stream output, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and writes a PNG to a stream.

method SaveSvg

public static void SaveSvg(MicroQRCodeData microQrCodeData, Stream output, int size = 512);

Renders the Micro QR code and writes an SVG document to a stream.

method SaveSvg

public static void SaveSvg(string content, Stream output, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and writes an SVG document to a stream.

method WriteImage

public static void WriteImage(MicroQRCodeData microQrCodeData, IBufferWriter<byte> writer, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the Micro QR code and writes an image in the format you choose to a buffer writer.

method WriteImage

public static void WriteImage(string content, IBufferWriter<byte> writer, SKEncodedImageFormat format, MicroQREccLevel eccLevel = 2, int size = 512, int quality = 100);

Encodes the content and writes an image in the format you choose to a buffer writer.

method WritePng

public static void WritePng(MicroQRCodeData microQrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the Micro QR code and writes a PNG to a buffer writer.

method WritePng

public static void WritePng(string content, IBufferWriter<byte> writer, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and writes a PNG to a buffer writer.

method WriteSvg

public static void WriteSvg(MicroQRCodeData microQrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the Micro QR code and writes an SVG document to a buffer writer.

method WriteSvg

public static void WriteSvg(string content, IBufferWriter<byte> writer, MicroQREccLevel eccLevel = 2, int size = 512);

Encodes the content and writes an SVG document to a buffer writer.

#class MicroQRCodeImageDecoder

public static class MicroQRCodeImageDecoder

Decodes Micro QR codes from SkiaSharp bitmaps. Extends MicroQRCodeDecoder , so with C# 14 the overloads are also reachable as MicroQRCodeDecoder.TryDecode(bitmap, ...). On older language versions call them on this class.

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text);

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text, out MicroQRCodeDecodeInfo info);

#class ModuleShape

public abstract class ModuleShape

How the individual modules of a symbol are drawn.

constructor ModuleShape

protected ModuleShape();

property RequiresAntialiasing

public abstract bool RequiresAntialiasing { get; }

Whether the shape needs antialiasing. Return true for curves, false for straight edges.

method Draw

public abstract void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

Draws one module.

#class QRCodeImageBuilder

public sealed class QRCodeImageBuilder : SymbolImageBuilderBase<QRCodeImageBuilder>

Turns text into a Standard QR image, as PNG, JPEG, WebP or SVG.

Notes

The static methods cover the common cases in one line, such as GetPngBytes . For anything else, construct the builder and chain the options, from sizing and colors down to WithIcon and WithFinderPatternShape.

constructor QRCodeImageBuilder

public QRCodeImageBuilder(QRCodeData qrCodeData);

Starts a builder that draws a QR code you have already generated. The QR code is used exactly as given, so only the appearance options apply. Most encoding options throw InvalidOperationException on a builder created this way. WithErrorCorrection and WithEciMode are accepted and then ignored.

constructor QRCodeImageBuilder

public QRCodeImageBuilder(string content);

Starts a builder that will encode content when you ask for an image. Error correction, version and every other option keep their defaults until you set them.

method WithEciMode

public QRCodeImageBuilder WithEciMode(EciMode eciMode);

Sets the character encoding to declare in the QR code.

method WithErrorCorrection

public QRCodeImageBuilder WithErrorCorrection(QREccLevel eccLevel);

Sets how much damage the QR code should survive: L recovers 7% of it, M 15%, Q 25% and H 30%.

method WithErrorCorrectionBoost

public QRCodeImageBuilder WithErrorCorrectionBoost(bool boostEccLevel = true);

Raise the error correction level above the one configured with WithErrorCorrection when the chosen version's capacity allows it, without changing the version or the QR code size. Recommended together with WithIcon : the spare capacity absorbs the modules the icon covers.

method WithIcon

public QRCodeImageBuilder WithIcon(IconData? iconData);

Draws an icon over the center of the QR code.

Notes

The icon covers modules, so pair it with a high error correction level or WithErrorCorrectionBoost , and scan what you ship. An icon that would cover more of the symbol than it can spare is refused when the image is rendered, not here, because how many modules it covers depends on the version the content selects.

method WithMaskPattern

public QRCodeImageBuilder WithMaskPattern(int? maskPattern);

Pin one of the eight data mask patterns (0-7) instead of the automatic penalty-scored selection. See MaskPattern .

method WithSegmentation

public QRCodeImageBuilder WithSegmentation(QRSegmentation segmentation);

Split the content into mixed-mode segments when that lowers the version (see QRSegmentation ). Defaults to Optimal . Never selects a larger version, and produces the identical QR code when a split would not shrink it.

method WithVersion

public QRCodeImageBuilder WithVersion(QRVersionRange versionRange);

Narrows the versions the generator may choose from, for a QR code that has to reach or stay under a physical size.

method WithVersion

public QRCodeImageBuilder WithVersion(int version);

Pins the version instead of letting the content choose it.

Notes

The pinned case of WithVersion .

method GetImageBytes

public static byte[] GetImageBytes(QRCodeData qrCodeData, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the QR code and returns an image in the format you choose.

method GetImageBytes

public static byte[] GetImageBytes(string content, SKEncodedImageFormat format, QREccLevel eccLevel = 1, int size = 512, int quality = 100);

Encodes the content and returns an image in the format you choose.

method GetPngBytes

public static byte[] GetPngBytes(QRCodeData qrCodeData, int size = 512);

Renders the QR code and returns a PNG image.

method GetPngBytes

public static byte[] GetPngBytes(string content, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and returns a PNG image.

method GetSvgBytes

public static byte[] GetSvgBytes(QRCodeData qrCodeData, int size = 512);

Renders the QR code and returns an SVG document as UTF-8 bytes.

method GetSvgBytes

public static byte[] GetSvgBytes(string content, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and returns an SVG document as UTF-8 bytes.

method GetSvgString

public static string GetSvgString(QRCodeData qrCodeData, int size = 512);

Renders the QR code and returns an SVG document as a string.

method GetSvgString

public static string GetSvgString(string content, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and returns an SVG document as a string.

method SavePng

public static void SavePng(QRCodeData qrCodeData, Stream output, int size = 512);

Renders the QR code and writes a PNG to a stream.

method SavePng

public static void SavePng(string content, Stream output, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and writes a PNG to a stream.

method SaveSvg

public static void SaveSvg(QRCodeData qrCodeData, Stream output, int size = 512);

Renders the QR code and writes an SVG document to a stream.

method SaveSvg

public static void SaveSvg(string content, Stream output, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and writes an SVG document to a stream.

method WriteImage

public static void WriteImage(QRCodeData qrCodeData, IBufferWriter<byte> writer, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the QR code and writes an image in the format you choose to a buffer writer.

method WriteImage

public static void WriteImage(string content, IBufferWriter<byte> writer, SKEncodedImageFormat format, QREccLevel eccLevel = 1, int size = 512, int quality = 100);

Encodes the content and writes an image in the format you choose to a buffer writer.

method WritePng

public static void WritePng(QRCodeData qrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the QR code and writes a PNG to a buffer writer.

method WritePng

public static void WritePng(string content, IBufferWriter<byte> writer, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and writes a PNG to a buffer writer.

method WriteSvg

public static void WriteSvg(QRCodeData qrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the QR code and writes an SVG document to a buffer writer.

method WriteSvg

public static void WriteSvg(string content, IBufferWriter<byte> writer, QREccLevel eccLevel = 1, int size = 512);

Encodes the content and writes an SVG document to a buffer writer.

#class QRCodeImageDecoder

public static class QRCodeImageDecoder

Decodes QR codes from SkiaSharp bitmaps. Extends QRCodeDecoder , so with C# 14 the overloads are also reachable as QRCodeDecoder.TryDecode(bitmap, ...). On older language versions call them on this class.

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text);

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text, out QRCodeDecodeInfo info);

#class RectangleFinderPatternShape

public sealed class RectangleFinderPatternShape : FinderPatternShape

The standard finder pattern: three nested squares.

field Default

public static readonly RectangleFinderPatternShape Default;

A ready-made instance to use as-is.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

Off: straight edges render cleanly without it.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class RectangleModuleShape

public sealed class RectangleModuleShape : ModuleShape

Draws modules as squares, the standard look.

field Default

public static readonly RectangleModuleShape Default;

A ready-made instance to use as-is.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

Off, so neighbouring modules do not show a gray seam between them.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class RmQRCodeImageBuilder

public sealed class RmQRCodeImageBuilder : SymbolImageBuilderBase<RmQRCodeImageBuilder>

Turns text into a rectangular rMQR image, as PNG, JPEG, WebP or SVG.

Notes

The same shape as QRCodeImageBuilder , with rMQR versions, levels and fit strategies and the 2-module quiet zone the specification asks for. Sizing has three modes: WithModulePixelSize gives the matrix at an exact scale, WithSize fits it into an exact canvas without stretching (every builder does that now, not just this one), and WithWidth takes a width and lets the height follow the code, which only a rectangular symbology has reason to offer. Icons are not offered here: rMQR has no error correction headroom to spare. Its one finder pattern can be styled with WithFinderPatternShape .

constructor RmQRCodeImageBuilder

public RmQRCodeImageBuilder(RmQRCodeData rmQrCodeData);

Starts a builder that draws an rMQR code you have already generated. The rMQR code is drawn exactly as given, so only the appearance options apply and the encoding options throw InvalidOperationException .

constructor RmQRCodeImageBuilder

public RmQRCodeImageBuilder(string content);

Starts a builder that will encode content when you ask for an image. Error correction, version and fit keep their defaults until you set them.

method WithEciMode

public RmQRCodeImageBuilder WithEciMode(EciMode eciMode);

Sets the character encoding to declare in the rMQR code.

method WithErrorCorrection

public RmQRCodeImageBuilder WithErrorCorrection(RmQREccLevel eccLevel);

Sets how much damage the rMQR code should survive, M or H.

method WithFitStrategy

public RmQRCodeImageBuilder WithFitStrategy(RmQRFitStrategy fitStrategy);

Configure how the version is chosen among those that hold the content. The default, MinimizeArea , takes the fewest modules and may prefer a taller, narrower rMQR code. Use MinimizeHeight or WithHeight for the flattest fit.

method WithHeight

public RmQRCodeImageBuilder WithHeight(RmQRHeight height);

Restrict automatic version selection to one rMQR code height (fixed height, automatic width). Must agree with WithVersion when both are used.

method WithSegmentation

public RmQRCodeImageBuilder WithSegmentation(RmQRSegmentation segmentation);

Split the content into mixed-mode segments when that lowers the module count (see RmQRSegmentation ). Defaults to Optimal . Fewer modules is not the same as a smaller image: a flatter, wider rMQR code can render onto a larger grid.

method WithVersion

public RmQRCodeImageBuilder WithVersion(RmQRVersion version);

Pins the version instead of letting the content choose it.

method WithWidth

public RmQRCodeImageBuilder WithWidth(int width);

Configure the image width in pixels. The height follows the rMQR code aspect ratio (rounded to whole pixels), the background covers the whole image and the rMQR code is drawn at a uniform module scale inside it. This is the static helpers' sizing rule and the default (512) when no size is configured. WithSize (letterbox into an exact canvas) or WithModulePixelSize (exact matrix) take precedence when also called.

method GetImageBytes

public static byte[] GetImageBytes(RmQRCodeData rmQrCodeData, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the rMQR code and returns an image in the format you choose.

method GetImageBytes

public static byte[] GetImageBytes(string content, SKEncodedImageFormat format, RmQREccLevel eccLevel = 0, int size = 512, int quality = 100);

Encodes the content and returns an image in the format you choose.

method GetPngBytes

public static byte[] GetPngBytes(RmQRCodeData rmQrCodeData, int size = 512);

Renders the rMQR code and returns a PNG image.

method GetPngBytes

public static byte[] GetPngBytes(string content, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and returns a PNG image.

method GetSvgBytes

public static byte[] GetSvgBytes(RmQRCodeData rmQrCodeData, int size = 512);

Renders the rMQR code and returns an SVG document as UTF-8 bytes.

method GetSvgBytes

public static byte[] GetSvgBytes(string content, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and returns an SVG document as UTF-8 bytes.

method GetSvgString

public static string GetSvgString(RmQRCodeData rmQrCodeData, int size = 512);

Renders the rMQR code and returns an SVG document as a string.

method GetSvgString

public static string GetSvgString(string content, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and returns an SVG document as a string.

method SavePng

public static void SavePng(RmQRCodeData rmQrCodeData, Stream output, int size = 512);

Renders the rMQR code and writes a PNG to a stream.

method SavePng

public static void SavePng(string content, Stream output, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and writes a PNG to a stream.

method SaveSvg

public static void SaveSvg(RmQRCodeData rmQrCodeData, Stream output, int size = 512);

Renders the rMQR code and writes an SVG document to a stream.

method SaveSvg

public static void SaveSvg(string content, Stream output, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and writes an SVG document to a stream.

method WriteImage

public static void WriteImage(RmQRCodeData rmQrCodeData, IBufferWriter<byte> writer, SKEncodedImageFormat format, int size = 512, int quality = 100);

Renders the rMQR code and writes an image in the format you choose to a buffer writer.

method WriteImage

public static void WriteImage(string content, IBufferWriter<byte> writer, SKEncodedImageFormat format, RmQREccLevel eccLevel = 0, int size = 512, int quality = 100);

Encodes the content and writes an image in the format you choose to a buffer writer.

method WritePng

public static void WritePng(RmQRCodeData rmQrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the rMQR code and writes a PNG to a buffer writer.

method WritePng

public static void WritePng(string content, IBufferWriter<byte> writer, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and writes a PNG to a buffer writer.

method WriteSvg

public static void WriteSvg(RmQRCodeData rmQrCodeData, IBufferWriter<byte> writer, int size = 512);

Renders the rMQR code and writes an SVG document to a buffer writer.

method WriteSvg

public static void WriteSvg(string content, IBufferWriter<byte> writer, RmQREccLevel eccLevel = 0, int size = 512);

Encodes the content and writes an SVG document to a buffer writer.

#class RmQRCodeImageDecoder

public static class RmQRCodeImageDecoder

Decodes rMQR Codes from SkiaSharp bitmaps. Extends RmQRCodeDecoder , so with C# 14 the overloads are also reachable as RmQRCodeDecoder.TryDecode(bitmap, ...). On older language versions call them on this class.

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text);

method TryDecode

public static bool TryDecode(SKBitmap bitmap, out string text, out RmQRCodeDecodeInfo info);

#class RoundedRectangleCircleFinderPatternShape

public sealed class RoundedRectangleCircleFinderPatternShape : FinderPatternShape

Two nested rounded rectangles around an oval, a circle on a square area.

field Default

public static readonly RoundedRectangleCircleFinderPatternShape Default;

A ready-made instance to use as-is.

constructor RoundedRectangleCircleFinderPatternShape

public RoundedRectangleCircleFinderPatternShape(float cornerRadiusPercent = 0.3);

Creates the shape with a corner radius of your own.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

On, so the curves do not come out jagged.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class RoundedRectangleFinderPatternShape

public sealed class RoundedRectangleFinderPatternShape : FinderPatternShape

Three nested rounded rectangles.

field Default

public static readonly RoundedRectangleFinderPatternShape Default;

A ready-made instance to use as-is.

constructor RoundedRectangleFinderPatternShape

public RoundedRectangleFinderPatternShape(float cornerRadiusPercent = 0.2);

Creates the shape with a corner radius of your own.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

On, so the curves do not come out jagged.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class RoundedRectangleModuleShape

public sealed class RoundedRectangleModuleShape : ModuleShape

Draws modules as rounded squares.

field Default

public static readonly RoundedRectangleModuleShape Default;

A ready-made instance to use as-is.

constructor RoundedRectangleModuleShape

public RoundedRectangleModuleShape(float cornerRadiusPercent = 0.3);

Creates the shape with a corner radius of your own.

property RequiresAntialiasing

public override bool RequiresAntialiasing { get; }

On, so the curves do not come out jagged.

method Draw

public override void Draw(SKCanvas canvas, SKRect rect, SKPaint paint);

#class SKCanvasExtensions

public static class SKCanvasExtensions

Draws a QR, Micro QR or rMQR code onto an SKCanvas you already have, instead of producing an image file.

Notes

Each method clears the whole canvas before drawing, so anything already on it is lost. Every argument is checked before that clear, so a refused call leaves the canvas as it was. To place a code inside a larger drawing, wrap the call in Save and ClipRect , or call SymbolRenderer directly, which draws only the code. Every symbology is fitted into the area at one uniform module scale and centered, using the same fit as the image builders (given an explicit canvas size, they also round the offset to whole pixels): a finder pattern is located by its 1:1:3:1:1 run along a line, and that ratio survives on one axis only once the modules stop being square. The whole area gets the background color. To pre-distort a symbol for an output device whose dots are not square, scale the canvas and draw into a square area. An inverted area is refused rather than read as a mirror. For a mirrored symbol, scale the canvas by -1 about the area.

method Render

public static void Render(SKCanvas canvas, MicroQRCodeData data, SKRect area, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a Micro QR code into an area of the canvas.

Notes

The Micro QR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color. Micro QR does not offer the Standard QR icon overlay, since it has no error-correction headroom for overlays. Its one finder pattern takes a shape like any other symbology.

method Render

public static void Render(SKCanvas canvas, MicroQRCodeData data, int width, int height, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a Micro QR code into an area of this size.

Notes

The Micro QR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color. Micro QR does not offer the Standard QR icon overlay, since it has no error-correction headroom for overlays. Its one finder pattern takes a shape like any other symbology.

method Render

public static void Render(SKCanvas canvas, QRCodeData data, SKRect area, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, IconData? iconData = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a QR code into an area of the canvas.

Notes

The QR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color.

method Render

public static void Render(SKCanvas canvas, QRCodeData data, int width, int height, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, IconData? iconData = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a QR code into an area of this size.

Notes

The QR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color.

method Render

public static void Render(SKCanvas canvas, RmQRCodeData data, SKRect area, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a rMQR code into an area of the canvas.

Notes

The rMQR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color. rMQR has no error correction headroom to spare, so there is no icon option. Its one finder pattern takes a shape like any other symbology.

method Render

public static void Render(SKCanvas canvas, RmQRCodeData data, int width, int height, SKColor? clearColor = null, SKColor? codeColor = null, SKColor? backgroundColor = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a rMQR code into an area of this size.

Notes

The rMQR code is drawn at a uniform module scale and centered, never stretched, and the whole area gets the background color. rMQR has no error correction headroom to spare, so there is no icon option. Its one finder pattern takes a shape like any other symbology.

#class SymbolImageBuilderBase

public abstract class SymbolImageBuilderBase<TSelf>

Shared implementation for the symbology-specific QR image builders ( QRCodeImageBuilder , MicroQRCodeImageBuilder , RmQRCodeImageBuilder ): the fluent options every symbology supports, canvas layout, and the complete raster/SVG output surface. Symbology-specific concerns, such as error correction and version types and icon overlays, live on the derived builders.

Notes

The self-referential type parameter keeps fluent chains typed to the concrete builder, so shared and symbology-specific options mix freely without casts: new MicroQRCodeImageBuilder("...").WithSize(256, 256).WithVersion(MicroQRVersion.M4). Deriving from this class outside the library is not supported: the abstract hooks that connect a symbology's data model to the shared output pipeline are private protected.

method ToBitmap

public SKBitmap ToBitmap();

Renders the symbol as an SKBitmap , which the caller disposes.

method ToImage

public SKImage ToImage();

Renders the symbol as an SKImage , which the caller disposes.

method WithBackgroundColor

public TSelf WithBackgroundColor(SKColor backgroundColor);

Sets the color behind the symbol, quiet zone included. White by default.

method WithClearColor

public TSelf WithClearColor(SKColor? clearColor);

Sets the padding around the symbol when the canvas is larger than the content, which is also the color the canvas is cleared with before the symbol is drawn.

Notes

Without a clear color the padding follows the background, so the image does not come out part symbol and part transparent. Pass Transparent for transparent surroundings.

method WithCodeColor

public TSelf WithCodeColor(SKColor codeColor);

Sets the color of the dark modules, black by default.

Notes

A gradient set with WithGradient takes precedence over this color whatever the order of the two calls, so this is not the way to replace a gradient with a solid color. Pass null to WithGradient for that, or a gradient whose direction is None , which paints this color.

method WithColors

public TSelf WithColors(SKColor codeColor, SKColor backgroundColor);

Sets the two colors a symbol always has, the modules and what is behind them.

Notes

Both are required, so this call sets exactly the two colors it names and leaves the clear color alone. To change one color on its own use WithCodeColor or WithBackgroundColor . The code color's interaction with WithGradient is described there.

method WithFinderPatternShape

public TSelf WithFinderPatternShape(FinderPatternShape finderPatternShape);

Draws the finder patterns as a shape of their own.

Notes

The built-in shapes reshape the concentric rings without breaking them, so they stay detectable. What a decoder needs is that the rings are continuous, not that they are square. Not calling this leaves the plain square the standards define, which is always the safest to scan, and it is also what a styled symbol gets: a shaped module never reaches a finder pattern. A shape draws the dark modules only and leaves the light ring undrawn, so the background shows through it at any alpha, in raster and SVG output alike.

method WithFormat

public TSelf WithFormat(SKEncodedImageFormat format, int quality = 100);

Sets the encoded image format and quality. PNG at 100 by default.

method WithGradient

public TSelf WithGradient(GradientOptions? gradientOptions);

Paints the modules with a gradient instead of one solid color.

Notes

A gradient takes precedence over the code color whatever the order of the calls, so a later WithCodeColor does not turn it back into a solid color. This setter's own null does, as does a gradient whose direction is None .

method WithModulePixelSize

public TSelf WithModulePixelSize(int modulePixelSize);

Gives every module an exact pixel size, so the symbol comes out crisp at any version.

Notes

On its own the image is exactly as large as the symbol needs. Combined with WithSize the content is centered on that canvas and the rest padded, in the clear color when one is set and the background color otherwise.

method WithModuleShape

public TSelf WithModuleShape(ModuleShape moduleShape, float sizePercent = 1);

Draws the modules as a shape other than plain squares.

Notes

Styles the data modules only. The finder patterns keep their solid shape whatever is asked for here, because a decoder locates the symbol by scanning for their 1:1:3:1:1 run of dark and light, and gaps between modules erase it: a symbol whose finders are drawn as separated shapes is not read by anything, this library or a phone. Use WithFinderPatternShape to style them in a way that keeps them detectable. Every custom shape costs scan margin, and below 0.8 the symbol may stop scanning reliably, so test what you ship.

method WithQuietZone

public TSelf WithQuietZone(int size);

Sets the width of the light border around the symbol.

Notes

Defaults to what the specification asks for: 4 modules for Standard QR, 2 for Micro QR and rMQR. Ignored when the builder was given a ready-made symbol, which carries its own quiet zone.

method WithSize

public TSelf WithSize(int width, int height);

Sets the output image size in pixels.

Notes

On its own, the symbol is fitted into the canvas with one uniform module scale and centered, whatever the canvas aspect ratio: modules stay square, because a symbol whose modules are not square stops being findable well before it stops being drawn. The module size follows from the canvas, so it can be fractional and shifts when the version changes. Combined with WithModulePixelSize this is the canvas alone and the modules decide the content size. Either way the content is centered and the leftover canvas is padded, in the clear color when one is set and the background color otherwise. A canvas smaller than the content on either side is an error, but only when the module size is pinned. On its own this method has no size it cannot fit.

method ToByteArray

public byte[] ToByteArray();

Renders the symbol and returns the encoded image bytes.

method ToSvgString

public string ToSvgString();

Renders the symbol as an SVG document and returns it as a string.

Notes

Renders exactly as SaveToSvg .

method SaveTo

public void SaveTo(IBufferWriter<byte> writer);

Renders the symbol and writes the encoded image to a buffer writer, skipping the intermediate buffering the stream overload does.

method SaveTo

public void SaveTo(Stream output);

Renders the symbol and writes the encoded image to a stream.

method SaveToSvg

public void SaveToSvg(IBufferWriter<byte> writer);

Renders the symbol as an SVG document and writes it to a buffer writer.

Notes

Renders exactly as SaveToSvg . The document is written in the writer own segments, so a segmented writer such as a pipe never has to hold it contiguously.

method SaveToSvg

public void SaveToSvg(Stream output);

Renders the symbol as an SVG document and writes it to a stream.

Notes

The symbol is drawn as vector shapes, so it scales without losing quality, and the colors, shapes, gradients and icons all apply, on a background of any alpha. The root element carries a viewBox, so the document resizes when embedded at another size. Plain square modules get shape-rendering="crispEdges" to avoid antialiasing seams. Custom shapes keep antialiasing for smooth curves. WithFormat does not apply, since SVG is not a raster format. The size options set the viewport instead.

#class SymbolRenderer

public static class SymbolRenderer

Draws a QR, Micro QR or rMQR code onto a SkiaSharp canvas, with full control over colors, shapes, gradients and icon overlays. Use it when the image builders do not give you the control you need.

Notes

The symbol is fitted into the area at one uniform module scale and centered, whatever the area's aspect ratio, using the same fit as the image builders (given an explicit canvas size, they also round the offset to whole pixels): modules stay square, because a symbol whose modules are not square stops being findable well before it stops being drawn. The background covers the whole area. To pre-distort a symbol for an output device whose dots are not square, scale the canvas and draw into a square area. An inverted area is refused rather than read as a mirror. For a mirrored symbol (a transfer print, a sticker read through glass), scale the canvas by -1 about the area.

method GetFinderPatternRect

public static SKRect GetFinderPatternRect(QRCodeData data, int patternIndex, SKRect renderArea);

Where one of the three finder patterns lands inside a rendered QR code, so you can draw over or around it.

Notes

The finder patterns are the large squares typically located at three corners of a QR code. This method calculates their positions based on the QR code's size and quiet zone, ensuring accurate placement within the specified rendering area. Pass the area you gave Render: a non-square one is fitted the same way, so the answer is where the pattern was drawn. For a QRCodeImageBuilder output, the whole image works when only the canvas size was set, to within half a pixel, because the builder rounds its centering offset down to whole pixels where this fit does not. With a module pixel size pinned inside a larger canvas the symbol is smaller than the fit, so pass its content rectangle instead: matrix size Γ— module pixel size on each side, offset by half the leftover, rounded down.

method GetIconRects

public static ValueTuple<SKRect, SKRect> GetIconRects(QRCodeData data, SKRect area, IconData iconData);

Works out where an icon and its border land inside a QR code.

Notes

When IconSizeModules is set, sizing is module-based and percent/pixel values are ignored. A non-square area is fitted exactly as Render fits it, so pass the area you drew into. An area no symbol fits in, where Render draws nothing, gives empty rectangles at the fitted symbol's centre. Module-based icons are validated against QR size and core occupancy at render time. Icon rectangles are snapped to the module grid, since even module sizes cannot be geometrically centered on an odd QR matrix.

method Render

public static void Render(SKCanvas canvas, SKRect area, MicroQRCodeData data, SKColor codeColor, SKColor backgroundColor, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a Micro QR code into an area of the canvas.

Notes

A non-square area gets the symbol at a uniform module scale, centered, with the background over the whole area. The two colors are values with no spelling for "the default": default is transparent here, not black. Micro QR has one finder pattern, at the top left, and no error-correction headroom for overlays, so the Standard QR icon option is intentionally not available. See Render for the module-run merge behavior shared with Standard QR.

method Render

public static void Render(SKCanvas canvas, SKRect area, QRCodeData data, SKColor codeColor, SKColor backgroundColor, IconData? iconData = null, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a QR code into an area of the canvas.

Notes

A non-square area gets the symbol at a uniform module scale, centered, with the background over the whole area. The two colors are values with no spelling for "the default": default is transparent here, not black. GetFinderPatternRect and GetIconRects fit the same way, so pass them the same area. With the default rectangle shape at moduleSizePercent 1.0, horizontal runs of dark modules are drawn as single merged rectangles (fewer native draw calls). Merged and per-module rendering are pixel-identical under axis-preserving canvas transforms (translation/scale). Under rotation, shared-edge rounding may differ at sub-pixel level. Any custom module shape or a module size below 1.0 falls back to per-module drawing.

method Render

public static void Render(SKCanvas canvas, SKRect area, RmQRCodeData data, SKColor codeColor, SKColor backgroundColor, ModuleShape? moduleShape = null, float moduleSizePercent = 1, GradientOptions? gradientOptions = null, FinderPatternShape? finderPatternShape = null);

Draws a rectangular rMQR code into an area of the canvas, at a uniform module scale and centered, never stretched.

Notes

The whole area gets the background color, not just the code itself. The two colors are values with no spelling for "the default": default is transparent here, not black. rMQR has no error correction headroom to spare, so there is no icon option. Modules are merged as for Standard QR.

#enum TextVerticalAlignment

public enum TextVerticalAlignment : int

Where the text sits relative to the icon.

Bottom = 0,

Below the icon.

Center = 1,

Centered on the icon.

Top = 2,

Above the icon.