Texture Rendering (#9)
Co-authored-by: Zachary Levy <zachary@sunforge.is> Reviewed-on: #9
This commit was merged in pull request #9.
This commit is contained in:
@@ -73,57 +73,32 @@ main :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Utilities
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Prints the given QR Code to the console.
|
||||
print_qr :: proc(qrcode: []u8) {
|
||||
size := qr.get_size(qrcode)
|
||||
border :: 4
|
||||
for y in -border ..< size + border {
|
||||
for x in -border ..< size + border {
|
||||
fmt.print("##" if qr.get_module(qrcode, x, y) else " ")
|
||||
}
|
||||
fmt.println()
|
||||
}
|
||||
fmt.println()
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Demo: Basic
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Creates a single QR Code, then prints it to the console.
|
||||
basic :: proc() {
|
||||
text :: "Hello, world!"
|
||||
ecl :: qr.Ecc.Low
|
||||
|
||||
qrcode: [qr.BUFFER_LEN_MAX]u8
|
||||
ok := qr.encode(text, qrcode[:], ecl)
|
||||
ok := qr.encode_auto(text, qrcode[:], ecl)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Demo: Variety
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Creates a variety of QR Codes that exercise different features of the library.
|
||||
variety :: proc() {
|
||||
qrcode: [qr.BUFFER_LEN_MAX]u8
|
||||
|
||||
{ // Numeric mode encoding (3.33 bits per digit)
|
||||
ok := qr.encode("314159265358979323846264338327950288419716939937510", qrcode[:], qr.Ecc.Medium)
|
||||
ok := qr.encode_auto("314159265358979323846264338327950288419716939937510", qrcode[:], qr.Ecc.Medium)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
{ // Alphanumeric mode encoding (5.5 bits per character)
|
||||
ok := qr.encode("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", qrcode[:], qr.Ecc.High)
|
||||
ok := qr.encode_auto("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", qrcode[:], qr.Ecc.High)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
{ // Unicode text as UTF-8
|
||||
ok := qr.encode(
|
||||
ok := qr.encode_auto(
|
||||
"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81" +
|
||||
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4",
|
||||
qrcode[:],
|
||||
@@ -133,7 +108,7 @@ variety :: proc() {
|
||||
}
|
||||
|
||||
{ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
|
||||
ok := qr.encode(
|
||||
ok := qr.encode_auto(
|
||||
"Alice was beginning to get very tired of sitting by her sister on the bank, " +
|
||||
"and of having nothing to do: once or twice she had peeped into the book her sister was reading, " +
|
||||
"but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice " +
|
||||
@@ -148,10 +123,6 @@ variety :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Demo: Segment
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Creates QR Codes with manually specified segments for better compactness.
|
||||
segment :: proc() {
|
||||
qrcode: [qr.BUFFER_LEN_MAX]u8
|
||||
@@ -163,7 +134,7 @@ segment :: proc() {
|
||||
// Encode as single text (auto mode selection)
|
||||
{
|
||||
concat :: silver0 + silver1
|
||||
ok := qr.encode(concat, qrcode[:], qr.Ecc.Low)
|
||||
ok := qr.encode_auto(concat, qrcode[:], qr.Ecc.Low)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
@@ -172,7 +143,7 @@ segment :: proc() {
|
||||
seg_buf0: [qr.BUFFER_LEN_MAX]u8
|
||||
seg_buf1: [qr.BUFFER_LEN_MAX]u8
|
||||
segs := [2]qr.Segment{qr.make_alphanumeric(silver0, seg_buf0[:]), qr.make_numeric(silver1, seg_buf1[:])}
|
||||
ok := qr.encode(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
ok := qr.encode_auto(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
}
|
||||
@@ -185,7 +156,7 @@ segment :: proc() {
|
||||
// Encode as single text (auto mode selection)
|
||||
{
|
||||
concat :: golden0 + golden1 + golden2
|
||||
ok := qr.encode(concat, qrcode[:], qr.Ecc.Low)
|
||||
ok := qr.encode_auto(concat, qrcode[:], qr.Ecc.Low)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
@@ -201,7 +172,7 @@ segment :: proc() {
|
||||
qr.make_numeric(golden1, seg_buf1[:]),
|
||||
qr.make_alphanumeric(golden2, seg_buf2[:]),
|
||||
}
|
||||
ok := qr.encode(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
ok := qr.encode_auto(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
}
|
||||
@@ -219,7 +190,7 @@ segment :: proc() {
|
||||
"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF" +
|
||||
"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF" +
|
||||
"\xBC\x9F"
|
||||
ok := qr.encode(madoka, qrcode[:], qr.Ecc.Low)
|
||||
ok := qr.encode_auto(madoka, qrcode[:], qr.Ecc.Low)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
@@ -254,16 +225,12 @@ segment :: proc() {
|
||||
seg.data = seg_buf[:(seg.bit_length + 7) / 8]
|
||||
|
||||
segs := [1]qr.Segment{seg}
|
||||
ok := qr.encode(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
ok := qr.encode_auto(segs[:], qr.Ecc.Low, qrcode[:])
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Demo: Mask
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Creates QR Codes with the same size and contents but different mask patterns.
|
||||
mask :: proc() {
|
||||
qrcode: [qr.BUFFER_LEN_MAX]u8
|
||||
@@ -271,10 +238,10 @@ mask :: proc() {
|
||||
{ // Project Nayuki URL
|
||||
ok: bool
|
||||
|
||||
ok = qr.encode("https://www.nayuki.io/", qrcode[:], qr.Ecc.High)
|
||||
ok = qr.encode_auto("https://www.nayuki.io/", qrcode[:], qr.Ecc.High)
|
||||
if ok do print_qr(qrcode[:])
|
||||
|
||||
ok = qr.encode("https://www.nayuki.io/", qrcode[:], qr.Ecc.High, mask = qr.Mask.M3)
|
||||
ok = qr.encode_auto("https://www.nayuki.io/", qrcode[:], qr.Ecc.High, mask = qr.Mask.M3)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
|
||||
@@ -290,16 +257,29 @@ mask :: proc() {
|
||||
|
||||
ok: bool
|
||||
|
||||
ok = qr.encode(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M0)
|
||||
ok = qr.encode_auto(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M0)
|
||||
if ok do print_qr(qrcode[:])
|
||||
|
||||
ok = qr.encode(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M1)
|
||||
ok = qr.encode_auto(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M1)
|
||||
if ok do print_qr(qrcode[:])
|
||||
|
||||
ok = qr.encode(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M5)
|
||||
ok = qr.encode_auto(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M5)
|
||||
if ok do print_qr(qrcode[:])
|
||||
|
||||
ok = qr.encode(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M7)
|
||||
ok = qr.encode_auto(text, qrcode[:], qr.Ecc.Medium, mask = qr.Mask.M7)
|
||||
if ok do print_qr(qrcode[:])
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the given QR Code to the console.
|
||||
print_qr :: proc(qrcode: []u8) {
|
||||
size := qr.get_size(qrcode)
|
||||
border :: 4
|
||||
for y in -border ..< size + border {
|
||||
for x in -border ..< size + border {
|
||||
fmt.print("##" if qr.get_module(qrcode, x, y) else " ")
|
||||
}
|
||||
fmt.println()
|
||||
}
|
||||
fmt.println()
|
||||
}
|
||||
|
||||
@@ -2,10 +2,30 @@ package qrcode
|
||||
|
||||
import "core:slice"
|
||||
|
||||
VERSION_MIN :: 1
|
||||
VERSION_MAX :: 40
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Types
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// The worst-case number of bytes needed to store one QR Code, up to and including version 40.
|
||||
BUFFER_LEN_MAX :: 3918 // buffer_len_for_version(VERSION_MAX)
|
||||
|
||||
// Returns the number of bytes needed to store any QR Code up to and including the given version.
|
||||
buffer_len_for_version :: #force_inline proc(n: int) -> int {
|
||||
size := n * 4 + 17
|
||||
return (size * size + 7) / 8 + 1
|
||||
}
|
||||
|
||||
@(private)
|
||||
LENGTH_OVERFLOW :: -1
|
||||
@(private)
|
||||
REED_SOLOMON_DEGREE_MAX :: 30
|
||||
@(private)
|
||||
PENALTY_N1 :: 3
|
||||
@(private)
|
||||
PENALTY_N2 :: 3
|
||||
@(private)
|
||||
PENALTY_N3 :: 40
|
||||
@(private)
|
||||
PENALTY_N4 :: 10
|
||||
|
||||
// The error correction level in a QR Code symbol.
|
||||
Ecc :: enum {
|
||||
@@ -44,39 +64,6 @@ Segment :: struct {
|
||||
bit_length: int,
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
VERSION_MIN :: 1
|
||||
VERSION_MAX :: 40
|
||||
|
||||
// The worst-case number of bytes needed to store one QR Code, up to and including version 40.
|
||||
BUFFER_LEN_MAX :: 3918 // buffer_len_for_version(VERSION_MAX)
|
||||
|
||||
// Returns the number of bytes needed to store any QR Code up to and including the given version.
|
||||
buffer_len_for_version :: #force_inline proc(n: int) -> int {
|
||||
size := n * 4 + 17
|
||||
return (size * size + 7) / 8 + 1
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Private constants
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
@(private)
|
||||
LENGTH_OVERFLOW :: -1
|
||||
@(private)
|
||||
REED_SOLOMON_DEGREE_MAX :: 30
|
||||
@(private)
|
||||
PENALTY_N1 :: 3
|
||||
@(private)
|
||||
PENALTY_N2 :: 3
|
||||
@(private)
|
||||
PENALTY_N3 :: 40
|
||||
@(private)
|
||||
PENALTY_N4 :: 10
|
||||
|
||||
//odinfmt: disable
|
||||
// For generating error correction codes. Index 0 is padding (set to illegal value).
|
||||
@(private)
|
||||
@@ -96,10 +83,9 @@ NUM_ERROR_CORRECTION_BLOCKS := [4][41]i8{
|
||||
}
|
||||
//odinfmt: enable
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Encode procedures
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Encode Procedures ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Encodes the given text string to a QR Code, automatically selecting
|
||||
// numeric, alphanumeric, or byte mode based on content.
|
||||
@@ -117,7 +103,7 @@ NUM_ERROR_CORRECTION_BLOCKS := [4][41]i8{
|
||||
// - The text cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||
// - The encoded segment data exceeds the buffer capacity.
|
||||
@(require_results)
|
||||
encode_text_explicit_temp :: proc(
|
||||
encode_text_manual :: proc(
|
||||
text: string,
|
||||
temp_buffer, qrcode: []u8,
|
||||
ecl: Ecc,
|
||||
@@ -130,7 +116,7 @@ encode_text_explicit_temp :: proc(
|
||||
) {
|
||||
text_len := len(text)
|
||||
if text_len == 0 {
|
||||
return encode_segments_advanced_explicit_temp(
|
||||
return encode_segments_advanced_manual(
|
||||
nil,
|
||||
ecl,
|
||||
min_version,
|
||||
@@ -162,7 +148,7 @@ encode_text_explicit_temp :: proc(
|
||||
seg.data = temp_buffer[:text_len]
|
||||
}
|
||||
segs := [1]Segment{seg}
|
||||
return encode_segments_advanced_explicit_temp(
|
||||
return encode_segments_advanced_manual(
|
||||
segs[:],
|
||||
ecl,
|
||||
min_version,
|
||||
@@ -211,13 +197,9 @@ encode_text_auto :: proc(
|
||||
return false
|
||||
}
|
||||
defer delete(temp_buffer, temp_allocator)
|
||||
return encode_text_explicit_temp(text, temp_buffer, qrcode, ecl, min_version, max_version, mask, boost_ecl)
|
||||
return encode_text_manual(text, temp_buffer, qrcode, ecl, min_version, max_version, mask, boost_ecl)
|
||||
}
|
||||
|
||||
encode_text :: proc {
|
||||
encode_text_explicit_temp,
|
||||
encode_text_auto,
|
||||
}
|
||||
|
||||
// Encodes arbitrary binary data to a QR Code using byte mode.
|
||||
//
|
||||
@@ -234,7 +216,7 @@ encode_text :: proc {
|
||||
// Returns ok=false when:
|
||||
// - The payload cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||
@(require_results)
|
||||
encode_binary :: proc(
|
||||
encode_binary_manual :: proc(
|
||||
data_and_temp: []u8,
|
||||
data_len: int,
|
||||
qrcode: []u8,
|
||||
@@ -256,7 +238,7 @@ encode_binary :: proc(
|
||||
seg.num_chars = data_len
|
||||
seg.data = data_and_temp[:data_len]
|
||||
segs := [1]Segment{seg}
|
||||
return encode_segments_advanced(
|
||||
return encode_segments_advanced_manual(
|
||||
segs[:],
|
||||
ecl,
|
||||
min_version,
|
||||
@@ -268,6 +250,55 @@ encode_binary :: proc(
|
||||
)
|
||||
}
|
||||
|
||||
// Encodes arbitrary binary data to a QR Code using byte mode,
|
||||
// automatically allocating and freeing the temp buffer.
|
||||
//
|
||||
// Parameters:
|
||||
// bin_data - [in] Payload bytes (aliased by the internal segment; not modified).
|
||||
// qrcode - [out] On success, contains the encoded QR Code. On failure, qrcode[0] is
|
||||
// set to 0.
|
||||
// temp_allocator - Allocator used for the internal scratch buffer. Freed before return.
|
||||
//
|
||||
// qrcode must have length >= buffer_len_for_version(max_version).
|
||||
//
|
||||
// Returns ok=false when:
|
||||
// - The payload cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||
// - The temp_allocator fails to allocate.
|
||||
@(require_results)
|
||||
encode_binary_auto :: proc(
|
||||
bin_data: []u8,
|
||||
qrcode: []u8,
|
||||
ecl: Ecc,
|
||||
min_version: int = VERSION_MIN,
|
||||
max_version: int = VERSION_MAX,
|
||||
mask: Maybe(Mask) = nil,
|
||||
boost_ecl: bool = true,
|
||||
temp_allocator := context.temp_allocator,
|
||||
) -> (
|
||||
ok: bool,
|
||||
) {
|
||||
seg: Segment
|
||||
seg.mode = .Byte
|
||||
seg.bit_length = calc_segment_bit_length(.Byte, len(bin_data))
|
||||
if seg.bit_length == LENGTH_OVERFLOW {
|
||||
qrcode[0] = 0
|
||||
return false
|
||||
}
|
||||
seg.num_chars = len(bin_data)
|
||||
seg.data = bin_data
|
||||
segs := [1]Segment{seg}
|
||||
return encode_segments_advanced_auto(
|
||||
segs[:],
|
||||
ecl,
|
||||
min_version,
|
||||
max_version,
|
||||
mask,
|
||||
boost_ecl,
|
||||
qrcode,
|
||||
temp_allocator,
|
||||
)
|
||||
}
|
||||
|
||||
// Encodes the given segments to a QR Code using default parameters
|
||||
// (VERSION_MIN..VERSION_MAX, auto mask, boost ECL).
|
||||
//
|
||||
@@ -282,17 +313,8 @@ encode_binary :: proc(
|
||||
// Returns ok=false when:
|
||||
// - The total segment data exceeds the capacity of version 40 at the given ECL.
|
||||
@(require_results)
|
||||
encode_segments_explicit_temp :: proc(segs: []Segment, ecl: Ecc, temp_buffer, qrcode: []u8) -> (ok: bool) {
|
||||
return encode_segments_advanced_explicit_temp(
|
||||
segs,
|
||||
ecl,
|
||||
VERSION_MIN,
|
||||
VERSION_MAX,
|
||||
nil,
|
||||
true,
|
||||
temp_buffer,
|
||||
qrcode,
|
||||
)
|
||||
encode_segments_manual :: proc(segs: []Segment, ecl: Ecc, temp_buffer, qrcode: []u8) -> (ok: bool) {
|
||||
return encode_segments_advanced_manual(segs, ecl, VERSION_MIN, VERSION_MAX, nil, true, temp_buffer, qrcode)
|
||||
}
|
||||
|
||||
// Encodes segments to a QR Code using default parameters, automatically allocating the temp buffer.
|
||||
@@ -328,13 +350,9 @@ encode_segments_auto :: proc(
|
||||
return false
|
||||
}
|
||||
defer delete(temp_buffer, temp_allocator)
|
||||
return encode_segments_explicit_temp(segs, ecl, temp_buffer, qrcode)
|
||||
return encode_segments_manual(segs, ecl, temp_buffer, qrcode)
|
||||
}
|
||||
|
||||
encode_segments :: proc {
|
||||
encode_segments_explicit_temp,
|
||||
encode_segments_auto,
|
||||
}
|
||||
|
||||
// Encodes the given segments to a QR Code with full control over version range, mask, and ECL boosting.
|
||||
//
|
||||
@@ -353,7 +371,7 @@ encode_segments :: proc {
|
||||
// - The total segment data exceeds the capacity of every version in [min_version, max_version]
|
||||
// at the given ECL.
|
||||
@(require_results)
|
||||
encode_segments_advanced_explicit_temp :: proc(
|
||||
encode_segments_advanced_manual :: proc(
|
||||
segs: []Segment,
|
||||
ecl: Ecc,
|
||||
min_version, max_version: int,
|
||||
@@ -490,7 +508,7 @@ encode_segments_advanced_auto :: proc(
|
||||
return false
|
||||
}
|
||||
defer delete(temp_buffer, temp_allocator)
|
||||
return encode_segments_advanced_explicit_temp(
|
||||
return encode_segments_advanced_manual(
|
||||
segs,
|
||||
ecl,
|
||||
min_version,
|
||||
@@ -502,24 +520,24 @@ encode_segments_advanced_auto :: proc(
|
||||
)
|
||||
}
|
||||
|
||||
encode_segments_advanced :: proc {
|
||||
encode_segments_advanced_explicit_temp,
|
||||
encode_segments_advanced_auto,
|
||||
encode_manual :: proc {
|
||||
encode_text_manual,
|
||||
encode_binary_manual,
|
||||
encode_segments_manual,
|
||||
encode_segments_advanced_manual,
|
||||
}
|
||||
|
||||
encode :: proc {
|
||||
encode_text_explicit_temp,
|
||||
encode_auto :: proc {
|
||||
encode_text_auto,
|
||||
encode_binary,
|
||||
encode_segments_explicit_temp,
|
||||
encode_binary_auto,
|
||||
encode_segments_auto,
|
||||
encode_segments_advanced_explicit_temp,
|
||||
encode_segments_advanced_auto,
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Error correction code generation
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Error Correction Code Generation ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Appends error correction bytes to each block of data, then interleaves bytes from all blocks.
|
||||
@(private)
|
||||
@@ -587,10 +605,6 @@ get_num_raw_data_modules :: proc(ver: int) -> int {
|
||||
return result
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Reed-Solomon ECC generator
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
@(private)
|
||||
reed_solomon_compute_divisor :: proc(degree: int, result: []u8) {
|
||||
assert(1 <= degree && degree <= REED_SOLOMON_DEGREE_MAX, "reed-solomon degree out of range")
|
||||
@@ -637,9 +651,9 @@ reed_solomon_multiply :: proc(x, y: u8) -> u8 {
|
||||
return z
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Drawing function modules
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Drawing Function Modules ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Clears the QR Code grid and marks every function module as dark.
|
||||
@(private)
|
||||
@@ -785,9 +799,9 @@ fill_rectangle :: proc(left, top, width, height: int, qrcode: []u8) {
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Drawing data modules and masking
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Drawing data modules and masking ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@(private)
|
||||
draw_codewords :: proc(data: []u8, data_len: int, qrcode: []u8) {
|
||||
@@ -965,9 +979,9 @@ finder_penalty_add_history :: proc(current_run_length: int, run_history: ^[7]int
|
||||
run_history[0] = current_run_length
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Basic QR Code information
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Basic QR code information ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Returns the minimum buffer size (in bytes) needed for both temp_buffer and qrcode
|
||||
// to encode the given content at the given ECC level within the given version range.
|
||||
@@ -981,7 +995,7 @@ min_buffer_size :: proc {
|
||||
min_buffer_size_segments,
|
||||
}
|
||||
|
||||
// Text path: auto-selects numeric/alphanumeric/byte mode the same way encode_text does.
|
||||
// Text path: auto-selects numeric/alphanumeric/byte mode the same way encode_text_manual does.
|
||||
//
|
||||
// Returns ok=false when:
|
||||
// - The text exceeds QR Code capacity for every version in the range at the given ECL.
|
||||
@@ -1127,9 +1141,9 @@ get_bit :: #force_inline proc(x: int, i: uint) -> bool {
|
||||
return ((x >> i) & 1) != 0
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Segment handling
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Segment Handling ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Tests whether the given string can be encoded in numeric mode.
|
||||
is_numeric :: proc(text: string) -> bool {
|
||||
@@ -1162,7 +1176,6 @@ calc_segment_buffer_size :: proc(mode: Mode, num_chars: int) -> int {
|
||||
return (temp + 7) / 8
|
||||
}
|
||||
|
||||
@(private)
|
||||
calc_segment_bit_length :: proc(mode: Mode, num_chars: int) -> int {
|
||||
if num_chars < 0 || num_chars > 32767 {
|
||||
return LENGTH_OVERFLOW
|
||||
@@ -1319,11 +1332,11 @@ make_eci :: proc(assign_val: int, buf: []u8) -> Segment {
|
||||
return result
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Private helpers
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Helpers ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@(private)
|
||||
// Internal
|
||||
append_bits_to_buffer :: proc(val: uint, num_bits: int, buffer: []u8, bit_len: ^int) {
|
||||
assert(0 <= num_bits && num_bits <= 16 && val >> uint(num_bits) == 0, "invalid bit count or value overflow")
|
||||
for i := num_bits - 1; i >= 0; i -= 1 {
|
||||
@@ -1332,7 +1345,7 @@ append_bits_to_buffer :: proc(val: uint, num_bits: int, buffer: []u8, bit_len: ^
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
// Internal
|
||||
get_total_bits :: proc(segs: []Segment, version: int) -> int {
|
||||
result := 0
|
||||
for &seg in segs {
|
||||
@@ -1354,7 +1367,7 @@ get_total_bits :: proc(segs: []Segment, version: int) -> int {
|
||||
return result
|
||||
}
|
||||
|
||||
@(private)
|
||||
// Internal
|
||||
num_char_count_bits :: proc(mode: Mode, version: int) -> int {
|
||||
assert(VERSION_MIN <= version && version <= VERSION_MAX, "version out of bounds")
|
||||
i := (version + 7) / 17
|
||||
@@ -1376,8 +1389,8 @@ num_char_count_bits :: proc(mode: Mode, version: int) -> int {
|
||||
unreachable()
|
||||
}
|
||||
|
||||
// Internal
|
||||
// Returns the index of c in the alphanumeric charset (0-44), or -1 if not found.
|
||||
@(private)
|
||||
alphanumeric_index :: proc(c: u8) -> int {
|
||||
switch c {
|
||||
case '0' ..= '9': return int(c - '0')
|
||||
@@ -2487,7 +2500,7 @@ test_min_buffer_size_text :: proc(t: ^testing.T) {
|
||||
testing.expect(t, planned > 0)
|
||||
qrcode: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok := encode_text(text, temp[:], qrcode[:], Ecc.Low)
|
||||
ok := encode_text_manual(text, temp[:], qrcode[:], Ecc.Low)
|
||||
testing.expect(t, ok)
|
||||
actual_version_size := get_size(qrcode[:])
|
||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||
@@ -2538,7 +2551,7 @@ test_min_buffer_size_binary :: proc(t: ^testing.T) {
|
||||
testing.expect(t, size > 0)
|
||||
testing.expect(t, size <= buffer_len_for_version(2))
|
||||
|
||||
// Verify agreement with encode_binary
|
||||
// Verify agreement with encode_binary_manual
|
||||
{
|
||||
data_len :: 100
|
||||
planned, planned_ok := min_buffer_size(data_len, .Medium)
|
||||
@@ -2549,7 +2562,7 @@ test_min_buffer_size_binary :: proc(t: ^testing.T) {
|
||||
for i in 0 ..< data_len {
|
||||
dat[i] = u8(i)
|
||||
}
|
||||
ok := encode_binary(dat[:], data_len, qrcode[:], .Medium)
|
||||
ok := encode_binary_manual(dat[:], data_len, qrcode[:], .Medium)
|
||||
testing.expect(t, ok)
|
||||
actual_version_size := get_size(qrcode[:])
|
||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||
@@ -2609,7 +2622,7 @@ test_min_buffer_size_segments :: proc(t: ^testing.T) {
|
||||
// Verify against actual encode
|
||||
qrcode: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok := encode_segments(segs[:], Ecc.Low, temp[:], qrcode[:])
|
||||
ok := encode_segments_manual(segs[:], Ecc.Low, temp[:], qrcode[:])
|
||||
testing.expect(t, ok)
|
||||
actual_version_size := get_size(qrcode[:])
|
||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||
@@ -2631,7 +2644,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
||||
text :: "Hello, world!"
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_text_explicit_temp(text, temp[:], qr_explicit[:], .Low)
|
||||
ok_explicit := encode_text_manual(text, temp[:], qr_explicit[:], .Low)
|
||||
testing.expect(t, ok_explicit)
|
||||
|
||||
qr_auto: [BUFFER_LEN_MAX]u8
|
||||
@@ -2650,7 +2663,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
||||
text :: "314159265358979323846264338327950288419716939937510"
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_text_explicit_temp(text, temp[:], qr_explicit[:], .Medium)
|
||||
ok_explicit := encode_text_manual(text, temp[:], qr_explicit[:], .Medium)
|
||||
testing.expect(t, ok_explicit)
|
||||
|
||||
qr_auto: [BUFFER_LEN_MAX]u8
|
||||
@@ -2669,7 +2682,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
||||
text :: "HELLO WORLD"
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_text_explicit_temp(text, temp[:], qr_explicit[:], .Quartile)
|
||||
ok_explicit := encode_text_manual(text, temp[:], qr_explicit[:], .Quartile)
|
||||
testing.expect(t, ok_explicit)
|
||||
|
||||
qr_auto: [BUFFER_LEN_MAX]u8
|
||||
@@ -2695,7 +2708,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
||||
text :: "https://www.nayuki.io/"
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_text_explicit_temp(text, temp[:], qr_explicit[:], .High, mask = .M3)
|
||||
ok_explicit := encode_text_manual(text, temp[:], qr_explicit[:], .High, mask = .M3)
|
||||
testing.expect(t, ok_explicit)
|
||||
|
||||
qr_auto: [BUFFER_LEN_MAX]u8
|
||||
@@ -2732,7 +2745,7 @@ test_encode_segments_auto :: proc(t: ^testing.T) {
|
||||
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_segments_explicit_temp(segs[:], .Low, temp[:], qr_explicit[:])
|
||||
ok_explicit := encode_segments_manual(segs[:], .Low, temp[:], qr_explicit[:])
|
||||
testing.expect(t, ok_explicit)
|
||||
|
||||
qr_auto: [BUFFER_LEN_MAX]u8
|
||||
@@ -2764,7 +2777,7 @@ test_encode_segments_advanced_auto :: proc(t: ^testing.T) {
|
||||
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_segments_advanced_explicit_temp(
|
||||
ok_explicit := encode_segments_advanced_manual(
|
||||
segs[:],
|
||||
.Medium,
|
||||
VERSION_MIN,
|
||||
@@ -2795,7 +2808,7 @@ test_encode_segments_advanced_auto :: proc(t: ^testing.T) {
|
||||
|
||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||
temp: [BUFFER_LEN_MAX]u8
|
||||
ok_explicit := encode_segments_advanced_explicit_temp(
|
||||
ok_explicit := encode_segments_advanced_manual(
|
||||
segs[:],
|
||||
.High,
|
||||
1,
|
||||
|
||||
Reference in New Issue
Block a user