Implementation of the Canon CAPT v1 protocol and SCoA compression based on reverse engineering of the original driver.
NOTE: This is not a full-fledged driver that you can install into your system. It is an implementation of the compression algorithm and protocol, abstracted from any operating system or transmission channel.
Currently, the target devices are Canon CAPT v1 printers, as listed below.
Support for newer models is not planned in the near future.
| Model | Cartridge | PPM (A4) | Max Resolution | Year (approx.) |
|---|---|---|---|---|
| LBP800 | EP-22 | 8 | 600 dpi | 1999-2001 |
| LBP810 | EP-22 | 8 | 600 dpi | 2001-2002 |
| LBP1120 | EP-22 | 10 | 600 dpi | 2003-2004 |
| LBP1210 | EP-25 | 14 | 600 dpi | ~2002 |
| LBP3200 | EP-26/EP-27 | 18 | 600 dpi | 2004-2006 |
The protocol is now well enough researched to ensure smooth operation of printing and cleaning.
The most important thing was the absence of any defects/glitches in the printed page. This was achieved through comprehensive testing of the compression algorithm and subsequent verification on real hardware.
The SCoA compression is completely reverse-engineered. Current implementation of the compression algorithm provides on average 24% better compression and runs up to 26X faster than the compression implementation of the original driver.
If you want to print on a Canon LBP printer, you have several options (besides the original driver):
- darkvision77/captppd — CUPS driver based on libcapt (CAPT v1 only)
- UoWPrint — print server that supports all Canon LBP models (and other printers)
- mounaiban/captdriver — CUPS driver for the newer Canon LBP models (early alpha stage)
The examples folder contains an example program for printing PBM files.
Keep in mind that this program does not implement all the features and is used only for testing.
cmake -S. -B build -DLIBCAPT_BUILD_EXAMPLES=ON
cmake --build build
./build/examples/printpbm /dev/usb/lp0 ./examples/data/example-1.pbmTo rasterize PDF files into PBM, you can use the pdf2pbm.sh script. Also, you can find some test PBM files in the examples/data folder.
cmake -S. -B build
cmake --build build- gcc >= 11 or clang >= 16 or MSVC (tested on 19.44.35217.0)
- cmake >= 3.21
- gtest (+ gmock)
- gdb
- python3
- ghostscript
- poppler-utils (
pdfseparate,pdfinfo, etc.) - captfilter deps (
libpopt0:i386on Debian)
cmake -S. -B build -DLIBCAPT_BUILD_TESTS=ON
cmake --build build
ctest --test-dir buildcmake -S. -B build -DLIBCAPT_BUILD_TESTS=ON -DLIBCAPT_COMPRESSION_TESTS=ON
cmake --build build
ctest --test-dir buildCompression test files are located at tests/Compression/data.
As mentioned above, the most important task is to ensure that the printout is correct and free of any glitches.
The SCoA stream consists of a sequence of commands. For example, the sequence
0x6A 0x12means “copy two bytes from the previous line and repeat byte0x12five times”. The command that produced this sequence is calledCopyThenRepeat.The commands are implemented in ScoaCmd.cpp.
For the compression algorithm to work correctly, you need to know how commands are encoded,
what their valid values are, and what commands exist in general.
All of this is pretty easy to find in the captfilter binary,
where you can also find their names (thanks to the preserved debug prints).
All that remains is to make tests for all this. This will require a decoder, that can be used to verify the correctness of the compressor's output data.
But first, you need to make sure that the decoder itself is working properly.
To do this, captfilter is launched under the GDB script, which records the sequence
of SCoA commands issued by the filter (the so-called command log).
That is, after running captfilter, we get compressed data and the sequence
of commands that were called to produce this data.
In addition to recording commands, the script also removes all margins, as
captfilterchanges the raster size by default, which prevents further byte-by-byte comparison of the original raster and the decoded one.Furthermore, a bug was found in the original driver that causes incorrect printouts (noticed when compressing random data).
The easiest way to describe it is in code:char rawData[] = {1, 2, 3, 4, 5, ..., 256}; CopyThenRawLong(0, rawData, 255); // writes {1, 2, 3, ..., 255} // rawData += 255; <- pointer offset was missed CopyThenRaw(0, rawData, 1); // writes {1}, but it should be {256}This bug is also fixed by the GDB script.
The decoder, meanwhile, reads the compressed data and also writes a log of the commands it has read. Next, the resulting command logs are compared to verify that the commands were recognized correctly. The original raster and the raster obtained by the decoder are also compared to verify the correctness of the commands themselves.
And with a verified decoder, the compression algorithm is tested using a raster compression and decompression cycle and subsequent comparison.
PVS-Studio — static analyzer for C, C++, C#, and Java code.
libcapt is licensed under a 2-clause BSD license.