diff --git a/print_tape.py b/print_tape.py index 6bfc018..f4d9a61 100644 --- a/print_tape.py +++ b/print_tape.py @@ -16,15 +16,22 @@ from escpos.printer import Dummy from glyphs import price_to_fraction, upload_fractions -# TM-T88V with 90° rotation: Font A chars are 24 dots wide (instead of 12), -# so 512 printable dots / 24 = 21 chars fit across the 80mm paper width. -LINE_WIDTH = 21 +# TM-T88V print area and font metrics +PRINT_WIDTH_DOTS = 512 # 80mm paper printable width +CHAR_WIDTH_DOTS = 24 # Font A rotated 90°: 24 dots wide NUM_COLUMNS = 4 -COL_WIDTH = 4 -EDGE = 1 # 1-char margin on each edge -GAP = 1 # 1-char gap between columns -# Layout: edge(1) + col(4) + gap(1) + col(4) + gap(1) + col(4) + gap(1) + col(4) + edge(1) = 21 -COL_STARTS = [EDGE + i * (COL_WIDTH + GAP) for i in range(NUM_COLUMNS)] + +# The TM-T88V has ~4mm (~28 dot) non-printable margins on each side. +# To make columns look evenly spaced on the paper, we treat the margin +# as part of the edge gap. Setting inter-column gap = margin gives perfect +# symmetry: 5 gaps(28) + 4 cols(107) = 568 paper dots, 512 printable. +MARGIN_DOTS = 28 +PAPER_DOTS = PRINT_WIDTH_DOTS + 2 * MARGIN_DOTS +GAP_DOTS = MARGIN_DOTS +COL_SPAN_DOTS = (PAPER_DOTS - (NUM_COLUMNS + 1) * GAP_DOTS) // NUM_COLUMNS # 107 + +COL_BOTTOM = [(i + 1) * GAP_DOTS + i * COL_SPAN_DOTS - MARGIN_DOTS for i in range(NUM_COLUMNS)] +COL_TOP = [b + COL_SPAN_DOTS - CHAR_WIDTH_DOTS for b in COL_BOTTOM] def format_price(lots, price): @@ -71,6 +78,11 @@ def build_column_chars(trades_in_column): return chars +def _set_pos(p, dots): + """ESC $ nL nH: set absolute horizontal print position in dots.""" + p._raw(b"\x1b\x24" + bytes([dots % 256, dots // 256])) + + def print_all(p, trades): """Print all trades across multiple columns, one row at a time.""" columns = assign_to_columns(trades) @@ -78,16 +90,18 @@ def print_all(p, trades): max_len = max(len(cc) for cc in col_chars) for row_idx in range(max_len): - row = [" "] * LINE_WIDTH for col_idx in range(NUM_COLUMNS): - col_start = COL_STARTS[col_idx] if row_idx < len(col_chars[col_idx]): entry = col_chars[col_idx][row_idx] if entry[0] == "top": - row[col_start + COL_WIDTH - 1] = entry[1] + _set_pos(p, COL_TOP[col_idx]) + p._raw(entry[1].encode()) elif entry[0] == "bottom": - row[col_start] = entry[1] - p.text("".join(row) + "\n") + _set_pos(p, COL_BOTTOM[col_idx]) + p._raw(entry[1].encode()) + p._raw(b"\n") + + return max_len def main(): @@ -112,15 +126,22 @@ def main(): # Upload custom fraction glyphs (⅛ ¼ ⅜ ½ ⅝ ¾ ⅞) upload_fractions(p) - print_all(p, trades) + num_rows = print_all(p, trades) # Feed past the cutter (~20mm above print head) - p.text("\n" * 16) + feed_rows = 16 + p.text("\n" * feed_rows) p.cut() with open(output_file, "wb") as f: f.write(p.output) + + # Calculate print length: each row is 12 dots at 180 DPI + total_rows = num_rows + feed_rows + length_mm = total_rows * 12 / 180 * 25.4 + length_in = total_rows * 12 / 180 print(f"Wrote {len(p.output)} bytes to {output_file}", file=sys.stderr) + print(f"{num_rows} rows, {length_mm:.0f}mm ({length_in:.1f}in) of tape", file=sys.stderr) if __name__ == "__main__":