Add support for printing on red/black tapes

My QL-800 refuses to print black only on a red/black tape.

I really don't like the added `rb` function parameter.
It would be best to be able to recognize such tapes, however
nothing of the sort is documented in official Brother documentation.

makeBitmapData{,RB} also look like they could be simplified further.
This commit is contained in:
Přemysl Eric Janouch 2021-06-10 02:24:00 +02:00
parent 9734cdd16e
commit 269e6514df
Signed by: p
GPG Key ID: A0420B94F92B9493
5 changed files with 80 additions and 22 deletions

View File

@ -211,7 +211,7 @@ func handle(w http.ResponseWriter, r *http.Request) {
font.Font, params.Text, mediaInfo.PrintAreaPins, params.Scale) font.Font, params.Text, mediaInfo.PrintAreaPins, params.Scale)
} }
if r.FormValue("print") != "" { if r.FormValue("print") != "" {
if err := printer.Print(img); err != nil { if err := printer.Print(img, false); err != nil {
log.Println("print error:", err) log.Println("print error:", err)
} }
} }

View File

@ -17,6 +17,7 @@ import (
var scale = flag.Int("scale", 1, "integer upscaling") var scale = flag.Int("scale", 1, "integer upscaling")
var rotate = flag.Bool("rotate", false, "print sideways") var rotate = flag.Bool("rotate", false, "print sideways")
var redblack = flag.Bool("redblack", false, "red and black print")
func main() { func main() {
flag.Usage = func() { flag.Usage = func() {
@ -82,7 +83,7 @@ func main() {
log.Fatalln("the image is too high,", dy, ">", mi.PrintAreaLength, "pt") log.Fatalln("the image is too high,", dy, ">", mi.PrintAreaLength, "pt")
} }
if err := p.Print(img); err != nil { if err := p.Print(img, *redblack); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
} }

View File

@ -309,7 +309,7 @@ func printLabel(id string) error {
} }
return printer.Print(&imgutil.LeftRotate{Image: label.GenLabelForHeight( return printer.Print(&imgutil.LeftRotate{Image: label.GenLabelForHeight(
labelFont, id, mediaInfo.PrintAreaPins, db.BDFScale)}) labelFont, id, mediaInfo.PrintAreaPins, db.BDFScale)}, false)
} }
func handleLabel(w http.ResponseWriter, r *http.Request) { func handleLabel(w http.ResponseWriter, r *http.Request) {

View File

@ -120,9 +120,67 @@ const (
printPins = printBytes * 8 printPins = printBytes * 8
) )
// pack packs a bool array into a byte array for the printer to print out.
func pack(data [printPins]bool, out *[]byte) {
for i := 0; i < printBytes; i++ {
var b byte
for j := 0; j < 8; j++ {
b <<= 1
if data[i*8+j] {
b |= 1
}
}
*out = append(*out, b)
}
}
// makeBitmapDataRB converts an image to the printer's red-black raster format.
func makeBitmapDataRB(src image.Image, margin, length int) []byte {
data, bounds := []byte{}, src.Bounds()
if bounds.Dy() > length {
bounds.Max.Y = bounds.Min.Y + length
}
if bounds.Dx() > printPins-margin {
bounds.Max.X = bounds.Min.X + printPins
}
redcells, blackcells := [printPins]bool{}, [printPins]bool{}
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
length--
// The graphics needs to be inverted horizontally, iterating backwards.
offset := margin
for x := bounds.Max.X - 1; x >= bounds.Min.X; x-- {
r, g, b, a := src.At(x, y).RGBA()
redcells[offset] = r >= 0xc000 && g < 0x4000 && b < 0x4000 &&
a >= 0x8000
blackcells[offset] = r < 0x4000 && g < 0x4000 && b < 0x4000 &&
a >= 0x8000
offset++
}
data = append(data, 'w', 0x01, printBytes)
pack(blackcells, &data)
data = append(data, 'w', 0x02, printBytes)
pack(redcells, &data)
}
for ; length > 0; length-- {
data = append(data, 'w', 0x01, printBytes)
data = append(data, make([]byte, printBytes)...)
data = append(data, 'w', 0x02, printBytes)
data = append(data, make([]byte, printBytes)...)
}
return data
}
// makeBitmapData converts an image to the printer's raster format. // makeBitmapData converts an image to the printer's raster format.
func makeBitmapData(src image.Image, margin, length int) (data []byte) { func makeBitmapData(src image.Image, rb bool, margin, length int) []byte {
bounds := src.Bounds() // It's a necessary nuisance, so just copy and paste.
if rb {
return makeBitmapDataRB(src, margin, length)
}
data, bounds := []byte{}, src.Bounds()
if bounds.Dy() > length { if bounds.Dy() > length {
bounds.Max.Y = bounds.Min.Y + length bounds.Max.Y = bounds.Min.Y + length
} }
@ -138,30 +196,24 @@ func makeBitmapData(src image.Image, margin, length int) (data []byte) {
offset := margin offset := margin
for x := bounds.Max.X - 1; x >= bounds.Min.X; x-- { for x := bounds.Max.X - 1; x >= bounds.Min.X; x-- {
r, g, b, a := src.At(x, y).RGBA() r, g, b, a := src.At(x, y).RGBA()
pixels[offset] = r == 0 && g == 0 && b == 0 && a >= 0x8000 pixels[offset] = r < 0x4000 && g < 0x4000 && b < 0x4000 &&
a >= 0x8000
offset++ offset++
} }
data = append(data, 'g', 0x00, printBytes) data = append(data, 'g', 0x00, printBytes)
for i := 0; i < printBytes; i++ { pack(pixels, &data)
var b byte
for j := 0; j < 8; j++ {
b <<= 1
if pixels[i*8+j] {
b |= 1
}
}
data = append(data, b)
}
} }
for ; length > 0; length-- { for ; length > 0; length-- {
data = append(data, 'g', 0x00, printBytes) data = append(data, 'g', 0x00, printBytes)
data = append(data, make([]byte, printBytes)...) data = append(data, make([]byte, printBytes)...)
} }
return return data
} }
func makePrintData(status *Status, image image.Image) (data []byte) { // XXX: It would be preferrable to know for certain if this is a red-black tape,
// because the printer refuses to print on a mismatch.
func makePrintData(status *Status, image image.Image, rb bool) (data []byte) {
mediaInfo := GetMediaInfo( mediaInfo := GetMediaInfo(
status.MediaWidthMM(), status.MediaWidthMM(),
status.MediaLengthMM(), status.MediaLengthMM(),
@ -198,7 +250,11 @@ func makePrintData(status *Status, image image.Image) (data []byte) {
// Cut at end (though it's the default). // Cut at end (though it's the default).
// Not sure what it means, doesn't seem to have any effect to turn it off. // Not sure what it means, doesn't seem to have any effect to turn it off.
if rb {
data = append(data, 0x1b, 0x69, 0x4b, 0x08|0x01)
} else {
data = append(data, 0x1b, 0x69, 0x4b, 0x08) data = append(data, 0x1b, 0x69, 0x4b, 0x08)
}
if status.MediaLengthMM() != 0 { if status.MediaLengthMM() != 0 {
// 3mm margins along the direction of feed. 0x23 = 35 dots, the minimum. // 3mm margins along the direction of feed. 0x23 = 35 dots, the minimum.
@ -213,7 +269,8 @@ func makePrintData(status *Status, image image.Image) (data []byte) {
data = append(data, 0x4d, 0x00) data = append(data, 0x4d, 0x00)
// The graphics data itself. // The graphics data itself.
data = append(data, makeBitmapData(image, mediaInfo.SideMarginPins, dy)...) bitmapData := makeBitmapData(image, rb, mediaInfo.SideMarginPins, dy)
data = append(data, bitmapData...)
// Print command with feeding. // Print command with feeding.
return append(data, 0x1a) return append(data, 0x1a)

View File

@ -172,8 +172,8 @@ var errErrorOccurred = errors.New("error occurred")
var errUnexpectedStatus = errors.New("unexpected status") var errUnexpectedStatus = errors.New("unexpected status")
var errUnknownMedia = errors.New("unknown media") var errUnknownMedia = errors.New("unknown media")
func (p *Printer) Print(image image.Image) error { func (p *Printer) Print(image image.Image, rb bool) error {
data := makePrintData(p.LastStatus, image) data := makePrintData(p.LastStatus, image, rb)
if data == nil { if data == nil {
return errUnknownMedia return errUnknownMedia
} }