Added support for previews
This commit is contained in:
parent
5c55474145
commit
7a6d24e2e4
124
main.go
124
main.go
@ -52,6 +52,7 @@ var (
|
|||||||
getQueryCount bool
|
getQueryCount bool
|
||||||
ejectPaper uint
|
ejectPaper uint
|
||||||
retractPaper uint
|
retractPaper uint
|
||||||
|
outputPath string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -85,6 +86,9 @@ func init() {
|
|||||||
flag.UintVar(&retractPaper, "retract", 0, "Retract paper by N lines")
|
flag.UintVar(&retractPaper, "retract", 0, "Retract paper by N lines")
|
||||||
flag.UintVar(&retractPaper, "R", 0, "Retract paper by N lines")
|
flag.UintVar(&retractPaper, "R", 0, "Retract paper by N lines")
|
||||||
|
|
||||||
|
flag.StringVar(&outputPath, "o", "", "Output PNG preview instead of printing (specify output path)")
|
||||||
|
flag.StringVar(&outputPath, "output", "", "Output PNG preview instead of printing (specify output path)")
|
||||||
|
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage: %s [options] <image_path or ->\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "Usage: %s [options] <image_path or ->\n", os.Args[0])
|
||||||
fmt.Fprintln(os.Stderr, `
|
fmt.Fprintln(os.Stderr, `
|
||||||
@ -373,9 +377,86 @@ func sendLineCommand(client ble.Client, printChr *ble.Characteristic, cmdId byte
|
|||||||
return client.WriteCharacteristic(printChr, cmd, true)
|
return client.WriteCharacteristic(printChr, cmd, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderPreviewFrom1bpp(pixels []byte, width, height int) image.Image {
|
||||||
|
img := image.NewGray(image.Rect(0, 0, width, height))
|
||||||
|
for y := 0; y < height; y++ {
|
||||||
|
for x := 0; x < width; x++ {
|
||||||
|
idx := (y*width + x) / 8
|
||||||
|
bit := uint(x % 8)
|
||||||
|
if pixels[idx]&(1<<bit) != 0 {
|
||||||
|
img.SetGray(x, y, color.Gray{Y: 0})
|
||||||
|
} else {
|
||||||
|
img.SetGray(x, y, color.Gray{Y: 255})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderPreviewFrom4bpp(pixels []byte, width, height int) image.Image {
|
||||||
|
img := image.NewGray(image.Rect(0, 0, width, height))
|
||||||
|
for y := 0; y < height; y++ {
|
||||||
|
for x := 0; x < width; x++ {
|
||||||
|
idx := (y*width + x) >> 1
|
||||||
|
shift := uint(((x & 1) ^ 1) << 2)
|
||||||
|
val := (pixels[idx] >> shift) & 0x0F
|
||||||
|
gray := 255 - val*17
|
||||||
|
img.SetGray(x, y, color.Gray{Y: gray})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
var printMode PrintMode
|
||||||
|
switch mode {
|
||||||
|
case "1bpp":
|
||||||
|
printMode = Mode1bpp
|
||||||
|
case "4bpp":
|
||||||
|
printMode = Mode4bpp
|
||||||
|
default:
|
||||||
|
fmt.Println("Invalid mode. Use '1bpp' or '4bpp'.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imagePath := flag.Arg(0)
|
||||||
|
|
||||||
|
var pixels []byte
|
||||||
|
var height int
|
||||||
|
img, err := decodeImage(imagePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Image load error: %v", err)
|
||||||
|
}
|
||||||
|
img = padImageToMinLines(img, minLines)
|
||||||
|
|
||||||
|
switch printMode {
|
||||||
|
case Mode1bpp:
|
||||||
|
pixels, height, err = loadImageMonoFromImage(img, ditherType)
|
||||||
|
case Mode4bpp:
|
||||||
|
pixels, height, err = loadImage4BitFromImage(img)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Image conversion error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outputPath != "" {
|
||||||
|
var previewImg image.Image
|
||||||
|
switch printMode {
|
||||||
|
case Mode1bpp:
|
||||||
|
previewImg = renderPreviewFrom1bpp(pixels, linePixels, height)
|
||||||
|
case Mode4bpp:
|
||||||
|
previewImg = renderPreviewFrom4bpp(pixels, linePixels, height)
|
||||||
|
}
|
||||||
|
err = imaging.Save(previewImg, outputPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to save PNG preview: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Preview PNG written to %s\n", outputPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
@ -442,17 +523,15 @@ func main() {
|
|||||||
log.Fatalf("Missing required print characteristic")
|
log.Fatalf("Missing required print characteristic")
|
||||||
}
|
}
|
||||||
|
|
||||||
if notifyChr != nil {
|
needNotifications := getStatus || getBattery || getVersion || getPrintType || getQueryCount || ejectPaper > 0 || retractPaper > 0
|
||||||
// 1) Make sure the CCCD has been discovered so Subscribe can succeed.
|
|
||||||
_, _ = client.DiscoverDescriptors(nil, notifyChr)
|
|
||||||
|
|
||||||
// 2) Now subscribe. This registers the notification handler **and**
|
if notifyChr != nil && needNotifications {
|
||||||
// writes 0x01-00 to the CCCD for us.
|
_, _ = client.DiscoverDescriptors(nil, notifyChr)
|
||||||
err = client.Subscribe(notifyChr, false, func(b []byte) {
|
err = client.Subscribe(notifyChr, false, func(b []byte) {
|
||||||
parseNotification(b)
|
parseNotification(b)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Subscribe still failed: %v – notifications will be ignored", err)
|
log.Printf("Subscribe failed: %v – notifications will be ignored", err)
|
||||||
} else {
|
} else {
|
||||||
log.Println("Subscribed to printer notifications.")
|
log.Println("Subscribed to printer notifications.")
|
||||||
}
|
}
|
||||||
@ -486,9 +565,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
if flag.NArg() < 1 {
|
if flag.NArg() < 1 {
|
||||||
return // no image to print, other commands may have run
|
return // no image to print, other commands may have run
|
||||||
|
} else if flag.NArg() >= 1 && needNotifications {
|
||||||
|
log.Fatalf("Refusing to print and query at the same time due to a firmware bug. Please run print and query commands separately.")
|
||||||
}
|
}
|
||||||
|
|
||||||
imagePath := flag.Arg(0)
|
|
||||||
i := intensity
|
i := intensity
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = 0
|
i = 0
|
||||||
@ -498,36 +578,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
intensityByte := byte(i)
|
intensityByte := byte(i)
|
||||||
|
|
||||||
var printMode PrintMode
|
|
||||||
switch mode {
|
|
||||||
case "1bpp":
|
|
||||||
printMode = Mode1bpp
|
|
||||||
case "4bpp":
|
|
||||||
printMode = Mode4bpp
|
|
||||||
default:
|
|
||||||
fmt.Println("Invalid mode. Use '1bpp' or '4bpp'.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
img, err := decodeImage(imagePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Image load error: %v", err)
|
|
||||||
}
|
|
||||||
img = padImageToMinLines(img, minLines)
|
|
||||||
|
|
||||||
var pixels []byte
|
|
||||||
var height int
|
|
||||||
|
|
||||||
switch printMode {
|
|
||||||
case Mode1bpp:
|
|
||||||
pixels, height, err = loadImageMonoFromImage(img, ditherType)
|
|
||||||
case Mode4bpp:
|
|
||||||
pixels, height, err = loadImage4BitFromImage(img)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Image conversion error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if dataChr == nil {
|
if dataChr == nil {
|
||||||
log.Fatalf("Missing required data characteristic")
|
log.Fatalf("Missing required data characteristic")
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user