aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2021-06-10 02:24:00 +0200
committerPřemysl Eric Janouch <p@janouch.name>2021-06-10 02:37:14 +0200
commit269e6514df30943e1e108df97558b460f407d7a2 (patch)
treed1c8589fa7ed472a2d705ccbb018f65748e60e4f
parent9734cdd16e1b7572464dfaed3bd03a70db46a3d3 (diff)
downloadsklad-269e6514df30943e1e108df97558b460f407d7a2.tar.gz
sklad-269e6514df30943e1e108df97558b460f407d7a2.tar.xz
sklad-269e6514df30943e1e108df97558b460f407d7a2.zip
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.
-rw-r--r--cmd/label-tool/main.go2
-rw-r--r--cmd/ql-print/main.go3
-rw-r--r--cmd/sklad/main.go2
-rw-r--r--ql/ql.go91
-rw-r--r--ql/ql_linux.go4
5 files changed, 80 insertions, 22 deletions
diff --git a/cmd/label-tool/main.go b/cmd/label-tool/main.go
index 893aa13..0f0ab4b 100644
--- a/cmd/label-tool/main.go
+++ b/cmd/label-tool/main.go
@@ -211,7 +211,7 @@ func handle(w http.ResponseWriter, r *http.Request) {
font.Font, params.Text, mediaInfo.PrintAreaPins, params.Scale)
}
if r.FormValue("print") != "" {
- if err := printer.Print(img); err != nil {
+ if err := printer.Print(img, false); err != nil {
log.Println("print error:", err)
}
}
diff --git a/cmd/ql-print/main.go b/cmd/ql-print/main.go
index d0c986d..647ba1a 100644
--- a/cmd/ql-print/main.go
+++ b/cmd/ql-print/main.go
@@ -17,6 +17,7 @@ import (
var scale = flag.Int("scale", 1, "integer upscaling")
var rotate = flag.Bool("rotate", false, "print sideways")
+var redblack = flag.Bool("redblack", false, "red and black print")
func main() {
flag.Usage = func() {
@@ -82,7 +83,7 @@ func main() {
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)
}
}
diff --git a/cmd/sklad/main.go b/cmd/sklad/main.go
index 4808713..bf745e8 100644
--- a/cmd/sklad/main.go
+++ b/cmd/sklad/main.go
@@ -309,7 +309,7 @@ func printLabel(id string) error {
}
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) {
diff --git a/ql/ql.go b/ql/ql.go
index ec84656..3625f4b 100644
--- a/ql/ql.go
+++ b/ql/ql.go
@@ -120,9 +120,67 @@ const (
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.
-func makeBitmapData(src image.Image, margin, length int) (data []byte) {
- bounds := src.Bounds()
+func makeBitmapData(src image.Image, rb bool, margin, length int) []byte {
+ // 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 {
bounds.Max.Y = bounds.Min.Y + length
}
@@ -138,30 +196,24 @@ func makeBitmapData(src image.Image, margin, length int) (data []byte) {
offset := margin
for x := bounds.Max.X - 1; x >= bounds.Min.X; x-- {
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++
}
data = append(data, 'g', 0x00, printBytes)
- for i := 0; i < printBytes; i++ {
- var b byte
- for j := 0; j < 8; j++ {
- b <<= 1
- if pixels[i*8+j] {
- b |= 1
- }
- }
- data = append(data, b)
- }
+ pack(pixels, &data)
}
for ; length > 0; length-- {
data = append(data, 'g', 0x00, 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(
status.MediaWidthMM(),
status.MediaLengthMM(),
@@ -198,7 +250,11 @@ func makePrintData(status *Status, image image.Image) (data []byte) {
// Cut at end (though it's the default).
// Not sure what it means, doesn't seem to have any effect to turn it off.
- data = append(data, 0x1b, 0x69, 0x4b, 0x08)
+ if rb {
+ data = append(data, 0x1b, 0x69, 0x4b, 0x08|0x01)
+ } else {
+ data = append(data, 0x1b, 0x69, 0x4b, 0x08)
+ }
if status.MediaLengthMM() != 0 {
// 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)
// 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.
return append(data, 0x1a)
diff --git a/ql/ql_linux.go b/ql/ql_linux.go
index 9d465b5..26675eb 100644
--- a/ql/ql_linux.go
+++ b/ql/ql_linux.go
@@ -172,8 +172,8 @@ var errErrorOccurred = errors.New("error occurred")
var errUnexpectedStatus = errors.New("unexpected status")
var errUnknownMedia = errors.New("unknown media")
-func (p *Printer) Print(image image.Image) error {
- data := makePrintData(p.LastStatus, image)
+func (p *Printer) Print(image image.Image, rb bool) error {
+ data := makePrintData(p.LastStatus, image, rb)
if data == nil {
return errUnknownMedia
}