printer: align direct PCL/PS output with host-mode cutbox geometry
This commit is contained in:
parent
e3cae9b541
commit
391528daa5
@ -41,6 +41,49 @@ type placementPlan struct {
|
||||
pages []pagePlacement
|
||||
}
|
||||
|
||||
const (
|
||||
// Direct host backends (raw PCL/PS) tend to clip near page top versus CUPS/HBP.
|
||||
// Keep HBP/layout geometry unchanged and apply a small emit-time translation here.
|
||||
hostDirectTopOffsetMM = 5.0
|
||||
// Raw PCL path is typically shifted right; compensate left to restore centering.
|
||||
hostPCLLeftOffsetMM = -5.0
|
||||
)
|
||||
|
||||
func offsetPagePlacement(p pagePlacement, dx, dy int) pagePlacement {
|
||||
out := pagePlacement{
|
||||
slots: make([]placedPlate, 0, len(p.slots)),
|
||||
cutBoxes: make([]image.Rectangle, 0, len(p.cutBoxes)),
|
||||
marks: make([]cutMark, 0, len(p.marks)),
|
||||
overlays: make([]placedPlate, 0, len(p.overlays)),
|
||||
}
|
||||
for _, s := range p.slots {
|
||||
out.slots = append(out.slots, placedPlate{
|
||||
plate: s.plate,
|
||||
x: s.x + dx,
|
||||
y: s.y + dy,
|
||||
})
|
||||
}
|
||||
for _, b := range p.cutBoxes {
|
||||
out.cutBoxes = append(out.cutBoxes, b.Add(image.Pt(dx, dy)))
|
||||
}
|
||||
for _, m := range p.marks {
|
||||
out.marks = append(out.marks, cutMark{
|
||||
x0: m.x0 + dx,
|
||||
y0: m.y0 + dy,
|
||||
x1: m.x1 + dx,
|
||||
y1: m.y1 + dy,
|
||||
})
|
||||
}
|
||||
for _, ov := range p.overlays {
|
||||
out.overlays = append(out.overlays, placedPlate{
|
||||
plate: ov.plate,
|
||||
x: ov.x + dx,
|
||||
y: ov.y + dy,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func newProgressWriter(stage PrintStage, w io.Writer, total int64, progress ProgressFunc) *progressWriter {
|
||||
return &progressWriter{
|
||||
w: w,
|
||||
@ -124,6 +167,8 @@ func WritePCLPlatesWithInvert(w io.Writer, seedPlates, descPlates []*image.Palet
|
||||
rowBytes := (width + 7) / 8
|
||||
rowPix := make([]uint8, width)
|
||||
rowPacked := make([]byte, rowBytes)
|
||||
dx := mmToPx(hostPCLLeftOffsetMM, dpi)
|
||||
dy := mmToPx(hostDirectTopOffsetMM, dpi)
|
||||
|
||||
for _, page := range plan.pages {
|
||||
if _, err := fmt.Fprintf(pw, "\x1bE"); err != nil { // reset
|
||||
@ -153,9 +198,10 @@ func WritePCLPlatesWithInvert(w io.Writer, seedPlates, descPlates []*image.Palet
|
||||
if _, err := fmt.Fprintf(pw, "\x1b*r0F"); err != nil { // start raster graphics
|
||||
return err
|
||||
}
|
||||
renderPage := offsetPagePlacement(page, dx, dy)
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
renderPlannedRow(rowPix, y, page, invert)
|
||||
renderPlannedRow(rowPix, y, renderPage, invert)
|
||||
packBits(rowPacked, rowPix)
|
||||
if _, err := fmt.Fprintf(pw, "\x1b*b%dW", rowBytes); err != nil {
|
||||
return err
|
||||
@ -297,9 +343,12 @@ func WritePCL(w io.Writer, pages []*image.Paletted, dpi float64, paper PaperSize
|
||||
|
||||
rowBytes := (width + 7) / 8
|
||||
buf := make([]byte, rowBytes)
|
||||
rowPix := make([]uint8, width)
|
||||
dx := mmToPx(hostPCLLeftOffsetMM, dpi)
|
||||
dy := mmToPx(hostDirectTopOffsetMM, dpi)
|
||||
for y := 0; y < height; y++ {
|
||||
pix := page.Pix[y*page.Stride : y*page.Stride+width]
|
||||
packBits(buf, pix)
|
||||
renderShiftedPageRow(rowPix, page, y, dx, dy)
|
||||
packBits(buf, rowPix)
|
||||
if _, err := fmt.Fprintf(pw, "\x1b*b%dW", rowBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -356,6 +405,38 @@ func packBits(dst []byte, row []uint8) {
|
||||
}
|
||||
}
|
||||
|
||||
func renderShiftedPageRow(dst []uint8, page *image.Paletted, y, dx, dy int) {
|
||||
for i := range dst {
|
||||
dst[i] = 0
|
||||
}
|
||||
if page == nil {
|
||||
return
|
||||
}
|
||||
b := page.Bounds()
|
||||
srcY := y - dy
|
||||
if srcY < 0 || srcY >= b.Dy() {
|
||||
return
|
||||
}
|
||||
src := page.Pix[(b.Min.Y+srcY)*page.Stride+b.Min.X : (b.Min.Y+srcY)*page.Stride+b.Min.X+b.Dx()]
|
||||
dstStart := dx
|
||||
srcStart := 0
|
||||
n := len(src)
|
||||
if dstStart < 0 {
|
||||
srcStart = -dstStart
|
||||
dstStart = 0
|
||||
}
|
||||
if dstStart >= len(dst) || srcStart >= n {
|
||||
return
|
||||
}
|
||||
n -= srcStart
|
||||
if dstStart+n > len(dst) {
|
||||
n = len(dst) - dstStart
|
||||
}
|
||||
if n > 0 {
|
||||
copy(dst[dstStart:dstStart+n], src[srcStart:srcStart+n])
|
||||
}
|
||||
}
|
||||
|
||||
func minInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
|
||||
@ -58,6 +58,9 @@ func WritePS(w io.Writer, pages []*image.Paletted, paper PaperSize, progress Pro
|
||||
}
|
||||
rowBytes := (width + 7) / 8
|
||||
buf := make([]byte, rowBytes)
|
||||
rowPix := make([]uint8, width)
|
||||
effectiveDPI := float64(width) * 25.4 / pageWmm
|
||||
dy := mmToPx(hostDirectTopOffsetMM, effectiveDPI)
|
||||
if _, err := fmt.Fprintf(bw, "%%%%Page: %d %d\n", i+1, i+1); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -88,8 +91,8 @@ func WritePS(w io.Writer, pages []*image.Paletted, paper PaperSize, progress Pro
|
||||
}
|
||||
hexRow := make([]byte, rowBytes*2+1)
|
||||
for y := 0; y < height; y++ {
|
||||
pix := page.Pix[y*page.Stride : y*page.Stride+width]
|
||||
packBits(buf, pix)
|
||||
renderShiftedPageRow(rowPix, page, y, 0, dy)
|
||||
packBits(buf, rowPix)
|
||||
hex.Encode(hexRow[:rowBytes*2], buf)
|
||||
hexRow[rowBytes*2] = '\n'
|
||||
if _, err := bw.Write(hexRow); err != nil {
|
||||
@ -170,6 +173,7 @@ func WritePSPlatesWithInvert(w io.Writer, seedPlates, descPlates []*image.Palett
|
||||
rowPix := make([]uint8, width)
|
||||
rowPacked := make([]byte, rowBytes)
|
||||
hexRow := make([]byte, rowBytes*2+1)
|
||||
dy := mmToPx(hostDirectTopOffsetMM, dpi)
|
||||
|
||||
pageNum := 1
|
||||
for _, page := range plan.pages {
|
||||
@ -200,9 +204,10 @@ func WritePSPlatesWithInvert(w io.Writer, seedPlates, descPlates []*image.Palett
|
||||
if _, err := fmt.Fprintf(bw, "{ currentfile picstr readhexstring pop } imagemask\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
renderPage := offsetPagePlacement(page, 0, dy)
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
renderPlannedRow(rowPix, y, page, invert)
|
||||
renderPlannedRow(rowPix, y, renderPage, invert)
|
||||
packBits(rowPacked, rowPix)
|
||||
hex.Encode(hexRow[:rowBytes*2], rowPacked)
|
||||
hexRow[rowBytes*2] = '\n'
|
||||
@ -252,8 +257,8 @@ func WritePSPlatesWithInvert(w io.Writer, seedPlates, descPlates []*image.Palett
|
||||
return err
|
||||
}
|
||||
for y := 0; y < height; y++ {
|
||||
pix := page.Pix[(b.Min.Y+y)*page.Stride+b.Min.X : (b.Min.Y+y)*page.Stride+b.Min.X+width]
|
||||
packBits(rowPacked, pix)
|
||||
renderShiftedPageRow(rowPix, page, y, 0, dy)
|
||||
packBits(rowPacked, rowPix)
|
||||
hex.Encode(hexRow[:rowBytes*2], rowPacked)
|
||||
hexRow[rowBytes*2] = '\n'
|
||||
if _, err := bw.Write(hexRow); err != nil {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user