QR code improvements
This commit is contained in:
@@ -3,76 +3,188 @@ package draw_qr
|
|||||||
import draw ".."
|
import draw ".."
|
||||||
import "../../qrcode"
|
import "../../qrcode"
|
||||||
|
|
||||||
// A registered QR code texture, ready for display via draw.rectangle_texture.
|
// -----------------------------------------------------------------------------
|
||||||
QR :: struct {
|
// Layer 1 — pure: encoded QR buffer → RGBA pixels + descriptor
|
||||||
texture_id: draw.Texture_Id,
|
// -----------------------------------------------------------------------------
|
||||||
size: int, // modules per side (e.g. 21..177)
|
|
||||||
|
// Returns the number of bytes to_texture will write for the given encoded
|
||||||
|
// QR buffer. Equivalent to size*size*4 where size = qrcode.get_size(qrcode_buf).
|
||||||
|
texture_size :: #force_inline proc(qrcode_buf: []u8) -> int {
|
||||||
|
size := qrcode.get_size(qrcode_buf)
|
||||||
|
return size * size * 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode text as a QR code and register the result as an R8 texture.
|
// Decodes an encoded QR buffer into tightly-packed RGBA pixel data written to
|
||||||
// The texture uses Nearest_Clamp sampling by default (sharp module edges).
|
// texture_buf. No allocations, no GPU calls. Returns the Texture_Desc the
|
||||||
// Returns ok=false if encoding or registration fails.
|
// caller should pass to draw.register_texture alongside texture_buf.
|
||||||
|
//
|
||||||
|
// Returns ok=false when:
|
||||||
|
// - qrcode_buf is invalid (qrcode.get_size returns 0).
|
||||||
|
// - texture_buf is smaller than to_texture_size(qrcode_buf).
|
||||||
@(require_results)
|
@(require_results)
|
||||||
create_from_text :: proc(
|
to_texture :: proc(
|
||||||
|
qrcode_buf: []u8,
|
||||||
|
texture_buf: []u8,
|
||||||
|
dark: draw.Color = draw.BLACK,
|
||||||
|
light: draw.Color = draw.WHITE,
|
||||||
|
) -> (
|
||||||
|
desc: draw.Texture_Desc,
|
||||||
|
ok: bool,
|
||||||
|
) {
|
||||||
|
size := qrcode.get_size(qrcode_buf)
|
||||||
|
if size == 0 do return {}, false
|
||||||
|
if len(texture_buf) < size * size * 4 do return {}, false
|
||||||
|
|
||||||
|
for y in 0 ..< size {
|
||||||
|
for x in 0 ..< size {
|
||||||
|
i := (y * size + x) * 4
|
||||||
|
c := dark if qrcode.get_module(qrcode_buf, x, y) else light
|
||||||
|
texture_buf[i + 0] = c[0]
|
||||||
|
texture_buf[i + 1] = c[1]
|
||||||
|
texture_buf[i + 2] = c[2]
|
||||||
|
texture_buf[i + 3] = c[3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return draw.Texture_Desc {
|
||||||
|
width = u32(size),
|
||||||
|
height = u32(size),
|
||||||
|
depth_or_layers = 1,
|
||||||
|
type = .D2,
|
||||||
|
format = .R8G8B8A8_UNORM,
|
||||||
|
usage = {.SAMPLER},
|
||||||
|
mip_levels = 1,
|
||||||
|
kind = .Static,
|
||||||
|
},
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Layer 2 — raw: pre-encoded QR buffer → registered GPU texture
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Allocates pixel buffer via temp_allocator, decodes qrcode_buf into it, and
|
||||||
|
// registers with the GPU. The pixel allocation is freed before return.
|
||||||
|
//
|
||||||
|
// Returns ok=false when:
|
||||||
|
// - qrcode_buf is invalid (qrcode.get_size returns 0).
|
||||||
|
// - temp_allocator fails to allocate the pixel buffer.
|
||||||
|
// - GPU texture registration fails.
|
||||||
|
@(require_results)
|
||||||
|
register_texture_from_raw :: proc(
|
||||||
|
qrcode_buf: []u8,
|
||||||
|
dark: draw.Color = draw.BLACK,
|
||||||
|
light: draw.Color = draw.WHITE,
|
||||||
|
temp_allocator := context.temp_allocator,
|
||||||
|
) -> (
|
||||||
|
texture: draw.Texture_Id,
|
||||||
|
ok: bool,
|
||||||
|
) {
|
||||||
|
tex_size := texture_size(qrcode_buf)
|
||||||
|
if tex_size == 0 do return draw.INVALID_TEXTURE, false
|
||||||
|
|
||||||
|
pixels, alloc_err := make([]u8, tex_size, temp_allocator)
|
||||||
|
if alloc_err != nil do return draw.INVALID_TEXTURE, false
|
||||||
|
defer delete(pixels, temp_allocator)
|
||||||
|
|
||||||
|
desc := to_texture(qrcode_buf, pixels, dark, light) or_return
|
||||||
|
return draw.register_texture(desc, pixels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Layer 3 — text → registered GPU texture
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Encodes text as a QR Code and registers the result as an RGBA texture.
|
||||||
|
//
|
||||||
|
// Returns ok=false when:
|
||||||
|
// - temp_allocator fails to allocate.
|
||||||
|
// - The text cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||||
|
// - GPU texture registration fails.
|
||||||
|
@(require_results)
|
||||||
|
register_texture_from_text :: proc(
|
||||||
text: string,
|
text: string,
|
||||||
ecl: qrcode.Ecc = .Low,
|
ecl: qrcode.Ecc = .Low,
|
||||||
min_version: int = qrcode.VERSION_MIN,
|
min_version: int = qrcode.VERSION_MIN,
|
||||||
max_version: int = qrcode.VERSION_MAX,
|
max_version: int = qrcode.VERSION_MAX,
|
||||||
mask: Maybe(qrcode.Mask) = nil,
|
mask: Maybe(qrcode.Mask) = nil,
|
||||||
boost_ecl: bool = true,
|
boost_ecl: bool = true,
|
||||||
|
dark: draw.Color = draw.BLACK,
|
||||||
|
light: draw.Color = draw.WHITE,
|
||||||
|
temp_allocator := context.temp_allocator,
|
||||||
) -> (
|
) -> (
|
||||||
qr: QR,
|
texture: draw.Texture_Id,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
) {
|
) {
|
||||||
qrcode_buf: [qrcode.BUFFER_LEN_MAX]u8
|
qrcode_buf, alloc_err := make([]u8, qrcode.buffer_len_for_version(max_version), temp_allocator)
|
||||||
encode_ok := qrcode.encode(text, qrcode_buf[:], ecl, min_version, max_version, mask, boost_ecl)
|
if alloc_err != nil do return draw.INVALID_TEXTURE, false
|
||||||
if !encode_ok do return {}, false
|
defer delete(qrcode_buf, temp_allocator)
|
||||||
return create(qrcode_buf[:])
|
|
||||||
|
qrcode.encode_auto(
|
||||||
|
text,
|
||||||
|
qrcode_buf,
|
||||||
|
ecl,
|
||||||
|
min_version,
|
||||||
|
max_version,
|
||||||
|
mask,
|
||||||
|
boost_ecl,
|
||||||
|
temp_allocator,
|
||||||
|
) or_return
|
||||||
|
|
||||||
|
return register_texture_from_raw(qrcode_buf, dark, light, temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register an already-encoded QR code buffer as an R8 texture.
|
// -----------------------------------------------------------------------------
|
||||||
// qrcode_buf must be the output of qrcode.encode (byte 0 = side length, remaining = bit-packed modules).
|
// Layer 4 — binary → registered GPU texture
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Encodes arbitrary binary data as a QR Code and registers the result as an RGBA texture.
|
||||||
|
//
|
||||||
|
// Returns ok=false when:
|
||||||
|
// - temp_allocator fails to allocate.
|
||||||
|
// - The payload cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||||
|
// - GPU texture registration fails.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
create :: proc(qrcode_buf: []u8) -> (qr: QR, ok: bool) {
|
register_texture_from_binary :: proc(
|
||||||
size := qrcode.get_size(qrcode_buf)
|
bin_data: []u8,
|
||||||
if size == 0 do return {}, false
|
ecl: qrcode.Ecc = .Low,
|
||||||
|
min_version: int = qrcode.VERSION_MIN,
|
||||||
|
max_version: int = qrcode.VERSION_MAX,
|
||||||
|
mask: Maybe(qrcode.Mask) = nil,
|
||||||
|
boost_ecl: bool = true,
|
||||||
|
dark: draw.Color = draw.BLACK,
|
||||||
|
light: draw.Color = draw.WHITE,
|
||||||
|
temp_allocator := context.temp_allocator,
|
||||||
|
) -> (
|
||||||
|
texture: draw.Texture_Id,
|
||||||
|
ok: bool,
|
||||||
|
) {
|
||||||
|
qrcode_buf, alloc_err := make([]u8, qrcode.buffer_len_for_version(max_version), temp_allocator)
|
||||||
|
if alloc_err != nil do return draw.INVALID_TEXTURE, false
|
||||||
|
defer delete(qrcode_buf, temp_allocator)
|
||||||
|
|
||||||
// Build R8 pixel buffer: 0 = light, 255 = dark
|
qrcode.encode_auto(
|
||||||
pixels := make([]u8, size * size, context.temp_allocator)
|
bin_data,
|
||||||
for y in 0 ..< size {
|
qrcode_buf,
|
||||||
for x in 0 ..< size {
|
ecl,
|
||||||
pixels[y * size + x] = 255 if qrcode.get_module(qrcode_buf, x, y) else 0
|
min_version,
|
||||||
}
|
max_version,
|
||||||
}
|
mask,
|
||||||
|
boost_ecl,
|
||||||
|
temp_allocator,
|
||||||
|
) or_return
|
||||||
|
|
||||||
id, reg_ok := draw.register_texture(
|
return register_texture_from_raw(qrcode_buf, dark, light, temp_allocator)
|
||||||
draw.Texture_Desc {
|
|
||||||
width = u32(size),
|
|
||||||
height = u32(size),
|
|
||||||
depth_or_layers = 1,
|
|
||||||
type = .D2,
|
|
||||||
format = .R8_UNORM,
|
|
||||||
usage = {.SAMPLER},
|
|
||||||
mip_levels = 1,
|
|
||||||
kind = .Static,
|
|
||||||
},
|
|
||||||
pixels,
|
|
||||||
)
|
|
||||||
if !reg_ok do return {}, false
|
|
||||||
|
|
||||||
return QR{texture_id = id, size = size}, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the GPU texture.
|
// -----------------------------------------------------------------------------
|
||||||
destroy :: proc(qr: ^QR) {
|
// Clay integration helper
|
||||||
draw.unregister_texture(qr.texture_id)
|
// -----------------------------------------------------------------------------
|
||||||
qr.texture_id = draw.INVALID_TEXTURE
|
|
||||||
qr.size = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convenience: build a Clay_Image_Data for embedding a QR in Clay layouts.
|
// Default fit=.Fit preserves the QR's square aspect; override as needed.
|
||||||
// Uses Nearest_Clamp sampling (set via Sampler_Preset at draw time, not here) and Fit mode
|
clay_image :: #force_inline proc(
|
||||||
// to preserve the QR's square aspect ratio.
|
texture: draw.Texture_Id,
|
||||||
clay_image :: proc(qr: QR, tint: draw.Color = draw.WHITE) -> draw.Clay_Image_Data {
|
tint: draw.Color = draw.WHITE,
|
||||||
return draw.clay_image_data(qr.texture_id, fit = .Fit, tint = tint)
|
) -> draw.Clay_Image_Data {
|
||||||
|
return draw.clay_image_data(texture, fit = .Fit, tint = tint)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ textures :: proc() {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// QR code texture (R8_UNORM — see rendering note below)
|
// QR code texture (R8_UNORM — see rendering note below)
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
qr, _ := draw_qr.create_from_text("https://odin-lang.org/")
|
qr_texture, _ := draw_qr.register_texture_from_text("https://x.com/miiilato/status/1880241066471051443")
|
||||||
defer draw_qr.destroy(&qr)
|
defer draw.unregister_texture(qr_texture)
|
||||||
|
|
||||||
spin_angle: f32 = 0
|
spin_angle: f32 = 0
|
||||||
|
|
||||||
@@ -161,16 +161,12 @@ textures :: proc() {
|
|||||||
// =====================================================================
|
// =====================================================================
|
||||||
ROW2_Y :: f32(190)
|
ROW2_Y :: f32(190)
|
||||||
|
|
||||||
// QR code (R8_UNORM texture, nearest sampling)
|
// QR code (RGBA texture with baked colors, nearest sampling)
|
||||||
// NOTE: R8_UNORM samples as (r, 0, 0, 1) in Metal's default swizzle.
|
|
||||||
// With WHITE tint: dark modules (R=1) → red, light modules (R=0) → black.
|
|
||||||
// The result is a red-on-black QR code. The white bg rect below is
|
|
||||||
// occluded by the fully-opaque texture but kept for illustration.
|
|
||||||
draw.rectangle(base_layer, {COL1, ROW2_Y, ITEM_SIZE, ITEM_SIZE}, {255, 255, 255, 255}) // white bg
|
draw.rectangle(base_layer, {COL1, ROW2_Y, ITEM_SIZE, ITEM_SIZE}, {255, 255, 255, 255}) // white bg
|
||||||
draw.rectangle_texture(
|
draw.rectangle_texture(
|
||||||
base_layer,
|
base_layer,
|
||||||
{COL1, ROW2_Y, ITEM_SIZE, ITEM_SIZE},
|
{COL1, ROW2_Y, ITEM_SIZE, ITEM_SIZE},
|
||||||
qr.texture_id,
|
qr_texture,
|
||||||
sampler = .Nearest_Clamp,
|
sampler = .Nearest_Clamp,
|
||||||
)
|
)
|
||||||
draw.text(
|
draw.text(
|
||||||
|
|||||||
@@ -117,7 +117,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 text cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||||
// - The encoded segment data exceeds the buffer capacity.
|
// - The encoded segment data exceeds the buffer capacity.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
encode_text_explicit_temp :: proc(
|
encode_text_manual :: proc(
|
||||||
text: string,
|
text: string,
|
||||||
temp_buffer, qrcode: []u8,
|
temp_buffer, qrcode: []u8,
|
||||||
ecl: Ecc,
|
ecl: Ecc,
|
||||||
@@ -130,7 +130,7 @@ encode_text_explicit_temp :: proc(
|
|||||||
) {
|
) {
|
||||||
text_len := len(text)
|
text_len := len(text)
|
||||||
if text_len == 0 {
|
if text_len == 0 {
|
||||||
return encode_segments_advanced_explicit_temp(
|
return encode_segments_advanced_manual(
|
||||||
nil,
|
nil,
|
||||||
ecl,
|
ecl,
|
||||||
min_version,
|
min_version,
|
||||||
@@ -162,7 +162,7 @@ encode_text_explicit_temp :: proc(
|
|||||||
seg.data = temp_buffer[:text_len]
|
seg.data = temp_buffer[:text_len]
|
||||||
}
|
}
|
||||||
segs := [1]Segment{seg}
|
segs := [1]Segment{seg}
|
||||||
return encode_segments_advanced_explicit_temp(
|
return encode_segments_advanced_manual(
|
||||||
segs[:],
|
segs[:],
|
||||||
ecl,
|
ecl,
|
||||||
min_version,
|
min_version,
|
||||||
@@ -211,13 +211,9 @@ encode_text_auto :: proc(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer delete(temp_buffer, temp_allocator)
|
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.
|
// Encodes arbitrary binary data to a QR Code using byte mode.
|
||||||
//
|
//
|
||||||
@@ -234,7 +230,7 @@ encode_text :: proc {
|
|||||||
// Returns ok=false when:
|
// Returns ok=false when:
|
||||||
// - The payload cannot fit in any version within [min_version, max_version] at the given ECL.
|
// - The payload cannot fit in any version within [min_version, max_version] at the given ECL.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
encode_binary :: proc(
|
encode_binary_manual :: proc(
|
||||||
data_and_temp: []u8,
|
data_and_temp: []u8,
|
||||||
data_len: int,
|
data_len: int,
|
||||||
qrcode: []u8,
|
qrcode: []u8,
|
||||||
@@ -256,7 +252,7 @@ encode_binary :: proc(
|
|||||||
seg.num_chars = data_len
|
seg.num_chars = data_len
|
||||||
seg.data = data_and_temp[:data_len]
|
seg.data = data_and_temp[:data_len]
|
||||||
segs := [1]Segment{seg}
|
segs := [1]Segment{seg}
|
||||||
return encode_segments_advanced(
|
return encode_segments_advanced_manual(
|
||||||
segs[:],
|
segs[:],
|
||||||
ecl,
|
ecl,
|
||||||
min_version,
|
min_version,
|
||||||
@@ -268,6 +264,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
|
// Encodes the given segments to a QR Code using default parameters
|
||||||
// (VERSION_MIN..VERSION_MAX, auto mask, boost ECL).
|
// (VERSION_MIN..VERSION_MAX, auto mask, boost ECL).
|
||||||
//
|
//
|
||||||
@@ -282,17 +327,8 @@ encode_binary :: proc(
|
|||||||
// Returns ok=false when:
|
// Returns ok=false when:
|
||||||
// - The total segment data exceeds the capacity of version 40 at the given ECL.
|
// - The total segment data exceeds the capacity of version 40 at the given ECL.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
encode_segments_explicit_temp :: proc(segs: []Segment, ecl: Ecc, temp_buffer, qrcode: []u8) -> (ok: bool) {
|
encode_segments_manual :: proc(segs: []Segment, ecl: Ecc, temp_buffer, qrcode: []u8) -> (ok: bool) {
|
||||||
return encode_segments_advanced_explicit_temp(
|
return encode_segments_advanced_manual(segs, ecl, VERSION_MIN, VERSION_MAX, nil, true, temp_buffer, qrcode)
|
||||||
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.
|
// Encodes segments to a QR Code using default parameters, automatically allocating the temp buffer.
|
||||||
@@ -328,13 +364,9 @@ encode_segments_auto :: proc(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer delete(temp_buffer, temp_allocator)
|
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.
|
// Encodes the given segments to a QR Code with full control over version range, mask, and ECL boosting.
|
||||||
//
|
//
|
||||||
@@ -353,7 +385,7 @@ encode_segments :: proc {
|
|||||||
// - The total segment data exceeds the capacity of every version in [min_version, max_version]
|
// - The total segment data exceeds the capacity of every version in [min_version, max_version]
|
||||||
// at the given ECL.
|
// at the given ECL.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
encode_segments_advanced_explicit_temp :: proc(
|
encode_segments_advanced_manual :: proc(
|
||||||
segs: []Segment,
|
segs: []Segment,
|
||||||
ecl: Ecc,
|
ecl: Ecc,
|
||||||
min_version, max_version: int,
|
min_version, max_version: int,
|
||||||
@@ -490,7 +522,7 @@ encode_segments_advanced_auto :: proc(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer delete(temp_buffer, temp_allocator)
|
defer delete(temp_buffer, temp_allocator)
|
||||||
return encode_segments_advanced_explicit_temp(
|
return encode_segments_advanced_manual(
|
||||||
segs,
|
segs,
|
||||||
ecl,
|
ecl,
|
||||||
min_version,
|
min_version,
|
||||||
@@ -502,18 +534,17 @@ encode_segments_advanced_auto :: proc(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
encode_segments_advanced :: proc {
|
encode_manual :: proc {
|
||||||
encode_segments_advanced_explicit_temp,
|
encode_text_manual,
|
||||||
encode_segments_advanced_auto,
|
encode_binary_manual,
|
||||||
|
encode_segments_manual,
|
||||||
|
encode_segments_advanced_manual,
|
||||||
}
|
}
|
||||||
|
|
||||||
encode :: proc {
|
encode_auto :: proc {
|
||||||
encode_text_explicit_temp,
|
|
||||||
encode_text_auto,
|
encode_text_auto,
|
||||||
encode_binary,
|
encode_binary_auto,
|
||||||
encode_segments_explicit_temp,
|
|
||||||
encode_segments_auto,
|
encode_segments_auto,
|
||||||
encode_segments_advanced_explicit_temp,
|
|
||||||
encode_segments_advanced_auto,
|
encode_segments_advanced_auto,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +1012,7 @@ min_buffer_size :: proc {
|
|||||||
min_buffer_size_segments,
|
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:
|
// Returns ok=false when:
|
||||||
// - The text exceeds QR Code capacity for every version in the range at the given ECL.
|
// - The text exceeds QR Code capacity for every version in the range at the given ECL.
|
||||||
@@ -1162,7 +1193,6 @@ calc_segment_buffer_size :: proc(mode: Mode, num_chars: int) -> int {
|
|||||||
return (temp + 7) / 8
|
return (temp + 7) / 8
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
|
||||||
calc_segment_bit_length :: proc(mode: Mode, num_chars: int) -> int {
|
calc_segment_bit_length :: proc(mode: Mode, num_chars: int) -> int {
|
||||||
if num_chars < 0 || num_chars > 32767 {
|
if num_chars < 0 || num_chars > 32767 {
|
||||||
return LENGTH_OVERFLOW
|
return LENGTH_OVERFLOW
|
||||||
@@ -2487,7 +2517,7 @@ test_min_buffer_size_text :: proc(t: ^testing.T) {
|
|||||||
testing.expect(t, planned > 0)
|
testing.expect(t, planned > 0)
|
||||||
qrcode: [BUFFER_LEN_MAX]u8
|
qrcode: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok)
|
||||||
actual_version_size := get_size(qrcode[:])
|
actual_version_size := get_size(qrcode[:])
|
||||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||||
@@ -2538,7 +2568,7 @@ test_min_buffer_size_binary :: proc(t: ^testing.T) {
|
|||||||
testing.expect(t, size > 0)
|
testing.expect(t, size > 0)
|
||||||
testing.expect(t, size <= buffer_len_for_version(2))
|
testing.expect(t, size <= buffer_len_for_version(2))
|
||||||
|
|
||||||
// Verify agreement with encode_binary
|
// Verify agreement with encode_binary_manual
|
||||||
{
|
{
|
||||||
data_len :: 100
|
data_len :: 100
|
||||||
planned, planned_ok := min_buffer_size(data_len, .Medium)
|
planned, planned_ok := min_buffer_size(data_len, .Medium)
|
||||||
@@ -2549,7 +2579,7 @@ test_min_buffer_size_binary :: proc(t: ^testing.T) {
|
|||||||
for i in 0 ..< data_len {
|
for i in 0 ..< data_len {
|
||||||
dat[i] = u8(i)
|
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)
|
testing.expect(t, ok)
|
||||||
actual_version_size := get_size(qrcode[:])
|
actual_version_size := get_size(qrcode[:])
|
||||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||||
@@ -2609,7 +2639,7 @@ test_min_buffer_size_segments :: proc(t: ^testing.T) {
|
|||||||
// Verify against actual encode
|
// Verify against actual encode
|
||||||
qrcode: [BUFFER_LEN_MAX]u8
|
qrcode: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok)
|
||||||
actual_version_size := get_size(qrcode[:])
|
actual_version_size := get_size(qrcode[:])
|
||||||
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
actual_buf_len := buffer_len_for_version((actual_version_size - 17) / 4)
|
||||||
@@ -2631,7 +2661,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
|||||||
text :: "Hello, world!"
|
text :: "Hello, world!"
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok_explicit)
|
||||||
|
|
||||||
qr_auto: [BUFFER_LEN_MAX]u8
|
qr_auto: [BUFFER_LEN_MAX]u8
|
||||||
@@ -2650,7 +2680,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
|||||||
text :: "314159265358979323846264338327950288419716939937510"
|
text :: "314159265358979323846264338327950288419716939937510"
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok_explicit)
|
||||||
|
|
||||||
qr_auto: [BUFFER_LEN_MAX]u8
|
qr_auto: [BUFFER_LEN_MAX]u8
|
||||||
@@ -2669,7 +2699,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
|||||||
text :: "HELLO WORLD"
|
text :: "HELLO WORLD"
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok_explicit)
|
||||||
|
|
||||||
qr_auto: [BUFFER_LEN_MAX]u8
|
qr_auto: [BUFFER_LEN_MAX]u8
|
||||||
@@ -2695,7 +2725,7 @@ test_encode_text_auto :: proc(t: ^testing.T) {
|
|||||||
text :: "https://www.nayuki.io/"
|
text :: "https://www.nayuki.io/"
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok_explicit)
|
||||||
|
|
||||||
qr_auto: [BUFFER_LEN_MAX]u8
|
qr_auto: [BUFFER_LEN_MAX]u8
|
||||||
@@ -2732,7 +2762,7 @@ test_encode_segments_auto :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [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)
|
testing.expect(t, ok_explicit)
|
||||||
|
|
||||||
qr_auto: [BUFFER_LEN_MAX]u8
|
qr_auto: [BUFFER_LEN_MAX]u8
|
||||||
@@ -2764,7 +2794,7 @@ test_encode_segments_advanced_auto :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [BUFFER_LEN_MAX]u8
|
temp: [BUFFER_LEN_MAX]u8
|
||||||
ok_explicit := encode_segments_advanced_explicit_temp(
|
ok_explicit := encode_segments_advanced_manual(
|
||||||
segs[:],
|
segs[:],
|
||||||
.Medium,
|
.Medium,
|
||||||
VERSION_MIN,
|
VERSION_MIN,
|
||||||
@@ -2795,7 +2825,7 @@ test_encode_segments_advanced_auto :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
qr_explicit: [BUFFER_LEN_MAX]u8
|
qr_explicit: [BUFFER_LEN_MAX]u8
|
||||||
temp: [BUFFER_LEN_MAX]u8
|
temp: [BUFFER_LEN_MAX]u8
|
||||||
ok_explicit := encode_segments_advanced_explicit_temp(
|
ok_explicit := encode_segments_advanced_manual(
|
||||||
segs[:],
|
segs[:],
|
||||||
.High,
|
.High,
|
||||||
1,
|
1,
|
||||||
|
|||||||
Reference in New Issue
Block a user