ql-label 0.2.1

Brother QL series label printer driver for Rust
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a Rust library (`ptouch`) that provides USB printing capability for Brother P-Touch QL series label printers. The crate allows programmatic generation and printing of label images using the rusb library for USB communication.

## Development Commands

### Building
```bash
cargo build
```

### Running Examples
```bash
# Read printer status with debug logging
RUST_LOG=debug cargo run --example read_status

# Print test labels (various options available)
cargo run --example print_rust [normal|high|multiple|qr]
cargo run --example print_two_color [test|image <path>]

# Examples:
cargo run --example print_rust normal    # Normal resolution single label
cargo run --example print_rust multiple  # Multiple high resolution labels
cargo run --example print_rust qr        # QR code labels
cargo run --example print_two_color test # Two-color test pattern
cargo run --example print_two_color image path/to/image.png # Two-color image printing
```

### Testing
```bash
cargo test
```

## Core Architecture

### Module Structure

- **`printer.rs`** - Main `Printer` struct handling USB communication, status checking, and print operations
- **`model.rs`** - Defines supported printer models (QL-720NW, QL-800, QL-820NWB, etc.) with their PIDs and specifications
- **`media.rs`** - Media type definitions (Continuous vs DieCut) with detailed specifications for dimensions and offsets
- **`error.rs`** - Error types for USB, device, and printer-specific errors
- **`utils.rs`** - Image processing utilities for converting bitmap data to printer format

### Key Design Patterns

#### USB Device Management
The `Printer::new()` method handles complex USB device initialization:
- Finds printers by vendor ID (0x04f9) and product ID
- Matches devices by serial number string
- Handles kernel driver detachment (varies by model)
- Configures USB endpoints for bulk transfers

#### Iterator-Based Printing
The `print()` method accepts any `Iterator<Item = Matrix>`, enabling lazy label generation:
```rust
printer.print(vec![label_data].into_iter())?; // Single label
printer.print(LabelGenerator { count: 5 })?;  // Multiple labels via custom iterator
```

#### Media Specification System
Each media type has detailed specifications defining:
- Physical dimensions (mm and dots)
- Print area offsets (left, effective width, right margins)
- Feed values and validation rules
- Status parsing from printer responses

### Configuration System

The `Config` struct uses builder pattern for printer settings:
- Media type and model (immutable after creation) 
- Resolution modes (normal/high)
- Auto-cut behavior and frequency
- Two-color printing support
- Compression settings

### Status Monitoring

The printer status system parses 32-byte responses containing:
- Current media type and dimensions
- Error states and phase information
- Model identification and notification status

### Enhanced Print Completion Handling

The library features improved print completion monitoring with smart status polling:

#### Key Features
- **Adaptive Status Polling**: Replaces fixed retry approach with intelligent monitoring
- **Phase Transition Monitoring**: Tracks Printing → Receiving state transitions
- **Immediate Error Detection**: Detects printer errors (cover open, media issues) during print jobs
- **Timeout Protection**: Prevents indefinite waiting with configurable timeouts
- **Detailed Logging**: Enhanced debug output for troubleshooting

#### Implementation Details
- `wait_for_print_completion()`: Core monitoring function with adaptive polling
- Applied to both 0x0C (Print) and 0x1A (Print then Eject) commands
- Error types: `PrintTimeout`, `UnexpectedPhase`, `PrinterError`
- Typical completion time: ~1.8s for standard labels (reduced from previous approach)

## Hardware Integration Notes

- **Kernel Driver Handling**: QL-800 requires kernel driver detachment, QL-820NWB does not
- **USB Timeout**: Long labels (>1000mm) may cause USB timeout errors
- **Media Detection**: Printer automatically detects installed media tape, verified against config
- **Two-Color Support**: Requires alternating raster line commands for red/black printing

### Print Command Flow
The library handles two main print commands:
- **0x0C (FF : Print)**: Used for intermediate pages in multi-page jobs
- **0x1A (Control-Z : Print then Eject)**: Used for final page with media ejection
- Both commands now use `wait_for_print_completion()` for reliable status monitoring

### Two-Color Printing Support

The library now supports two-color printing (black and red) for compatible QL-820NWB printers:

#### Key Features
- **TwoColorMatrix**: New data structure for handling black and red image data separately
- **Automatic Alternating Lines**: Converts two-color data to alternating black/red raster lines
- **RGB Image Conversion**: Built-in function to convert RGB images to two-color format
- **Color Detection**: Smart pixel classification (red pixels: R>200,G<100,B<100; black pixels: brightness<128)

#### API Usage
```rust
// Enable two-color printing in config
let config = Config::new(model, serial, media)
    .two_colors(true);

// Print two-color labels
let two_color_data = TwoColorMatrix::new(black_matrix, red_matrix)?;
printer.print_two_color(vec![two_color_data].into_iter())?;

// Convert RGB image to two-color
let two_color_data = convert_rgb_to_two_color(width, height, &rgb_data)?;
```

#### Technical Implementation
- Black raster lines: `0x77 0x01 90` + 90-byte data
- Red raster lines: `0x77 0x02 90` + 90-byte data
- Alternating pattern: black line, red line, black line, etc.
- Raster count = image_height * 2 (due to line doubling)

## Image Data Format

Labels must be provided as `Matrix` type (`Vec<Vec<u8>>`):
- Width: 720px for normal printers, 1296px for wide printers
- 1-bit bitmap data packed into bytes (8 pixels per byte)
- Use `step_filter_normal()` utility to convert grayscale images
- Content positioning depends on media width (see media specifications)