About:
This is a port of https://github.com/HenrikBengtsson/brother-ptouch-label-printer-on-linux which was written in C and is now converted to go and support extended to E550W
It is not yet pure go but I hope it will get there eventually. At the moment is very experimental but I need to to work well enough to print my XMAS card labels.
ptouch-goprint is a command line tool to print labels on Brother P-Touch printers on Linux.
There is no need to install the printer via CUPS, the printer is accessed directly via libusb.
The tool was written for and tested with the PT-2430PC, but meanwhile is also used with others (see "ptouch-goprint --list-supported") Maybe others work too (please report USB VID and PID so I can include support for further models, too).
Further info can be found at: https://dominic.familie-radermacher.ch/projekte/ptouch-print/
Print 5 copies with half-cut between them
ptouch-goprint --text "Hello" --copies 5 --halfcut
With precut to clean up the first label edge
ptouch-goprint --text "Hello" --copies 5 --halfcut --precut
PT-550W summary
The protocol was summarised from this document cv_pte550wp750wp710bt_eng_raster_102 downloaded from Brother and a summary in protocol_summary.md is there.
Note:
Dear visitor, currently I have absolutely no time for improvements on this project (my free time currently is about one or two hours PER MONTH). Therefore, I can not look at suggestions about improvements.
Requires task from Taskfile.dev to build
Also need sudo apt install libusb-1.0-0-dev to release.
Using as a Go Module
Note: The core packages are currently in
internal/, so they cannot be imported by external programs. To use this as a library, you would need to fork the repository and move packages frominternal/to a public location (e.g.,pkg/).
Here's an example of printing one or more PNG images:
package main
import (
"fmt"
"image"
"image/png"
"os"
"github.com/drummonds/ptouch-goprint/pkg/device" // after moving from internal/
"github.com/drummonds/ptouch-goprint/pkg/render" // after moving from internal/
)
func main() {
images := []string{"label1.png", "label2.png", "label3.png"}
// Open the printer
dev, err := device.Open()
if err != nil {
fmt.Fprintf(os.Stderr, "Error opening printer: %v\n", err)
os.Exit(1)
}
defer dev.Close()
// Initialize and get status
if err := dev.Init(); err != nil {
fmt.Fprintf(os.Stderr, "Error initializing: %v\n", err)
os.Exit(1)
}
if err := dev.GetStatus(1); err != nil {
fmt.Fprintf(os.Stderr, "Error getting status: %v\n", err)
os.Exit(1)
}
// Print each image
autoCut := true // Set to true to cut after each label, false for chain mode
for i, imgPath := range images {
img, err := loadPNG(imgPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading %s: %v\n", imgPath, err)
os.Exit(1)
}
// chain=false means auto-cut after this label
// chain=true means don't cut (chain to next label)
isLast := i == len(images)-1
chain := !autoCut && !isLast // Only chain if not auto-cutting and not last
if err := printImage(dev, img, chain); err != nil {
fmt.Fprintf(os.Stderr, "Error printing %s: %v\n", imgPath, err)
os.Exit(1)
}
fmt.Printf("Printed %s\n", imgPath)
}
fmt.Println("All labels printed!")
}
func loadPNG(path string) (image.Image, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return png.Decode(f)
}
func printImage(dev *device.Device, img image.Image, chain bool) error {
bounds := img.Bounds()
imgWidth := bounds.Dx()
imgHeight := bounds.Dy()
tapeWidth := dev.GetTapeWidth()
maxPixels := dev.GetMaxWidth()
if imgHeight > tapeWidth {
return fmt.Errorf("image too tall (%dpx), max tape width is %dpx", imgHeight, tapeWidth)
}
// Calculate centering offset
offset := (maxPixels / 2) - (imgHeight / 2)
// Start raster mode
if err := dev.RasterStart(); err != nil {
return err
}
// Send info command for E550W/P750W printers
if dev.HasFlag(device.FlagUseInfoCmd) {
if err := dev.InfoCmd(imgWidth); err != nil {
return err
}
}
// Send raster data column by column
for x := 0; x < imgWidth; x++ {
raster := render.ImageToRaster(img, x, maxPixels, offset)
if err := dev.SendRaster(raster); err != nil {
return err
}
}
// Finalize - chain=true skips cutting between labels
return dev.Finalize(chain)
}
For now, the easiest way to print from another program is to shell out to the CLI:
// Print a single image (auto-cuts after printing)
cmd := exec.Command("ptouch-goprint", "-image", "label.png")
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
// Print multiple images with auto-cut (cuts after each label)
for _, img := range []string{"label1.png", "label2.png", "label3.png"} {
cmd := exec.Command("ptouch-goprint", "-image", img)
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
// Print multiple images with chain mode (no cut between labels, only at end)
cmd := exec.Command("ptouch-goprint",
"-image", "label1.png",
"-image", "label2.png",
"-image", "label3.png",
"-chain")
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
Links
| Documentation | https://h3-ptouch-goprint.statichost.page/ |
| Source (Codeberg) | https://codeberg.org/hum3/ptouch-goprint |
| Mirror (GitHub) | https://github.com/drummonds/ptouch-goprint |
| Docs repo | https://codeberg.org/hum3/ptouch-goprint-docs |