go-qrcode

repository·main·Indexed 21 days ago

https://github.com/yeqown/go-qrcode

A highly customizable Go library for generating QR codes (versions 1-40). It supports various encoding modes, error correction levels, custom cell shapes, logos, and multiple output formats including files, terminal, and WebAssembly. The library includes a CLI tool and specialized writers such as standard, terminal, file, and compressed.

Tokens
17.7K
Snippets
69
Records
91
Agent score
74%

What's inside go-qrcode

  1. Understanding Kanji Encoding Mode in QR Codes

    main

    Kanji mode is a specialized encoding mode in QR Codes designed to efficiently encode Japanese Kanji characters using the Shift JIS (JIS X 0208) character set. It is significantly more compact than byte mode, reducing QR Code size for Japanese text by approximately 50%.

    Key Specifications

    • Mode Indicator: 1000 (4 bits)
    • Bits per Character: 13 bits
    • Character Encoding: Shift JIS (JIS X 0208)

    Benefits

    • Compactness: Each Kanji character is encoded in 13 bits, compared to 16 bits in UTF-16 or 8 bytes per character in UTF-8.
    • Efficiency: Optimized specifically for the Japanese writing system to minimize storage requirements.
  2. How Kanji Encoding Algorithm Works

    main

    The encoding process transforms Unicode Kanji characters into a compressed 13-bit representation using their Shift JIS values.

    Encoding Steps

    1. Convert: Transform the Unicode character to its 2-byte Shift JIS representation.
    2. Adjust: Apply an adjustment formula based on the Shift JIS range.
    3. Split: Separate the adjusted value into high and low bytes.
    4. Encode: Calculate the final 13-bit value using the formula: (high × 0xC0) + low.

    Mathematical Formula

    Given a Shift JIS code code (2 bytes):

    // Step 1: Adjust the base
    if (code >= 0x8140 && code <= 0x9FFC) {
        adjusted = code - 0x8140
    } else if (code >= 0xE040 && code <= 0xEBBF) {
        adjusted = code - 0xC140
    }
    
    // Step 2: Split into high and low bytes
    high = adjusted >> 8      // Upper byte
    low = adjusted & 0xFF     // Lower byte
    
    // Step 3: Calculate encoded value (13-bit result)
    encoded = (high * 0xC0) + low
    // Step 1: Adjust the base
    if (code >= 0x8140 && code <= 0x9FFC) {
        adjusted = code - 0x8140
    } else if (code >= 0xE040 && code <= 0xEBBF) {
        adjusted = code - 0xC140
    }
    
    // Step 2: Split into high and low bytes
    high = adjusted >> 8      // Upper byte
    low = adjusted & 0xFF     // Lower byte
    
    // Step 3: Calculate encoded value (13-bit result)
    encoded = (high * 0xC0) + low
  3. Understand the Writer interface

    main

    The qrcode.Writer interface defines how a QR code's matrix is rendered or output to a destination (such as a file or a terminal). To use a writer, you must call its Write method with a matrix.Matrix and ensure you call Close if the writer manages an open stream.

    // Writer is the interface of a QR code writer, it defines the rule of how to
    // `print` the code image from matrix. There's built-in writer to output into
    // file, terminal.
    type Writer interface {
    	// Write writes the code image into itself stream, such as io.Writer, 
    	// terminal output stream, and etc
    	Write(mat matrix.Matrix) error
    	
    	// Close the writer stream if it exists after QRCode.Save() is called.
    	Close() error
    }
  4. Use go-qrcode in WebAssembly

    main

    When running go-qrcode in a WebAssembly environment, you can use the generateQRCode function to create QR codes. The function accepts a content string and an options object, returning a JSON object containing the success status, any error messages, and the resulting image as a Base64 encoded string.

    Options Object Schema

    KeyTypeDescription
    encodeVersionnumberQR version (0 - 40)
    encodeModenumberEncoding mode (0 - 3)
    encodeECLevelstringError correction level (L, M, Q, or H)
    outputBgColorstringBackground color hex code (#000000 - #ffffff)
    outputBgTransparentbooleanWhether the background is transparent
    outputQrColorstringQR code color hex code (#000000 - #ffffff)
    outputQrWidthnumberWidth of the QR code (0 - 256)
    outputCircleShapebooleanWhether to use a circular shape
    outputImageEncoderstringImage format (png, jpeg, or jpg)
    outputMarginnumberMargin size (0 - 256)
    let option = {
    	encodeVersion: 0,   // 0 - 40
    	encodeMode: 2,      // 0 - 3
    	encodeECLevel: "Q", // L, M, Q, H
    	
    	outputBgColor: "#123123",   // #000000 - #ffffff
    	outputBgTransparent: false, // true - false
    	outputQrColor: "#666666",   // #000000 - #ffffff
    	outputQrWidth: 20,          // 0 - 256
    	outputCircleShape: true,    // true - false
    	outputImageEncoder: "png",  // png, jpeg, jpg
    	outputMargin: 20,           // 0 - 256
    }
    let r = generateQRCode("content", option)
    // output:
    // {
    //     "success": true,
    //     "error": "",
    //     "base64EncodedImage": "iVBORw0KGgoAAAANSUhEUgAAAmwAAAJ... more"
    // }
  5. Use the `qrcode` CLI to generate QR codes

    main

    The qrcode command-line application allows you to generate QR codes from source text. By default, it generates a QR code and saves it to a file named qrcode.jpg.

    # Generate a QR code into file as default
    qrcode "Hello, World!"
  6. Draw QR Codes in the terminal using Terminal Writer

    main

    The terminal writer allows you to render QR Code images directly into your terminal interface. It implements the Writer interface from the v2 package.

    To use it, create a new QR code using qrcode.New, instantiate the terminal writer with terminal.New(), and pass it to the qrc.Save() method.

    package main
    
    import (
    	"github.com/yeqown/go-qrcode/v2"
    	"github.com/yeqown/go-qrcode/writer/terminal"
    )
    
    func main() {
    	// Create a new QR code with content
    	qrc, _ := qrcode.New("withTerminalWriter")
    
    	// Initialize the terminal writer
    	w := terminal.New()
    
    	// Render the QR code to the terminal
    	if err := qrc.Save(w); err != nil {
    		panic(err)
    	}
    }
  7. Use the File Writer to save QR Codes

    main

    The file writer is used to draw QR Code images into files using specific characters: , , , and space. It is designed to represent the QR code structure using these characters within a file-based output.

    package main
    
    import (
    	"os"
    	"github.com/yeqown/go-qrcode/v2"
    	"github.com/yeqown/go-qrcode/writer/file"
    )
    
    func main() {
    	// Create a new QR code with the specified content
    	qrc, _ := qrcode.New("with_file_writer")
    
    	// Initialize the File Writer with an output destination (e.g., os.Stdout or an os.File)
    	w := file.New(os.Stdout)
    
    	// Save the QR code using the writer
    	if err := qrc.Save(w); err != nil {
    		panic(err)
    	}
    }
  8. Detecting if a character is eligible for Kanji Mode

    main

    To determine if a character can be encoded using Kanji mode, it must satisfy several criteria. This is particularly important when deciding whether to use Kanji mode or fall back to byte mode (UTF-8).

    Detection Criteria

    1. Kanji Check: The character must be in the Japanese Kanji Unicode ranges (e.g., CJK Unified Ideographs U+4E00-U+9FFF).
    2. Shift JIS Conversion: The character must successfully convert to a 2-byte Shift JIS representation.
    3. Range Validation: The resulting Shift JIS code must fall within:
      • 0x8140 to 0x9FFC OR
      • 0xE040 to 0xEBBF

    Automatic Mode Selection Logic

    Use Kanji mode only if ALL characters in the data are valid Kanji characters that meet the criteria above. If any character fails validation (e.g., Hiragana, Katakana, or rare Kanji outside the ranges), you must fall back to a compatible mode like byte mode with UTF-8.

    Implementation Logic

    IsKanji(character) {
        shiftJIS = UnicodeToShiftJIS(character)
    
        if (shiftJIS.length != 2) {
            return false
        }
    
        code = (shiftJIS[0] << 8) | shiftJIS[1]
    
        return (code >= 0x8140 && code <= 0x9FFC) ||
               (code >= 0xE040 && code <= 0xEBBF)
    }
    IsKanji(character) {
        shiftJIS = UnicodeToShiftJIS(character)
    
        if (shiftJIS.length != 2) {
            return false
        }
    
        code = (shiftJIS[0] << 8) | shiftJIS[1]
    
        return (code >= 0x8140 && code <= 0x9FFC) ||
               (code >= 0xE040 && code <= 0xEBBF)
    }
  9. Migrating from v1 to v2

    main

    The v2 release is a major upgrade and is not backward compatible. The API has been redesigned for better flexibility, and features are now split into specialized modules:

    • Core logic: github.com/yeqown/go-qrcode/v2
    • Image file writing: github.com/yeqown/go-qrcode/writer/standard
    • Terminal writing: github.com/yeqown/go-qrcode/writer/terminal
  10. Implement a custom QR code Writer

    main

    You can implement the qrcode.Writer interface to create custom output formats (e.g., specific image formats or network streams).

    Logic for rendering

    When implementing Write(mat matrix.Matrix), you should iterate through the 2D array of matrix.State. You can determine the color of a pixel/block by checking the state of each cell.

    Generally, states that represent 'set' data (like StateTrue, StateInit, StateVersion, StateFormat, or StateFinder) are treated as the foreground color (e.g., BLACK), while StateFalse or ZERO are treated as the background (e.g., WHITE).

    State Exprvaluerepresentation
    StateFalse0unset (data and etc)
    ZERO0same as StateFalse
    StateTrue1set (data)
    StateInit1not changed since initialized (temporary state)
    StateVersion1set (qr version)
    StateFormat1set (qr format)
    StateFinder1set (qr finder)

    Implementation Pseudocode

    // define your own writer structure to implement `Writer` interface.
    object writer {};
    
    writer.Write(matrix.Matrix):
    	// these should be `IMAGE` stream controller, it receives matrix
    	object paint;  
    	
    	// set use BLACK, unset use WHITE. Or provides matrix.State to colors mapping
    	// so that you can control QR Image output intensively. 
    	foreach row in matrix:
    		foreach column in row:
    			if column.State in [StateFalse]:
    				// paint a WHITE square block
    				paint.draw(x, y, WHITE);
    			else:
    				// paint a BLACK square block
    				paint.draw(x, y, BLACK);
    	// loop end;
    	// output paint;
  11. Use go-qrcode with WebAssembly in a browser

    main

    You can use the pre-compiled WebAssembly (wasm) binary from go-qrcode/wasm to generate QR Code images directly in a web browser. To run the provided example, you must include the Go WebAssembly execution environment (wasm_exec.js) and the compiled .wasm file in your web server's directory.

    # 1. Copy the Go WASM execution support file from your GOROOT
    cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
    
    # 2. Copy the pre-compiled go-qrcode WASM binary to your project directory
    cp "$PATH/go-qrcode/wasm/com.github.yeqown.goqrcode.wasm" .
    
    # 3. Serve the directory using a local web server
    python3 -m http.server