Hacking CARPS printers

CANON CARPS (Canon Advanced Raster Printing System) print format
(reverse-engineered from LaserBase MF5730)

Hacking resulted in a working CUPS driver: CARPS-CUPS

Data is organized into blocks, each with 20-byte header:

0: 0xCD - magic value
1: 0xCA - magic value
2: 0x10 - magic value
3: data type (0x00 = control data, 0x02 = print data)
4: 0x00
5: block type (0x11, 0x12, 0x13, 0x14, 0x16, 0x17, 0x18, 0x19, 0x1a)
6: 0x00
7: 0x01
8: length (high byte) of data following the header (number of bytes)
9: length (low byte)
10-19: padding (zeros)

maximum block (URB?) size is 4KB (4096B)

DOCUMENT structure

Document consists of blocks in this order:

0x11: ???: 13 bytes: \x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00
0x12: document name: \x00\x04\x00\x11 + character count + name
0x12: user name: \x00\x06\x00\x11 + character count + name
0x12: ???: 10 bytes: \x00\x09\x00\x00\x07\x00\x00\x00\x00\x00
0x14: ???: 4 zero bytes
0x17: ???: 4 zero bytes
0x18: ???: 5 bytes: \x00\x2e\x82\x00\x00
0x18: image refinement: 3 bytes: \x08\x2d + \x01 (off) or \x02 (on)
0x18: toner save: 3 bytes: \x08\x5a + \x01 (off) or \x02 (on), if this block is not present,
"printer default" is used
PRINT DATA HERE
0x1a: end of print data: 1 byte: \x01
0x19: 0 bytes
0x16: 0 bytes
0x13: end of document: 1 zero byte

PRINT DATA structure

all print data is in blocks with data type 0x02, block type 0x1a

each page begins with a header (first page has header in separate block, others don’t (?)), such as:

\x01.%@.P42;600;1J;ImgColor.\.[11h.[?7;600 I.[20't.[14;;;;;;p.[?2h.[1v.[600;1;0;32;;64;0'c
P42: ???
600: 600dpi (300 = 300dpi)
1J: ???
ImgColor: ???
20't = Plain paper (15't = Plain L, 20't = Plain, 30't = Heavy, 35't = Heavy H,
40't = Transparencies, 55't = Envelope)
14 = A4, 16 = A5, 30 = letter (??????????????), 60 = envelope monarch
1v: 1 copy (2v = 2 copies, 99v = 99 copies)

then page data follows in STRIPs, each STRIP in one or more blocks
each STRIP includes a header, such as:

\x01.[;4724;110;15.P
4724: strip witdh (in dots) for A4 (letter = 4863), 2362 (A4 300dpi)
110: strip height (in dots) (minimum is 1, maximum 110)
15: ???

then COMPRESSED DATA HEADER follows (13 bytes):

0: 0x01 - magic value
1: 0x02 - magic value
2: 0x04 - magic value
3: 0x08 - magic value
4-5: 0x0000
6: 0x50 - magic value
7: 0x00
8: last strip indication (0x00 = last, 0x01 = not last)
9-10: length (little endian??) - number of following data bytes (excluding ending 0x80 byte),
can span multiple blocks, subsequent blocks do not have this header
11-12: 0x0000

then COMPRESSED DATA follows

strip can span multiple blocks (next blocks are without any headers)
strip ends with 0x80 byte

line ends with zero byte (1111 1101)
compression is per line (repeat stream can’t pass line end)

each page ends with a 2-byte block containing \x01\x0c

print data ends with a 7-byte block containing \x01\x1b\x50\x30\x4a\x1b\x5c

COMPRESSED DATA format

All data bytes in compressed blocks are XORed by value 0x43.

Compression works on byte level (with respect to print image data – each byte represents 8 dots on page) but the encoding is bit-level. There are 5 compression methods:

  1. Repeat bytes from this line at offset -80 bytes
  2. Repeat bytes from this line at offset -2 bytes
  3. Repeat bytes from this line at offset -1 byte (= last byte)
  4. Repeat bytes from -3rd or -7th previous line
  5. Get a byte from dictionary
    Dictionary is 16 byte long
  6. Zero byte
    0b11111101
  7. Byte immediate (no compression)
    0b1101
    0bxxxxxxxx (data)