sklad: import label printing capability from label-tool
This commit is contained in:
		
							parent
							
								
									4dade55387
								
							
						
					
					
						commit
						ea45784554
					
				| @ -4,60 +4,20 @@ import ( | ||||
| 	"errors" | ||||
| 	"html/template" | ||||
| 	"image" | ||||
| 	"image/draw" | ||||
| 	"image/png" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/boombuler/barcode" | ||||
| 	"github.com/boombuler/barcode/qr" | ||||
| 
 | ||||
| 	"janouch.name/sklad/bdf" | ||||
| 	"janouch.name/sklad/imgutil" | ||||
| 	"janouch.name/sklad/label" | ||||
| 	"janouch.name/sklad/ql" | ||||
| ) | ||||
| 
 | ||||
| var font *bdf.Font | ||||
| 
 | ||||
| func genLabelForHeight(text string, height, scale int) image.Image { | ||||
| 	// Create a scaled bitmap of the text label. | ||||
| 	textRect, _ := font.BoundString(text) | ||||
| 	textImg := image.NewRGBA(textRect) | ||||
| 	draw.Draw(textImg, textRect, image.White, image.ZP, draw.Src) | ||||
| 	font.DrawString(textImg, image.ZP, text) | ||||
| 
 | ||||
| 	scaledTextImg := imgutil.Scale{Image: textImg, Scale: scale} | ||||
| 	scaledTextRect := scaledTextImg.Bounds() | ||||
| 
 | ||||
| 	remains := height - scaledTextRect.Dy() - 20 | ||||
| 
 | ||||
| 	width := scaledTextRect.Dx() | ||||
| 	if remains > width { | ||||
| 		width = remains | ||||
| 	} | ||||
| 
 | ||||
| 	// Create a scaled bitmap of the QR code. | ||||
| 	qrImg, _ := qr.Encode(text, qr.H, qr.Auto) | ||||
| 	qrImg, _ = barcode.Scale(qrImg, remains, remains) | ||||
| 	qrRect := qrImg.Bounds() | ||||
| 
 | ||||
| 	// Combine. | ||||
| 	combinedRect := image.Rect(0, 0, width, height) | ||||
| 	combinedImg := image.NewRGBA(combinedRect) | ||||
| 	draw.Draw(combinedImg, combinedRect, image.White, image.ZP, draw.Src) | ||||
| 	draw.Draw(combinedImg, | ||||
| 		combinedRect.Add(image.Point{X: (width - qrRect.Dx()) / 2, Y: 0}), | ||||
| 		qrImg, image.ZP, draw.Src) | ||||
| 
 | ||||
| 	target := image.Rect( | ||||
| 		(width-scaledTextRect.Dx())/2, qrRect.Dy()+20, | ||||
| 		combinedRect.Max.X, combinedRect.Max.Y) | ||||
| 	draw.Draw(combinedImg, target, &scaledTextImg, scaledTextRect.Min, draw.Src) | ||||
| 	return combinedImg | ||||
| } | ||||
| 
 | ||||
| var tmpl = template.Must(template.New("form").Parse(` | ||||
| 	<!DOCTYPE html> | ||||
| 	<html><body> | ||||
| @ -183,12 +143,12 @@ func handle(w http.ResponseWriter, r *http.Request) { | ||||
| 		params.Scale = 3 | ||||
| 	} | ||||
| 
 | ||||
| 	var label image.Image | ||||
| 	var img image.Image | ||||
| 	if mediaInfo != nil { | ||||
| 		label = &imgutil.LeftRotate{Image: genLabelForHeight( | ||||
| 			params.Text, mediaInfo.PrintAreaPins, params.Scale)} | ||||
| 		img = &imgutil.LeftRotate{Image: label.GenLabelForHeight( | ||||
| 			font, params.Text, mediaInfo.PrintAreaPins, params.Scale)} | ||||
| 		if r.FormValue("print") != "" { | ||||
| 			if err := printer.Print(label); err != nil { | ||||
| 			if err := printer.Print(img); err != nil { | ||||
| 				log.Println("print error:", err) | ||||
| 			} | ||||
| 		} | ||||
| @ -206,7 +166,7 @@ func handle(w http.ResponseWriter, r *http.Request) { | ||||
| 	} | ||||
| 
 | ||||
| 	w.Header().Set("Content-Type", "image/png") | ||||
| 	if err := png.Encode(w, label); err != nil { | ||||
| 	if err := png.Encode(w, img); err != nil { | ||||
| 		http.Error(w, err.Error(), 500) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										21
									
								
								sklad/db.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								sklad/db.go
									
									
									
									
									
								
							| @ -7,6 +7,8 @@ import ( | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"janouch.name/sklad/bdf" | ||||
| ) | ||||
| 
 | ||||
| type Series struct { | ||||
| @ -46,6 +48,9 @@ type Database struct { | ||||
| 	Prefix     string       // prefix for all container IDs | ||||
| 	Series     []*Series    // all known series | ||||
| 	Containers []*Container // all known containers | ||||
| 
 | ||||
| 	BDFPath  string // path to bitmap font file | ||||
| 	BDFScale int    // integer scaling for the bitmap font | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| @ -57,6 +62,8 @@ var ( | ||||
| 	indexSeries    = map[string]*Series{} | ||||
| 	indexContainer = map[ContainerId]*Container{} | ||||
| 	indexChildren  = map[ContainerId][]*Container{} | ||||
| 
 | ||||
| 	labelFont *bdf.Font | ||||
| ) | ||||
| 
 | ||||
| // TODO: Some functions to add, remove and change things in the database. | ||||
| @ -192,6 +199,20 @@ func loadDatabase() error { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Prepare label printing. | ||||
| 	if db.BDFScale <= 0 { | ||||
| 		db.BDFScale = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	if f, err := os.Open(db.BDFPath); err != nil { | ||||
| 		return fmt.Errorf("cannot load label font: %s", err) | ||||
| 	} else { | ||||
| 		defer f.Close() | ||||
| 		if labelFont, err = bdf.NewFromBDF(f); err != nil { | ||||
| 			return fmt.Errorf("cannot load label font: %s", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Open database log file for appending. | ||||
| 	if dbLog, err = os.OpenFile(dbPath+".log", | ||||
| 		os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil { | ||||
|  | ||||
							
								
								
									
										13
									
								
								sklad/label.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								sklad/label.tmpl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| {{ define "Title" }}Tisk štítku{{ end }} | ||||
| {{ define "Content" }} | ||||
| <h2>Tisk štítku pro {{ .Id }}</h2> | ||||
| 
 | ||||
| {{ if .UnknownId }} | ||||
| <p>Neznámý obal. | ||||
| {{ else if .Error }} | ||||
| <p>Tisk selhal: {{ .Error }} | ||||
| {{ else }} | ||||
| <p>Tisk proběhl úspěšně. | ||||
| {{ end }} | ||||
| 
 | ||||
| {{ end }} | ||||
| @ -1,6 +1,7 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"html/template" | ||||
| 	"io" | ||||
| 	"log" | ||||
| @ -9,6 +10,10 @@ import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"janouch.name/sklad/imgutil" | ||||
| 	"janouch.name/sklad/label" | ||||
| 	"janouch.name/sklad/ql" | ||||
| ) | ||||
| 
 | ||||
| var templates = map[string]*template.Template{} | ||||
| @ -170,18 +175,59 @@ func handleSearch(w http.ResponseWriter, r *http.Request) { | ||||
| 	executeTemplate("search.tmpl", w, ¶ms) | ||||
| } | ||||
| 
 | ||||
| func printLabel(id string) error { | ||||
| 	printer, err := ql.Open() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if printer == nil { | ||||
| 		return errors.New("no suitable printer found") | ||||
| 	} | ||||
| 	defer printer.Close() | ||||
| 
 | ||||
| 	printer.StatusNotify = func(status *ql.Status) { | ||||
| 		log.Printf("\x1b[1mreceived status\x1b[m\n%+v\n%s", | ||||
| 			status[:], status) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := printer.Initialize(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := printer.UpdateStatus(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mediaInfo := ql.GetMediaInfo( | ||||
| 		printer.LastStatus.MediaWidthMM(), | ||||
| 		printer.LastStatus.MediaLengthMM(), | ||||
| 	) | ||||
| 	if mediaInfo == nil { | ||||
| 		return errors.New("unknown media") | ||||
| 	} | ||||
| 
 | ||||
| 	return printer.Print(&imgutil.LeftRotate{Image: label.GenLabelForHeight( | ||||
| 		labelFont, id, mediaInfo.PrintAreaPins, db.BDFScale)}) | ||||
| } | ||||
| 
 | ||||
| func handleLabel(w http.ResponseWriter, r *http.Request) { | ||||
| 	if r.Method != http.MethodPost { | ||||
| 		w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	id := r.FormValue("id") | ||||
| 	_ = id | ||||
| 	params := struct { | ||||
| 		Id        string | ||||
| 		UnknownId bool | ||||
| 		Error     error | ||||
| 	}{ | ||||
| 		Id: r.FormValue("id"), | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: See if such a container exists, print a label on the printer. | ||||
| 
 | ||||
| 	params := struct{}{} | ||||
| 	if c := indexContainer[ContainerId(params.Id)]; c == nil { | ||||
| 		params.UnknownId = true | ||||
| 	} else { | ||||
| 		params.Error = printLabel(params.Id) | ||||
| 	} | ||||
| 
 | ||||
| 	executeTemplate("label.tmpl", w, ¶ms) | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user