Skip to content

Commit f16102c

Browse files
committed
Added print chunking to avoid gibberish.
1 parent 16620df commit f16102c

File tree

4 files changed

+102
-24
lines changed

4 files changed

+102
-24
lines changed

frontend/src/js/ui/views/settings/index.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,36 @@ export default () => {
161161
oninput={binder.checkbox(store.data.settings.commands, 'cut')}
162162
/>
163163
</Form>
164+
<div className='divider' />
165+
</div>
166+
<div className='w-50 mb2'>
167+
<div className='f5 mb2 pt2'>Print Chunking</div>
168+
<div className='lh-copy o-70'>
169+
If you are using a old printer with a small print buffer you can tell Sales & Dungeons to split the printing into smaller chunks. This
170+
might help in avoiding gibberish print-outs.
171+
</div>
172+
<Form horizontal={true}>
173+
<Switch
174+
label='Enable'
175+
labelCol={4}
176+
value={store.data.settings.commands.splitPrinting}
177+
oninput={binder.checkbox(store.data.settings.commands, 'splitPrinting')}
178+
/>
179+
<Input
180+
label='Split Height'
181+
labelCol={4}
182+
placeholder='Pixel height to split like 300'
183+
value={store.data.settings.commands.splitHeight}
184+
oninput={binder.inputNumber(store.data.settings.commands, 'splitHeight')}
185+
/>
186+
<Input
187+
label='Split Delay'
188+
labelCol={4}
189+
placeholder='Delay after a print in milliseconds like 1000'
190+
value={store.data.settings.commands.splitDelay}
191+
oninput={binder.inputNumber(store.data.settings.commands, 'splitDelay')}
192+
/>
193+
</Form>
164194
</div>
165195
</div>
166196
</div>

rpc/print.go

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"image"
99
"image/png"
1010
"io/ioutil"
11+
"math"
1112
"math/rand"
1213
"net"
1314
"net/http"
@@ -147,33 +148,75 @@ func print(db database.Database, printer printing.PossiblePrinter, html string)
147148
renderCache.SetDefault(tempId, finalHtml)
148149

149150
// Render the html to image
150-
image, err := rendering.RenderURL(fmt.Sprintf("http://127.0.0.1:7123/api/html/%s", tempId), settings.PrinterWidth)
151+
renderedImage, err := rendering.RenderURL(fmt.Sprintf("http://127.0.0.1:7123/api/html/%s", tempId), settings.PrinterWidth)
151152
if err != nil {
152153
return fmt.Errorf("html to image rendering failed: %w", err)
153154
}
154155

155-
// Print
156-
buf := &bytes.Buffer{}
156+
imageRgb := renderedImage.(*image.RGBA)
157+
height := imageRgb.Bounds().Max.Y
158+
width := imageRgb.Bounds().Max.X
157159

158-
if settings.Commands.ExplicitInit {
159-
epson.InitPrinter(buf)
160-
}
160+
var images []image.Image
161+
if settings.Commands.SplitPrinting && height > settings.Commands.SplitHeight {
162+
if settings.Commands.SplitHeight < 100 {
163+
return fmt.Errorf("please use a split height of at least 100")
164+
}
161165

162-
if settings.Commands.ForceStandardMode {
163-
epson.SetStandardMode(buf)
164-
}
166+
chunks := int(math.Ceil(float64(height) / float64(settings.Commands.SplitHeight)))
165167

166-
buf.WriteString(strings.Repeat("\n", settings.Commands.LinesBefore))
167-
epson.Image(buf, image)
168-
buf.WriteString(strings.Repeat("\n", 5+settings.Commands.LinesAfter))
168+
// Chunk the images
169+
for i := 0; i < chunks; i++ {
170+
y1 := i * settings.Commands.SplitHeight
171+
y2 := y1 + settings.Commands.SplitHeight
172+
if y2 > height {
173+
y2 = height
174+
}
169175

170-
if settings.Commands.Cut {
171-
epson.CutPaper(buf)
176+
images = append(images, imageRgb.SubImage(image.Rect(0, y1, width, y2)))
177+
}
178+
} else {
179+
images = []image.Image{renderedImage}
172180
}
173181

174-
err = selectedPrinter.Print(settings.PrinterEndpoint, image, buf.Bytes())
175-
if err != nil {
176-
return fmt.Errorf("printer wasn't able to print: %w", err)
182+
// Print
183+
for i, img := range images {
184+
buf := &bytes.Buffer{}
185+
186+
// At the first chunk set modes and lines
187+
if i == 0 {
188+
if settings.Commands.ExplicitInit {
189+
epson.InitPrinter(buf)
190+
}
191+
192+
if settings.Commands.ForceStandardMode {
193+
epson.SetStandardMode(buf)
194+
}
195+
196+
buf.WriteString(strings.Repeat("\n", settings.Commands.LinesBefore))
197+
}
198+
199+
epson.Image(buf, img)
200+
201+
// At the last chunk insert lines and cut
202+
if i == len(images)-1 {
203+
buf.WriteString(strings.Repeat("\n", 5+settings.Commands.LinesAfter))
204+
205+
if settings.Commands.Cut {
206+
epson.CutPaper(buf)
207+
}
208+
}
209+
210+
// Print chunk
211+
err = selectedPrinter.Print(settings.PrinterEndpoint, renderedImage, buf.Bytes())
212+
if err != nil {
213+
return fmt.Errorf("printer wasn't able to print: %w", err)
214+
}
215+
216+
// Add delay to consecutive prints
217+
if len(images) > 1 && settings.Commands.SplitDelay > 0 {
218+
time.Sleep(time.Millisecond * time.Duration(settings.Commands.SplitDelay))
219+
}
177220
}
178221

179222
return nil

settings.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ type Settings struct {
1111
ForceStandardMode bool `json:"forceStandardMode"`
1212
LinesBefore int `json:"linesBefore"`
1313
LinesAfter int `json:"linesAfter"`
14+
SplitPrinting bool `json:"splitPrinting"`
15+
SplitHeight int `json:"splitHeight"`
16+
SplitDelay int `json:"splitDelay"`
1417
} `json:"commands"`
1518
Stylesheets []string `json:"stylesheets"`
1619
SpellcheckerLanguages []string `json:"spellcheckerLanguages"`

thermalprinter/epson/epson.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,26 @@ func LineBreak(buf io.Writer) {
3636
func Image(buf io.Writer, image image.Image) {
3737
bb := image.Bounds()
3838

39-
width := bb.Max.X
39+
height := bb.Max.Y - bb.Min.Y
40+
realWidth := bb.Max.X - bb.Min.X
41+
width := realWidth
4042
if width%8 != 0 {
4143
width += 8
4244
}
4345

4446
xL := uint8(width % 2048 / 8)
4547
xH := uint8(width / 2048)
46-
yL := uint8(bb.Max.Y % 256)
47-
yH := uint8(bb.Max.Y / 256)
48+
yL := uint8(height % 256)
49+
yH := uint8(height / 256)
4850

4951
_, _ = buf.Write([]byte{0x1d, 0x76, 0x30, 48, xL, xH, yL, yH})
5052

5153
var cb byte
5254
var bindex byte
53-
for y := 0; y < bb.Max.Y; y++ {
54-
for x := 0; x < int(math.Ceil(float64(bb.Max.X)/8.0))*8; x++ {
55-
if x < bb.Max.X {
56-
r, g, b, a := image.At(x, y).RGBA()
55+
for y := 0; y < height; y++ {
56+
for x := 0; x < int(math.Ceil(float64(realWidth)/8.0))*8; x++ {
57+
if x < realWidth {
58+
r, g, b, a := image.At(bb.Min.X+x, bb.Min.Y+y).RGBA()
5759
r, g, b, a = r>>8, g>>8, b>>8, a>>8
5860

5961
if a > 255/2 {

0 commit comments

Comments
 (0)