新增 XSLPrintDot 项目,包含打印服务的核心功能和相关配置。实现打印机查询、打印任务处理、远程转发功能,并支持多平台设备ID获取。优化打印数据准备逻辑,增强系统的可维护性和扩展性,同时更新工作区配置以支持新项目。
This commit is contained in:
157
XSLPrintDot/backend_unix.go
Normal file
157
XSLPrintDot/backend_unix.go
Normal file
@@ -0,0 +1,157 @@
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b *Bridge) getPrintersPlatform() ([]PrinterInfo, error) {
|
||||
defaultName := ""
|
||||
if out, err := exec.Command("lpstat", "-d").Output(); err == nil {
|
||||
line := strings.TrimSpace(string(out))
|
||||
if idx := strings.LastIndex(line, ":"); idx >= 0 {
|
||||
defaultName = strings.TrimSpace(line[idx+1:])
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", "lpstat -a | cut -d ' ' -f 1")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
var printers []PrinterInfo
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed != "" {
|
||||
printers = append(printers, PrinterInfo{Name: trimmed, IsDefault: trimmed == defaultName})
|
||||
}
|
||||
}
|
||||
return printers, nil
|
||||
}
|
||||
|
||||
func (b *Bridge) getPrinterCapabilitiesPlatform(printerName string) (map[string]interface{}, error) {
|
||||
printerName = strings.TrimSpace(printerName)
|
||||
if printerName == "" {
|
||||
return nil, fmt.Errorf("printer name is empty")
|
||||
}
|
||||
|
||||
cmd := exec.Command("lpoptions", "-p", printerName, "-l")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lpoptions error: %v, output: %s", err, string(output))
|
||||
}
|
||||
|
||||
options := map[string]map[string]interface{}{}
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
left := strings.TrimSpace(parts[0])
|
||||
right := strings.TrimSpace(parts[1])
|
||||
optName := left
|
||||
if idx := strings.Index(left, "/"); idx >= 0 {
|
||||
optName = strings.TrimSpace(left[:idx])
|
||||
}
|
||||
|
||||
values := []string{}
|
||||
defaultValue := ""
|
||||
for _, token := range strings.Fields(right) {
|
||||
if strings.HasPrefix(token, "*") {
|
||||
clean := strings.TrimPrefix(token, "*")
|
||||
defaultValue = clean
|
||||
values = append(values, clean)
|
||||
continue
|
||||
}
|
||||
values = append(values, token)
|
||||
}
|
||||
|
||||
options[optName] = map[string]interface{}{
|
||||
"values": values,
|
||||
"default": defaultValue,
|
||||
"raw": right,
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"printer": printerName,
|
||||
"options": options,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *Bridge) printPDFPlatform(printerName, filePath string, options PrintOptions) error {
|
||||
args := []string{"-d", printerName}
|
||||
|
||||
if options.Copies > 1 {
|
||||
args = append(args, "-n", fmt.Sprintf("%d", options.Copies))
|
||||
}
|
||||
|
||||
if options.PageRange != "" {
|
||||
args = append(args, "-P", options.PageRange)
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(options.PageSet)) {
|
||||
case "even":
|
||||
args = append(args, "-o", "page-set=even")
|
||||
case "odd":
|
||||
args = append(args, "-o", "page-set=odd")
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(options.Duplex)) {
|
||||
case "long-edge", "long", "duplex", "duplexlong":
|
||||
args = append(args, "-o", "sides=two-sided-long-edge")
|
||||
case "short-edge", "short", "duplexshort":
|
||||
args = append(args, "-o", "sides=two-sided-short-edge")
|
||||
case "simplex", "one-sided":
|
||||
args = append(args, "-o", "sides=one-sided")
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(options.ColorMode)) {
|
||||
case "color":
|
||||
args = append(args, "-o", "ColorModel=RGB")
|
||||
case "mono", "monochrome", "grayscale", "gray":
|
||||
args = append(args, "-o", "ColorModel=Gray")
|
||||
}
|
||||
|
||||
if options.Paper != "" {
|
||||
args = append(args, "-o", fmt.Sprintf("media=%s", options.Paper))
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(options.Scale)) {
|
||||
case "noscale", "none", "actual":
|
||||
args = append(args, "-o", "scaling=100")
|
||||
case "shrink":
|
||||
// Default CUPS behavior already shrinks to fit if needed
|
||||
case "fit":
|
||||
args = append(args, "-o", "fit-to-page")
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(options.Orientation)) {
|
||||
case "portrait":
|
||||
args = append(args, "-o", "orientation-requested=3")
|
||||
case "landscape":
|
||||
args = append(args, "-o", "orientation-requested=4")
|
||||
}
|
||||
|
||||
if options.TrayBin != "" {
|
||||
args = append(args, "-o", fmt.Sprintf("InputSlot=%s", options.TrayBin))
|
||||
}
|
||||
|
||||
args = append(args, filePath)
|
||||
|
||||
cmd := exec.Command("lp", args...)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("lp error: %v, output: %s", err, string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user