├── src ├── ts │ ├── cptable.d.ts │ ├── GetPixels.ts │ ├── Enums.ts │ ├── Utils.ts │ ├── Image.ts │ ├── Commands.ts │ └── Document.ts └── tsconfig.json ├── esc-pos-output.jpg ├── LICENSE ├── dist ├── JSESCPOSBuilder.d.ts └── JSESCPOSBuilder.js └── README.md /src/ts/cptable.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace cptable { 2 | export var utils: any; 3 | } -------------------------------------------------------------------------------- /esc-pos-output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodynamic/js-escpos-builder/HEAD/esc-pos-output.jpg -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "outFile": "../dist/JSESCPOSBuilder.js", 5 | "sourceMap": false, 6 | "removeComments": true, 7 | "module": "None", 8 | "strict": false, 9 | "declaration": true, 10 | "lib": ["ES2015", "DOM"] 11 | }, 12 | "include": ["ts/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /src/ts/GetPixels.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export type PixelsStruct = { 3 | data: Uint8Array, 4 | shape: number[], 5 | stride: number[] 6 | } 7 | export class GetPixels { 8 | public static getPixels(b64_image: string): Promise { 9 | return new Promise((ok, err) => { 10 | let img = new Image(); 11 | img.crossOrigin = "Anonymous"; 12 | img.onload = () => { 13 | let canvas = document.createElement('canvas'); 14 | canvas.width = img.width; 15 | canvas.height = img.height; 16 | let context = canvas.getContext('2d'); 17 | context.drawImage(img, 0, 0); 18 | let pixels = context.getImageData(0, 0, img.width, img.height); 19 | ok({ data: new Uint8Array(pixels.data), shape: [img.width, img.height, 4], stride: [4, 4 * img.width, 1] }); 20 | } 21 | img.onerror = (e) => { err(e); } 22 | img.src = b64_image; 23 | }); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Neodynamic Dev Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/ts/Enums.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export enum PrinterModel { 3 | Generic, 4 | } 5 | export enum FeedControlSequence { 6 | PrintLineFeed, 7 | PrintFeedPaper, 8 | FormFeed, 9 | CarriageReturn, 10 | HorizontalTab, 11 | VerticalTab, 12 | } 13 | export enum TextAlignment { 14 | LeftJustification, 15 | Center, 16 | RightJustification, 17 | } 18 | 19 | export enum FontFamily { 20 | A, 21 | B, 22 | C, 23 | } 24 | 25 | export enum FontStyle { 26 | Bold, 27 | Italic, 28 | Underline, 29 | Underline2, 30 | } 31 | 32 | export enum Hardware { 33 | Init, 34 | Select, 35 | Reset, 36 | } 37 | 38 | export enum Barcode1DType { 39 | UPC_A, 40 | UPC_E, 41 | EAN13, 42 | EAN8, 43 | CODE39, 44 | ITF, 45 | CODE93, 46 | CODE128, 47 | CODABAR 48 | } 49 | 50 | export enum BarcodeTextPosition { 51 | Off, 52 | Above, 53 | Below, 54 | AboveAndBelow 55 | } 56 | 57 | export enum BarcodeFont { 58 | A, 59 | B 60 | } 61 | 62 | export enum QRLevel { 63 | L, 64 | M, 65 | Q, 66 | H 67 | } 68 | 69 | export enum BitmapDensity { 70 | S8, 71 | D8, 72 | S24, 73 | D24 74 | } 75 | } -------------------------------------------------------------------------------- /src/ts/Utils.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export class Utils { 3 | public static isValidUInt8(value: number) { 4 | return value == new Uint8Array([value])[0]; 5 | } 6 | 7 | public static repeat(value: any, count: number): any[] { 8 | let buf = []; 9 | for (var i = 0; i < count; i++) buf.push(value); 10 | return buf; 11 | } 12 | 13 | public static getParityBit(code: string): number { 14 | let parity = 0; 15 | let code_r = code.split('').reverse().join(''); 16 | for(var i = 0; i < code_r.length; i++) { 17 | parity += parseInt(code_r.charAt(i), 10) * Math.pow(3, ((i + 1) % 2)); 18 | } 19 | return ((10 - (parity % 10)) % 10).toString().charCodeAt(0); 20 | } 21 | 22 | public static check4CPTable() { 23 | if (!('cptable' in window)) { 24 | throw "cptable.js and cputils.js files from " + 25 | "https://github.com/SheetJS/js-codepage" + 26 | "project are missing"; 27 | } 28 | } 29 | 30 | public static int32ToArray(number: number): number[] { 31 | return [number & 0xFF, 32 | (number >> 8) & 0xFF, 33 | (number >> 16) & 0xFF, 34 | (number >> 24) & 0xFF]; 35 | } 36 | 37 | public static int16ToArray(number: number): number[] { 38 | return [number & 0xFF, 39 | (number >> 8) & 0xFF]; 40 | } 41 | 42 | public static codeLengthUInt16(code: string): number[] { 43 | return this.int16ToArray(code.length); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/ts/Image.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export class ESCPOSImageSize { 3 | public width: number = 0; 4 | public height: number = 0; 5 | public colors: number = 0; 6 | 7 | constructor(width?: number, height?: number, colors?: number) { 8 | if (width) 9 | this.width = width; 10 | if (height) 11 | this.height = height; 12 | if (colors) 13 | this.colors = colors; 14 | } 15 | } 16 | 17 | type ESCPOSImagePixel = { 18 | r: number, 19 | g: number, 20 | b: number, 21 | a: number 22 | }; 23 | 24 | export class ESCPOSImage { 25 | public pixels?: PixelsStruct; 26 | public data: number[] = []; 27 | 28 | private rgb(pixel: number[]): ESCPOSImagePixel { 29 | return { 30 | r: pixel[0], 31 | g: pixel[1], 32 | b: pixel[2], 33 | a: pixel[3] 34 | }; 35 | } 36 | 37 | constructor(pixels: PixelsStruct) { 38 | this.pixels = pixels; 39 | if (!this.size) 40 | throw "Invalid size"; 41 | let temp_arr: ESCPOSImagePixel[] = []; 42 | for (var i = 0; i < this.pixels.data.length; i += this.size.colors) { 43 | let color_arr = new Array(this.size.colors).fill(0); 44 | let d = this.rgb(color_arr.map((_, b) => this.pixels!.data[i + b])); 45 | temp_arr.push(d); 46 | }; 47 | 48 | this.data = temp_arr.map((pixel) => { 49 | if (pixel.a == 0) return 0; 50 | return pixel.r !== 0xFF || pixel.g !== 0xFF || pixel.b !== 0xFF ? 1 : 0; 51 | }); 52 | } 53 | 54 | public static load(b64_image: string): Promise { 55 | return new Promise((ok, err) => { 56 | GetPixels.getPixels(b64_image) 57 | .then((value: PixelsStruct) => { 58 | ok(new ESCPOSImage(value)); 59 | }) 60 | .catch((reason) => { 61 | err(reason); 62 | }); 63 | }); 64 | } 65 | 66 | get size(): ESCPOSImageSize | undefined { 67 | if (!this.pixels) 68 | return undefined; 69 | return new ESCPOSImageSize(this.pixels.shape[0], this.pixels.shape[1], this.pixels.shape[2]); 70 | } 71 | 72 | public toBitmap(density: number) { 73 | if (!this.size) 74 | return undefined; 75 | 76 | density = density || 24; 77 | 78 | var ld: number[] = []; 79 | var result: number[][] = []; 80 | var x: number, y: number, b: number, l: number, i: number; 81 | var c = density / 8; 82 | var n = Math.ceil(this.size.height / density); 83 | 84 | for (y = 0; y < n; y++) { 85 | ld = []; 86 | result[y] = []; 87 | for (x = 0; x < this.size.width; x++) { 88 | 89 | for (b = 0; b < density; b++) { 90 | i = x * c + (b >> 3); 91 | 92 | if (ld[i] === undefined) { 93 | ld[i] = 0; 94 | } 95 | 96 | l = y * density + b; 97 | if (l < this.size.height) { 98 | if (this.data[l * this.size.width + x]) { 99 | ld[i] += (0x80 >> (b & 0x7)); 100 | } 101 | } 102 | } 103 | } 104 | result[y] = ld; 105 | } 106 | 107 | return { 108 | data: result, 109 | density: density 110 | }; 111 | } 112 | 113 | public toRaster() { 114 | if (!this.size) 115 | return undefined; 116 | var result = []; 117 | var width = this.size.width; 118 | var height = this.size.height; 119 | var data = this.data; 120 | 121 | // n blocks of lines 122 | var n = Math.ceil(width / 8); 123 | var x: number, y: number, b: number, c: number, i: number; 124 | 125 | for (y = 0; y < height; y++) { 126 | 127 | for (x = 0; x < n; x++) { 128 | 129 | for (b = 0; b < 8; b++) { 130 | i = x * 8 + b; 131 | 132 | if (result[y * n + x] === undefined) { 133 | result[y * n + x] = 0; 134 | } 135 | 136 | c = x * 8 + b; 137 | if (c < width) { 138 | if (data[y * width + i]) { 139 | result[y * n + x] += (0x80 >> (b & 0x7)); 140 | } 141 | } 142 | } 143 | } 144 | } 145 | return { 146 | data: result, 147 | width: n, 148 | height: height 149 | }; 150 | } 151 | } 152 | } -------------------------------------------------------------------------------- /src/ts/Commands.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export class Constants { 3 | static readonly LF: number[] = [10]; 4 | static readonly FS: number[] = [28]; 5 | static readonly FF: number[] = [12]; 6 | static readonly GS: number[] = [29]; 7 | static readonly DLE: number[] = [16]; 8 | static readonly EOT: number[] = [4]; 9 | static readonly NUL: number[] = [0]; 10 | static readonly ESC: number[] = [27]; 11 | static readonly TAB: number[] = [116]; 12 | static readonly EOL: number[] = [10]; 13 | static readonly BEEP: number[] = [27, 66]; 14 | static readonly TXT_ALIGNMENT: number[] = [27, 97]; 15 | static readonly TXT_FONT_FAMILY: number[] = [27, 77]; 16 | } 17 | 18 | export class FeedControlSequences { 19 | static readonly LF: number[] = [10]; 20 | static readonly GLF: number[] = [74, 0]; 21 | static readonly FF: number[] = [12]; 22 | static readonly CR: number[] = [13]; 23 | static readonly HT: number[] = [9]; 24 | static readonly VT: number[] = [11]; 25 | } 26 | export class CharacterSpacing { 27 | static readonly DEFAULT: number[] = [27, 32, 0]; 28 | static readonly SET: number[] = [27, 32]; 29 | } 30 | export class LineSpacing { 31 | static readonly DEFAULT: number[] = [27, 50]; 32 | static readonly SET: number[] = [27, 51]; 33 | } 34 | export class HardwareOpt { 35 | static readonly INIT: number[] = [27, 64]; 36 | static readonly SELECT: number[] = [27, 61, 1]; 37 | static readonly RESET: number[] = [27, 63, 10, 0]; 38 | } 39 | export class CashDrawer { 40 | static readonly KICK_2: number[] = [27, 112, 0, 25, 250]; 41 | static readonly KICK_5: number[] = [27, 112, 1, 25, 250]; 42 | } 43 | export class Margins { 44 | static readonly BOTTOM: number[] = [27, 79]; 45 | static readonly LEFT: number[] = [27, 108]; 46 | static readonly RIGHT: number[] = [27, 81]; 47 | } 48 | export class Paper { 49 | static readonly FULL_CUT: number[] = [29, 86, 0]; 50 | static readonly PART_CUT: number[] = [29, 86, 1]; 51 | static readonly CUT_A: number[] = [29, 86, 65]; 52 | static readonly CUT_B: number[] = [29, 86, 66]; 53 | } 54 | export class TextFormat { 55 | static readonly NORMAL: number[] = [27, 33, 0]; 56 | static readonly TWO_HEIGHT: number[] = [27, 33, 16]; 57 | static readonly TWO_WIDTH: number[] = [27, 33, 32]; 58 | static readonly FOUR_SQUARE: number[] = [27, 33, 48]; 59 | static CUSTOM_SIZE(width: number, height: number): number[] { 60 | if (width < 0) throw "Min size 0"; 61 | if (width > 8) throw "Max size 7"; 62 | if (height < 0) throw "Min size 0"; 63 | if (height > 8) throw "Max size 7"; 64 | return [29, 33, (width * 16) + height]; 65 | } 66 | static HEIGHT(size: number): number[] { 67 | if (size < 1) throw "Min size 1"; 68 | if (size > 7) throw "Max size 7"; 69 | return [size - 1]; 70 | } 71 | static WIDTH(size: number): number[] { 72 | if (size < 1) throw "Min size 1"; 73 | if (size > 7) throw "Max size 7"; 74 | return [(size - 1) * 16]; 75 | } 76 | static readonly UNDERL_OFF: number[] = [27, 45, 0]; 77 | static readonly UNDERL_ON: number[] = [27, 45, 1]; 78 | static readonly UNDERL2_ON: number[] = [27, 45, 2]; 79 | static readonly BOLD_OFF: number[] = [27, 69, 0]; 80 | static readonly BOLD_ON: number[] = [27, 69, 1]; 81 | static readonly ITALIC_OFF: number[] = [27, 53]; 82 | static readonly ITALIC_ON: number[] = [27, 52]; 83 | } 84 | export class BarcodeFormat { 85 | static readonly TXT_OFF: number[] = [29, 72, 0]; 86 | static readonly TXT_ABV: number[] = [29, 72, 1]; 87 | static readonly TXT_BLW: number[] = [29, 72, 2]; 88 | static readonly TXT_BTH: number[] = [29, 72, 3]; 89 | static readonly FONT_A: number[] = [29, 102, 0]; 90 | static readonly FONT_B: number[] = [29, 102, 1]; 91 | static HEIGHT(height: number): number[] { 92 | return [29, 104, height]; 93 | } 94 | static WIDTH(size: number): number[] { 95 | if (size < 1) throw "Min size 1"; 96 | if (size > 5) throw "Max size 5"; 97 | return [29, 119, size + 1]; 98 | } 99 | static readonly HEIGHT_DEFAULT: number[] = [29, 104, 100]; 100 | static readonly WIDTH_DEFAULT: number[] = [29, 119, 1]; 101 | static readonly UPC_A: number[] = [29, 107, 0]; 102 | static readonly UPC_E: number[] = [29, 107, 1]; 103 | static readonly EAN13: number[] = [29, 107, 2]; 104 | static readonly EAN8: number[] = [29, 107, 3]; 105 | static readonly CODE39: number[] = [29, 107, 4]; 106 | static readonly ITF: number[] = [29, 107, 5]; 107 | static readonly CODABAR: number[] = [29, 107, 6]; 108 | static readonly CODE93: number[] = [29, 107, 72]; 109 | static readonly CODE128: number[] = [29, 107, 73]; 110 | } 111 | export class Code2DFormat { 112 | static readonly TYPE_PDF417: number[] = [29, 90, 0]; 113 | static readonly TYPE_DATAMATRIX: number[] = [29, 90, 1]; 114 | static readonly TYPE_QR: number[] = [29, 90, 2]; 115 | static readonly CODE2D: number[] = [27, 90]; 116 | static readonly QR_LEVEL_L: number[] = [76]; 117 | static readonly QR_LEVEL_M: number[] = [77]; 118 | static readonly QR_LEVEL_Q: number[] = [81]; 119 | static readonly QR_LEVEL_H: number[] = [72]; 120 | } 121 | export class ImageFormat { 122 | static readonly NORMAL: number[] = [29, 118, 48, 0]; 123 | static readonly DOUBLE_WIDTH: number[] = [29, 118, 48, 1]; 124 | static readonly DOUBLE_HEIGHT: number[] = [29, 118, 48, 2]; 125 | static readonly QUAD: number[] = [29, 118, 48, 3]; 126 | } 127 | export class BitmapFormat { 128 | static readonly S8: number[] = [27, 42, 0]; 129 | static readonly D8: number[] = [27, 42, 1]; 130 | static readonly S24: number[] = [27, 42, 32]; 131 | static readonly D24: number[] = [27, 42, 33]; 132 | } 133 | export class GSV0Format { 134 | static readonly NORMAL: number[] = [29, 118, 48, 0]; 135 | static readonly DW: number[] = [29, 118, 48, 1]; 136 | static readonly DH: number[] = [29, 118, 48, 2]; 137 | static readonly DWDH: number[] = [29, 118, 48, 3]; 138 | } 139 | 140 | export class Color { 141 | static readonly BLACK: number[] = [27, 114, 0]; 142 | static readonly RED: number[] = [27, 114, 1]; 143 | static readonly REVERSE: number[] = [29, 66, 49]; 144 | static readonly UNREVERSE: number[] = [29, 66, 48]; 145 | } 146 | export class Screen { 147 | static readonly BS: number[] = [8]; 148 | static readonly HT: number[] = [9]; 149 | static readonly LF: number[] = [10]; 150 | static readonly US_LF: number[] = [31, 10]; 151 | static readonly HOM: number[] = [11]; 152 | static readonly CR: number[] = [13]; 153 | static readonly US_CR: number[] = [31, 13]; 154 | static readonly US_B: number[] = [31, 66]; 155 | static readonly US_$: number[] = [31, 36]; 156 | static readonly CLR: number[] = [12]; 157 | static readonly CAN: number[] = [24]; 158 | static readonly US_MD1: number[] = [31, 1]; 159 | static readonly US_MD2: number[] = [31, 2]; 160 | static readonly US_MD3: number[] = [31, 3]; 161 | static readonly US_C: number[] = [31, 67]; 162 | static readonly US_E: number[] = [31, 69]; 163 | static readonly US_T: number[] = [31, 84]; 164 | static readonly US_U: number[] = [31, 85]; 165 | static readonly US_X: number[] = [31, 88]; 166 | static readonly US_r: number[] = [31, 114]; 167 | static readonly US_v: number[] = [31, 118]; 168 | } 169 | 170 | export class Barcode1DOptions { 171 | public width?: number; 172 | public height?: number; 173 | public position: BarcodeTextPosition = BarcodeTextPosition.Below; 174 | public include_parity: boolean = true; 175 | public font: BarcodeFont = BarcodeFont.A; 176 | 177 | constructor(width? :number, height?: number, include_parity = true, 178 | position = BarcodeTextPosition.Below, font = BarcodeFont.A) { 179 | this.width = width; 180 | this.height = height; 181 | this.position = position; 182 | this.include_parity = include_parity; 183 | this.font = font; 184 | } 185 | } 186 | 187 | export class BarcodePDF417Options { 188 | width: number = 3; 189 | height_multiplier: number = 3; 190 | data_column_count: number = 0; 191 | error_ratio: number = 0.1; 192 | truncated: boolean = false; 193 | 194 | constructor(width = 3, height_multiplier = 3, data_column_count = 0, 195 | error_ratio = 0.1, truncated = false) { 196 | this.width = width; 197 | this.height_multiplier = height_multiplier; 198 | this.data_column_count = data_column_count; 199 | this.error_ratio = error_ratio; 200 | this.truncated = truncated; 201 | } 202 | } 203 | 204 | export class BarcodeQROptions { 205 | level: QRLevel = QRLevel.L; 206 | size: number = 6; 207 | 208 | constructor(level = QRLevel.L, size = 6) { 209 | this.level = level; 210 | this.size = size; 211 | } 212 | } 213 | } -------------------------------------------------------------------------------- /dist/JSESCPOSBuilder.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Neodynamic.JSESCPOSBuilder { 2 | class Constants { 3 | static readonly LF: number[]; 4 | static readonly FS: number[]; 5 | static readonly FF: number[]; 6 | static readonly GS: number[]; 7 | static readonly DLE: number[]; 8 | static readonly EOT: number[]; 9 | static readonly NUL: number[]; 10 | static readonly ESC: number[]; 11 | static readonly TAB: number[]; 12 | static readonly EOL: number[]; 13 | static readonly BEEP: number[]; 14 | static readonly TXT_ALIGNMENT: number[]; 15 | static readonly TXT_FONT_FAMILY: number[]; 16 | } 17 | class FeedControlSequences { 18 | static readonly LF: number[]; 19 | static readonly GLF: number[]; 20 | static readonly FF: number[]; 21 | static readonly CR: number[]; 22 | static readonly HT: number[]; 23 | static readonly VT: number[]; 24 | } 25 | class CharacterSpacing { 26 | static readonly DEFAULT: number[]; 27 | static readonly SET: number[]; 28 | } 29 | class LineSpacing { 30 | static readonly DEFAULT: number[]; 31 | static readonly SET: number[]; 32 | } 33 | class HardwareOpt { 34 | static readonly INIT: number[]; 35 | static readonly SELECT: number[]; 36 | static readonly RESET: number[]; 37 | } 38 | class CashDrawer { 39 | static readonly KICK_2: number[]; 40 | static readonly KICK_5: number[]; 41 | } 42 | class Margins { 43 | static readonly BOTTOM: number[]; 44 | static readonly LEFT: number[]; 45 | static readonly RIGHT: number[]; 46 | } 47 | class Paper { 48 | static readonly FULL_CUT: number[]; 49 | static readonly PART_CUT: number[]; 50 | static readonly CUT_A: number[]; 51 | static readonly CUT_B: number[]; 52 | } 53 | class TextFormat { 54 | static readonly NORMAL: number[]; 55 | static readonly TWO_HEIGHT: number[]; 56 | static readonly TWO_WIDTH: number[]; 57 | static readonly FOUR_SQUARE: number[]; 58 | static CUSTOM_SIZE(width: number, height: number): number[]; 59 | static HEIGHT(size: number): number[]; 60 | static WIDTH(size: number): number[]; 61 | static readonly UNDERL_OFF: number[]; 62 | static readonly UNDERL_ON: number[]; 63 | static readonly UNDERL2_ON: number[]; 64 | static readonly BOLD_OFF: number[]; 65 | static readonly BOLD_ON: number[]; 66 | static readonly ITALIC_OFF: number[]; 67 | static readonly ITALIC_ON: number[]; 68 | } 69 | class BarcodeFormat { 70 | static readonly TXT_OFF: number[]; 71 | static readonly TXT_ABV: number[]; 72 | static readonly TXT_BLW: number[]; 73 | static readonly TXT_BTH: number[]; 74 | static readonly FONT_A: number[]; 75 | static readonly FONT_B: number[]; 76 | static HEIGHT(height: number): number[]; 77 | static WIDTH(size: number): number[]; 78 | static readonly HEIGHT_DEFAULT: number[]; 79 | static readonly WIDTH_DEFAULT: number[]; 80 | static readonly UPC_A: number[]; 81 | static readonly UPC_E: number[]; 82 | static readonly EAN13: number[]; 83 | static readonly EAN8: number[]; 84 | static readonly CODE39: number[]; 85 | static readonly ITF: number[]; 86 | static readonly CODABAR: number[]; 87 | static readonly CODE93: number[]; 88 | static readonly CODE128: number[]; 89 | } 90 | class Code2DFormat { 91 | static readonly TYPE_PDF417: number[]; 92 | static readonly TYPE_DATAMATRIX: number[]; 93 | static readonly TYPE_QR: number[]; 94 | static readonly CODE2D: number[]; 95 | static readonly QR_LEVEL_L: number[]; 96 | static readonly QR_LEVEL_M: number[]; 97 | static readonly QR_LEVEL_Q: number[]; 98 | static readonly QR_LEVEL_H: number[]; 99 | } 100 | class ImageFormat { 101 | static readonly NORMAL: number[]; 102 | static readonly DOUBLE_WIDTH: number[]; 103 | static readonly DOUBLE_HEIGHT: number[]; 104 | static readonly QUAD: number[]; 105 | } 106 | class BitmapFormat { 107 | static readonly S8: number[]; 108 | static readonly D8: number[]; 109 | static readonly S24: number[]; 110 | static readonly D24: number[]; 111 | } 112 | class GSV0Format { 113 | static readonly NORMAL: number[]; 114 | static readonly DW: number[]; 115 | static readonly DH: number[]; 116 | static readonly DWDH: number[]; 117 | } 118 | class Color { 119 | static readonly BLACK: number[]; 120 | static readonly RED: number[]; 121 | static readonly REVERSE: number[]; 122 | static readonly UNREVERSE: number[]; 123 | } 124 | class Screen { 125 | static readonly BS: number[]; 126 | static readonly HT: number[]; 127 | static readonly LF: number[]; 128 | static readonly US_LF: number[]; 129 | static readonly HOM: number[]; 130 | static readonly CR: number[]; 131 | static readonly US_CR: number[]; 132 | static readonly US_B: number[]; 133 | static readonly US_$: number[]; 134 | static readonly CLR: number[]; 135 | static readonly CAN: number[]; 136 | static readonly US_MD1: number[]; 137 | static readonly US_MD2: number[]; 138 | static readonly US_MD3: number[]; 139 | static readonly US_C: number[]; 140 | static readonly US_E: number[]; 141 | static readonly US_T: number[]; 142 | static readonly US_U: number[]; 143 | static readonly US_X: number[]; 144 | static readonly US_r: number[]; 145 | static readonly US_v: number[]; 146 | } 147 | class Barcode1DOptions { 148 | width?: number; 149 | height?: number; 150 | position: BarcodeTextPosition; 151 | include_parity: boolean; 152 | font: BarcodeFont; 153 | constructor(width?: number, height?: number, include_parity?: boolean, position?: BarcodeTextPosition, font?: BarcodeFont); 154 | } 155 | class BarcodePDF417Options { 156 | width: number; 157 | height_multiplier: number; 158 | data_column_count: number; 159 | error_ratio: number; 160 | truncated: boolean; 161 | constructor(width?: number, height_multiplier?: number, data_column_count?: number, error_ratio?: number, truncated?: boolean); 162 | } 163 | class BarcodeQROptions { 164 | level: QRLevel; 165 | size: number; 166 | constructor(level?: QRLevel, size?: number); 167 | } 168 | } 169 | declare namespace Neodynamic.JSESCPOSBuilder { 170 | class Document { 171 | private _buffer; 172 | model: PrinterModel; 173 | encoding: number; 174 | width: number; 175 | constructor(); 176 | private _addB; 177 | setCharacterCodeTable(code_table: number): Document; 178 | setPrintWidth(newWidth: number): Document; 179 | marginBottom(size: number): Document; 180 | marginLeft(size: number): Document; 181 | marginRight(size: number): Document; 182 | newLine(): Document; 183 | drawLine(new_line?: boolean): Document; 184 | drawTable(data: string[]): Document; 185 | feed(lines?: number): Document; 186 | control(sequence: FeedControlSequence): Document; 187 | align(alignment: TextAlignment): Document; 188 | font(family: FontFamily): Document; 189 | style(styles: Array): Document; 190 | size(width: number, height: number): Document; 191 | charSpacing(value?: number): Document; 192 | lineSpacing(value?: number): Document; 193 | hardware(hardware: Hardware): Document; 194 | linearBarcode(code: string, type: Barcode1DType, options?: Barcode1DOptions): Document; 195 | private _wrapperSend2DCodeData; 196 | qrCode(code: string, options?: BarcodeQROptions): Document; 197 | pdf417(code: string, options?: BarcodePDF417Options): Document; 198 | cashDraw(pin?: number): Document; 199 | beep(times: number, length: number): Document; 200 | cut(feed?: number, partial_cut?: boolean): Document; 201 | setColorMode(color: boolean): Document; 202 | reverseColors(reverse: boolean): Document; 203 | raw(data: number[]): Document; 204 | text(content: string, override_encoding?: number): Document; 205 | image(image: ESCPOSImage, density?: BitmapDensity): Document; 206 | generateUInt8Array(): Uint8Array; 207 | generateArray(): number[]; 208 | } 209 | } 210 | declare namespace Neodynamic.JSESCPOSBuilder { 211 | enum PrinterModel { 212 | Generic = 0 213 | } 214 | enum FeedControlSequence { 215 | PrintLineFeed = 0, 216 | PrintFeedPaper = 1, 217 | FormFeed = 2, 218 | CarriageReturn = 3, 219 | HorizontalTab = 4, 220 | VerticalTab = 5 221 | } 222 | enum TextAlignment { 223 | LeftJustification = 0, 224 | Center = 1, 225 | RightJustification = 2 226 | } 227 | enum FontFamily { 228 | A = 0, 229 | B = 1, 230 | C = 2 231 | } 232 | enum FontStyle { 233 | Bold = 0, 234 | Italic = 1, 235 | Underline = 2, 236 | Underline2 = 3 237 | } 238 | enum Hardware { 239 | Init = 0, 240 | Select = 1, 241 | Reset = 2 242 | } 243 | enum Barcode1DType { 244 | UPC_A = 0, 245 | UPC_E = 1, 246 | EAN13 = 2, 247 | EAN8 = 3, 248 | CODE39 = 4, 249 | ITF = 5, 250 | CODE93 = 6, 251 | CODE128 = 7, 252 | CODABAR = 8 253 | } 254 | enum BarcodeTextPosition { 255 | Off = 0, 256 | Above = 1, 257 | Below = 2, 258 | AboveAndBelow = 3 259 | } 260 | enum BarcodeFont { 261 | A = 0, 262 | B = 1 263 | } 264 | enum QRLevel { 265 | L = 0, 266 | M = 1, 267 | Q = 2, 268 | H = 3 269 | } 270 | enum BitmapDensity { 271 | S8 = 0, 272 | D8 = 1, 273 | S24 = 2, 274 | D24 = 3 275 | } 276 | } 277 | declare namespace Neodynamic.JSESCPOSBuilder { 278 | type PixelsStruct = { 279 | data: Uint8Array; 280 | shape: number[]; 281 | stride: number[]; 282 | }; 283 | class GetPixels { 284 | static getPixels(b64_image: string): Promise; 285 | } 286 | } 287 | declare namespace Neodynamic.JSESCPOSBuilder { 288 | class ESCPOSImageSize { 289 | width: number; 290 | height: number; 291 | colors: number; 292 | constructor(width?: number, height?: number, colors?: number); 293 | } 294 | class ESCPOSImage { 295 | pixels?: PixelsStruct; 296 | data: number[]; 297 | private rgb; 298 | constructor(pixels: PixelsStruct); 299 | static load(b64_image: string): Promise; 300 | get size(): ESCPOSImageSize | undefined; 301 | toBitmap(density: number): { 302 | data: number[][]; 303 | density: number; 304 | }; 305 | toRaster(): { 306 | data: any[]; 307 | width: number; 308 | height: number; 309 | }; 310 | } 311 | } 312 | declare namespace Neodynamic.JSESCPOSBuilder { 313 | class Utils { 314 | static isValidUInt8(value: number): boolean; 315 | static repeat(value: any, count: number): any[]; 316 | static getParityBit(code: string): number; 317 | static check4CPTable(): void; 318 | static int32ToArray(number: number): number[]; 319 | static int16ToArray(number: number): number[]; 320 | static codeLengthUInt16(code: string): number[]; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSESCPOSBuilder - ESC/POS Commands Builder for Javascript 2 | 3 | **Generates EPSON ESC/POS-compatible commands from Javascript!** Support most ESC/POS commands for printing **Images** (Logos, Symbols, etc), 4 | **Texts** (Normal, Bold, Italic, Alignment, etc), **Linear/1D Barcodes** (like Code 39, Code 128, EAN-UPC, etc), **2D Barcodes** (like QR Code, PDF417), and 5 | special commands like **paper cut, cashdraw, beep, and feed.** 6 | 7 | To **print/send** the generated **ESC/POS** commands from a **website/page/view _(written by using any web framework like React, Angular, Vue, ASP.NET, PHP, Django, etc)_ to the client printer** you can use the [**JSPrintManager**](https://github.com/neodynamic/JSPrintManager) solution. 8 | 9 | Project code is available in **Typescript** and plain **Javascript** code. 10 | 11 | ## Credits 12 | Most of the code of this project was based on the [https://github.com/escpos/node-escpos](https://github.com/escpos/node-escpos) and [https://github.com/mike42/escpos-php](https://github.com/mike42/escpos-php) projects 13 | 14 | ## Licenses 15 | 16 | - The **JSESCPOSBuilder** code is licensed under **MIT License** 17 | 18 | - The [**JSPrintManager**](https://www.neodynamic.com/products/printing/js-print-manager) solution is a [**Commercial product licensed under these terms**](https://neodynamic.com/eula) 19 | 20 | ## Dependencies 21 | 22 | - [https://github.com/SheetJS/js-codepage](https://github.com/SheetJS/js-codepage) 23 | 24 | ## Example: How to generate ESC/POS commands and print them through [**JSPrintManager**](https://www.neodynamic.com/products/printing/js-print-manager) 25 | 26 | ![ESC/POS Printing output from Javascript](esc-pos-output.jpg) 27 | 28 | ```html 29 | 30 | 31 | 32 | Advanced ESC/POS Printing from Javascript 33 | 34 | 35 | 36 | 37 |
38 |

Advanced ESC/POS Printing from Javascript

39 |
40 | 43 |

or...

44 |
45 | 46 | 47 |
48 |

49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 148 | 149 | 150 | ``` 151 | 152 | ## About ESC/POS International Text 153 | 154 | To print text in different languages you must be sure that the printer supports it. After that confirmation, you must specify the correct [**ESC/POS CodePage**](https://reference.epson-biz.com/modules/ref_charcode_en/index.php?content_id=1) (which might differ from ESC/POS compatible printers that are not from EPSON company) by using the `setCharacterCodeTable()` function and also specify the code page (from [https://github.com/SheetJS/js-codepage#generated-codepages](https://github.com/SheetJS/js-codepage#generated-codepages)) to the `text()` function. 155 | 156 | > IMPORTANT: Not all printers support a given CodePage so please refer to the manufacturer for further details. The following [json file](https://github.com/mike42/escpos-php/blob/development/src/Mike42/Escpos/resources/capabilities.json) used by excellent project [https://github.com/mike42/escpos-php](https://github.com/mike42/escpos-php) 157 | lists many printer models and the codePages supported by them. Anyway, always ask to the manufacturer for assistance. 158 | 159 | The following sample code generates ESC/POS commands for texts in different languages based on EPSON printers. 160 | ```js 161 | var escposCommands = doc 162 | .font(escpos.FontFamily.B) 163 | .size(0, 0) 164 | // Windows-1252 Western European: Supports French, Spanish, Italian, Portuguese, German 165 | .setCharacterCodeTable(16) // WPC1252 from EPSON CodePage 166 | .text("Voix ambiguë d'un cœur qui, au zéphyr, préfère les jattes de kiwis", 1252) // French 167 | .text("Tendré que ir a España. ¿Cómo? Por avión.", 1252) // Spanish 168 | .text("L'articolo è uno. Uno scontrino, perché? Perché la parola inizia per s più consonante.", 1252) // Italian 169 | .text("Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.", 1252) // Portuguese 170 | .text("Köln ist größer als Garmisch Partenkirchen. Der Rhein ist länger als die Mosel.", 1252) // German 171 | // Greek 172 | .setCharacterCodeTable(14) // PC737 from EPSON CodePage 173 | .text("καλημέρα", 737) 174 | // Russian Cyrillic 175 | .setCharacterCodeTable(17) // PC866 from EPSON CodePage 176 | .text("Быстрая коричневая лиса прыгает через ленивую собаку", 866) 177 | 178 | .feed(5) 179 | .cut() 180 | .generateUInt8Array(); 181 | ``` 182 | -------------------------------------------------------------------------------- /src/ts/Document.ts: -------------------------------------------------------------------------------- 1 | namespace Neodynamic.JSESCPOSBuilder { 2 | export class Document { 3 | private _buffer: number[] = []; 4 | public model: PrinterModel = PrinterModel.Generic; 5 | public encoding = 858; 6 | public width: number = 48; 7 | 8 | constructor() { 9 | Utils.check4CPTable(); 10 | } 11 | 12 | private _addB(value: number[][]) { 13 | for (var i = 0; i < value.length; i++) 14 | this._buffer = this._buffer.concat(value[i]); 15 | } 16 | public setCharacterCodeTable(code_table: number): Document { 17 | if (!Utils.isValidUInt8(code_table)) throw "Invalid code table"; 18 | this._addB([ 19 | Constants.ESC, 20 | Constants.TAB, 21 | [code_table], 22 | ]); 23 | return this; 24 | } 25 | 26 | public setPrintWidth(newWidth: number): Document { 27 | this.width = newWidth; 28 | this._addB([ 29 | Constants.GS, 30 | [87], 31 | Utils.int16ToArray(newWidth), 32 | ]); 33 | return this; 34 | } 35 | 36 | public marginBottom(size: number): Document { 37 | if (!Utils.isValidUInt8(size)) throw "Invalid size"; 38 | this._addB([Margins.BOTTOM, [size]]); 39 | return this; 40 | } 41 | 42 | public marginLeft(size: number): Document { 43 | if (!Utils.isValidUInt8(size)) throw "Invalid size"; 44 | this._addB([Margins.LEFT, [size]]); 45 | return this; 46 | } 47 | 48 | public marginRight(size: number): Document { 49 | if (!Utils.isValidUInt8(size)) throw "Invalid size"; 50 | this._addB([Margins.RIGHT, [size]]); 51 | return this; 52 | } 53 | 54 | public newLine(): Document { 55 | this._addB([Constants.EOL]); 56 | return this; 57 | } 58 | 59 | public drawLine(new_line = false): Document { 60 | if (new_line) this.newLine(); 61 | this._addB([Utils.repeat("-".charCodeAt(0), this.width)]); 62 | return this; 63 | } 64 | 65 | public drawTable(data: string[]): Document { 66 | let cell_width = this.width / data.length; 67 | let text = ""; 68 | for(var i = 0; i < data.length; i++) { 69 | text += data[i].toString(); 70 | let spaces = cell_width - data[i].toString().length; 71 | text += new Array(spaces + 1).join(' '); 72 | } 73 | this._addB([cptable.utils.encode(this.encoding, text)]); 74 | return this; 75 | } 76 | 77 | public feed(lines: number = 1): Document { 78 | this._addB(Utils.repeat(Constants.EOL, lines)); 79 | return this; 80 | } 81 | 82 | public control(sequence: FeedControlSequence): Document { 83 | let buf: number[][] = []; 84 | switch (sequence) { 85 | case FeedControlSequence.CarriageReturn: 86 | buf = [FeedControlSequences.CR]; 87 | break; 88 | case FeedControlSequence.FormFeed: 89 | buf = [FeedControlSequences.FF]; 90 | break; 91 | case FeedControlSequence.HorizontalTab: 92 | buf = [FeedControlSequences.HT]; 93 | break; 94 | case FeedControlSequence.PrintFeedPaper: 95 | buf = [FeedControlSequences.GLF]; 96 | break; 97 | case FeedControlSequence.PrintLineFeed: 98 | buf = [FeedControlSequences.LF]; 99 | break; 100 | case FeedControlSequence.VerticalTab: 101 | buf = [FeedControlSequences.VT]; 102 | break; 103 | } 104 | this._addB(buf); 105 | return this; 106 | } 107 | 108 | public align(alignment: TextAlignment): Document { 109 | let buf = []; 110 | buf = buf.concat(Constants.TXT_ALIGNMENT); 111 | switch (alignment) { 112 | case TextAlignment.Center: 113 | buf.push(1); 114 | break; 115 | case TextAlignment.LeftJustification: 116 | buf.push(0); 117 | break; 118 | case TextAlignment.RightJustification: 119 | buf.push(2); 120 | break; 121 | } 122 | this._addB([buf]); 123 | return this; 124 | } 125 | 126 | public font(family: FontFamily): Document { 127 | let buf = []; 128 | buf = buf.concat(Constants.TXT_FONT_FAMILY); 129 | switch (family) { 130 | case FontFamily.A: 131 | buf.push(0); 132 | break; 133 | case FontFamily.B: 134 | buf.push(1); 135 | break; 136 | case FontFamily.C: 137 | buf.push(2); 138 | break; 139 | } 140 | this._addB([buf]); 141 | return this; 142 | } 143 | 144 | public style(styles: Array): Document { 145 | let buf: number[][] = []; 146 | if (styles.indexOf(FontStyle.Bold) > -1) 147 | buf.push(TextFormat.BOLD_ON); 148 | else buf.push(TextFormat.BOLD_OFF); 149 | 150 | if (styles.indexOf(FontStyle.Italic) > -1) 151 | buf.push(TextFormat.ITALIC_ON); 152 | else buf.push(TextFormat.ITALIC_OFF); 153 | 154 | if (styles.indexOf(FontStyle.Underline) > -1) 155 | buf.push(TextFormat.UNDERL_ON); 156 | else if (styles.indexOf(FontStyle.Underline2) > -1) 157 | buf.push(TextFormat.UNDERL2_ON); 158 | else buf.push(TextFormat.UNDERL_OFF); 159 | 160 | this._addB(buf); 161 | return this; 162 | } 163 | 164 | public size(width: number, height: number): Document { 165 | let buf = []; 166 | buf = TextFormat.CUSTOM_SIZE(width, height); 167 | this._addB([buf]); 168 | return this; 169 | } 170 | 171 | public charSpacing(value?: number): Document { 172 | let buf: number[][] = []; 173 | if (value || value === 0) { 174 | if (!Utils.isValidUInt8(value)) throw "Invalid value"; 175 | buf.push(CharacterSpacing.SET); 176 | buf.push([value]); 177 | } else { 178 | buf.push(CharacterSpacing.DEFAULT); 179 | } 180 | this._addB(buf); 181 | return this; 182 | } 183 | 184 | public lineSpacing(value?: number): Document { 185 | let buf: number[][] = []; 186 | if (value || value === 0) { 187 | if (!Utils.isValidUInt8(value)) throw "Invalid value"; 188 | buf.push(LineSpacing.SET) 189 | buf.push([value]); 190 | } else { 191 | buf.push(LineSpacing.DEFAULT); 192 | } 193 | this._addB(buf); 194 | return this; 195 | } 196 | 197 | public hardware(hardware: Hardware): Document { 198 | let buf = []; 199 | switch (hardware) { 200 | case Hardware.Init: 201 | buf = HardwareOpt.INIT; 202 | break; 203 | case Hardware.Reset: 204 | buf = HardwareOpt.RESET; 205 | break; 206 | case Hardware.Select: 207 | buf = HardwareOpt.SELECT; 208 | break; 209 | } 210 | this._addB([buf]); 211 | return this; 212 | } 213 | 214 | public linearBarcode(code: string, type: Barcode1DType, 215 | options: Barcode1DOptions = new Barcode1DOptions()): Document { 216 | let buf: number[][] = []; 217 | if(options.width) 218 | buf.push(BarcodeFormat.WIDTH(options.width)); 219 | else 220 | buf.push(BarcodeFormat.WIDTH_DEFAULT); 221 | if(options.height) 222 | buf.push(BarcodeFormat.HEIGHT(options.height)); 223 | else 224 | buf.push(BarcodeFormat.HEIGHT_DEFAULT); 225 | switch (options.font) { 226 | case BarcodeFont.A: { 227 | buf.push(BarcodeFormat.FONT_A); 228 | } break; 229 | case BarcodeFont.B: { 230 | buf.push(BarcodeFormat.FONT_B); 231 | } break; 232 | } 233 | switch (options.position) { 234 | case BarcodeTextPosition.Above: { 235 | buf.push(BarcodeFormat.TXT_ABV); 236 | } break; 237 | case BarcodeTextPosition.AboveAndBelow: { 238 | buf.push(BarcodeFormat.TXT_BTH); 239 | } break; 240 | case BarcodeTextPosition.Below: { 241 | buf.push(BarcodeFormat.TXT_BLW); 242 | } break; 243 | case BarcodeTextPosition.Off: { 244 | buf.push(BarcodeFormat.TXT_OFF); 245 | } break; 246 | } 247 | switch (type) { 248 | case Barcode1DType.CODE39: { 249 | buf.push(BarcodeFormat.CODE39); 250 | } break; 251 | case Barcode1DType.ITF: { 252 | buf.push(BarcodeFormat.ITF); 253 | } break; 254 | case Barcode1DType.UPC_A: { 255 | buf.push(BarcodeFormat.UPC_A); 256 | } break; 257 | case Barcode1DType.UPC_E: { 258 | buf.push(BarcodeFormat.UPC_E); 259 | } break; 260 | case Barcode1DType.CODABAR: { 261 | buf.push(BarcodeFormat.CODABAR); 262 | } break; 263 | case Barcode1DType.CODE128: { 264 | buf.push(BarcodeFormat.CODE128); 265 | buf.push(Utils.codeLengthUInt16(code)); 266 | } break; 267 | case Barcode1DType.CODE93: { 268 | buf.push(BarcodeFormat.CODE93); 269 | buf.push(Utils.codeLengthUInt16(code)); 270 | } break; 271 | case Barcode1DType.EAN13: { 272 | buf.push(BarcodeFormat.EAN13); 273 | } break; 274 | case Barcode1DType.EAN8: { 275 | buf.push(BarcodeFormat.EAN8); 276 | } break; 277 | } 278 | buf.push(cptable.utils.encode(this.encoding, code)); 279 | if (options.include_parity && type in [Barcode1DType.EAN13, Barcode1DType.EAN8]) 280 | buf.push([Utils.getParityBit(code)]); 281 | buf.push([0]); 282 | this._addB(buf); 283 | return this; 284 | } 285 | 286 | private _wrapperSend2DCodeData(func: number, code_type: number, data?: string|number[], modifier?: number) { 287 | let buf: number[][] = []; 288 | let header = Utils.int16ToArray((data != undefined ? data.length : 0) + (modifier != undefined? 1 : 0) + 2); 289 | buf = [Constants.GS, [40, 107], header, [code_type, func]]; 290 | if(modifier != undefined) 291 | buf.push([modifier]); 292 | if(typeof(data) == 'string') 293 | buf.push(cptable.utils.encode(this.encoding, data)); 294 | else 295 | buf.push(data); 296 | this._addB(buf); 297 | } 298 | 299 | public qrCode(code: string, options: BarcodeQROptions = new BarcodeQROptions()): Document { 300 | let ct = 49; 301 | this._wrapperSend2DCodeData(65, ct, [50, 0]); // Model QR 2 302 | this._wrapperSend2DCodeData(67, ct, [options.size]); // Size 303 | this._wrapperSend2DCodeData(69, ct, [48 + options.level]); // Error correction level 304 | this._wrapperSend2DCodeData(80, ct, code, 48); // Send content & print 305 | this._wrapperSend2DCodeData(81, ct, '', 48); 306 | return this; 307 | } 308 | 309 | public pdf417(code: string, options: BarcodePDF417Options = new BarcodePDF417Options()): Document { 310 | let ct = 48; 311 | this._wrapperSend2DCodeData(70, ct, [options.truncated ? 1 : 0]); 312 | this._wrapperSend2DCodeData(65, ct, [options.data_column_count]); 313 | this._wrapperSend2DCodeData(67, ct, [options.width]); 314 | this._wrapperSend2DCodeData(68, ct, [options.height_multiplier]); 315 | let error = Math.ceil(options.error_ratio * 10); 316 | this._wrapperSend2DCodeData(69, ct, [error], 49); 317 | this._wrapperSend2DCodeData(80, ct, code, 48); 318 | this._wrapperSend2DCodeData(81, ct, '', 48); 319 | return this; 320 | } 321 | 322 | public cashDraw(pin: number = 2): Document { 323 | switch (pin) { 324 | case 2: { 325 | this._addB([CashDrawer.KICK_2]); 326 | } break; 327 | case 5: { 328 | this._addB([CashDrawer.KICK_2]); 329 | } break; 330 | default: { 331 | this._addB([CashDrawer.KICK_2]); 332 | } break; 333 | } 334 | return this; 335 | } 336 | 337 | public beep(times: number, length: number): Document { 338 | this._addB([Constants.BEEP, [times], [length]]); 339 | return this; 340 | } 341 | 342 | public cut(feed: number = 3, partial_cut: boolean = false): Document { 343 | let buf: number[][] = []; 344 | this.feed(feed); 345 | if (partial_cut) 346 | buf.push(Paper.PART_CUT); 347 | else 348 | buf.push(Paper.FULL_CUT); 349 | this._addB(buf); 350 | return this; 351 | } 352 | 353 | public setColorMode(color: boolean): Document { 354 | let buf: number[][] = []; 355 | if (color) 356 | buf = [Color.RED]; 357 | else 358 | buf = [Color.BLACK]; 359 | this._addB(buf); 360 | return this; 361 | } 362 | 363 | public reverseColors(reverse: boolean): Document { 364 | let buf: number[] = []; 365 | if (reverse) 366 | buf = Color.REVERSE; 367 | else 368 | buf = Color.UNREVERSE; 369 | this._addB([buf]); 370 | return this; 371 | } 372 | 373 | public raw(data: number[]): Document { 374 | this._addB([data]); 375 | return this; 376 | } 377 | 378 | public text(content: string, override_encoding?: number) : Document { 379 | if(!override_encoding) 380 | override_encoding = this.encoding 381 | this._addB([cptable.utils.encode(override_encoding, content), [Constants.EOL]]); 382 | return this; 383 | } 384 | 385 | public image(image: ESCPOSImage, density: BitmapDensity = BitmapDensity.D24): Document { 386 | let n = 3; 387 | if ([BitmapDensity.D8, BitmapDensity.S8].indexOf(density) > -1) 388 | n = 1; 389 | let bitmap = image.toBitmap(n * 8); 390 | let header = []; 391 | switch(density) { 392 | case BitmapDensity.S8: { 393 | header = BitmapFormat.S8; 394 | } break; 395 | case BitmapDensity.D8: { 396 | header = BitmapFormat.D8; 397 | } break; 398 | case BitmapDensity.S24: { 399 | header = BitmapFormat.S24; 400 | } break; 401 | case BitmapDensity.D24: { 402 | header = BitmapFormat.D24; 403 | } break; 404 | } 405 | this.lineSpacing(0); 406 | let buf: number[][] = []; 407 | for(var i = 0; i < bitmap.data.length; i++) { 408 | let line = bitmap.data[i]; 409 | buf.push(header); 410 | buf.push(Utils.int16ToArray(line.length / n)); 411 | buf.push(line); 412 | buf.push(Constants.EOL); 413 | } 414 | this._addB(buf); 415 | return this.lineSpacing(); 416 | } 417 | 418 | public generateUInt8Array(): Uint8Array { 419 | return new Uint8Array(this._buffer); 420 | } 421 | 422 | public generateArray(): number[] { 423 | return this._buffer; 424 | } 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /dist/JSESCPOSBuilder.js: -------------------------------------------------------------------------------- 1 | var Neodynamic; 2 | (function (Neodynamic) { 3 | var JSESCPOSBuilder; 4 | (function (JSESCPOSBuilder) { 5 | class Constants { 6 | } 7 | Constants.LF = [10]; 8 | Constants.FS = [28]; 9 | Constants.FF = [12]; 10 | Constants.GS = [29]; 11 | Constants.DLE = [16]; 12 | Constants.EOT = [4]; 13 | Constants.NUL = [0]; 14 | Constants.ESC = [27]; 15 | Constants.TAB = [116]; 16 | Constants.EOL = [10]; 17 | Constants.BEEP = [27, 66]; 18 | Constants.TXT_ALIGNMENT = [27, 97]; 19 | Constants.TXT_FONT_FAMILY = [27, 77]; 20 | JSESCPOSBuilder.Constants = Constants; 21 | class FeedControlSequences { 22 | } 23 | FeedControlSequences.LF = [10]; 24 | FeedControlSequences.GLF = [74, 0]; 25 | FeedControlSequences.FF = [12]; 26 | FeedControlSequences.CR = [13]; 27 | FeedControlSequences.HT = [9]; 28 | FeedControlSequences.VT = [11]; 29 | JSESCPOSBuilder.FeedControlSequences = FeedControlSequences; 30 | class CharacterSpacing { 31 | } 32 | CharacterSpacing.DEFAULT = [27, 32, 0]; 33 | CharacterSpacing.SET = [27, 32]; 34 | JSESCPOSBuilder.CharacterSpacing = CharacterSpacing; 35 | class LineSpacing { 36 | } 37 | LineSpacing.DEFAULT = [27, 50]; 38 | LineSpacing.SET = [27, 51]; 39 | JSESCPOSBuilder.LineSpacing = LineSpacing; 40 | class HardwareOpt { 41 | } 42 | HardwareOpt.INIT = [27, 64]; 43 | HardwareOpt.SELECT = [27, 61, 1]; 44 | HardwareOpt.RESET = [27, 63, 10, 0]; 45 | JSESCPOSBuilder.HardwareOpt = HardwareOpt; 46 | class CashDrawer { 47 | } 48 | CashDrawer.KICK_2 = [27, 112, 0, 25, 250]; 49 | CashDrawer.KICK_5 = [27, 112, 1, 25, 250]; 50 | JSESCPOSBuilder.CashDrawer = CashDrawer; 51 | class Margins { 52 | } 53 | Margins.BOTTOM = [27, 79]; 54 | Margins.LEFT = [27, 108]; 55 | Margins.RIGHT = [27, 81]; 56 | JSESCPOSBuilder.Margins = Margins; 57 | class Paper { 58 | } 59 | Paper.FULL_CUT = [29, 86, 0]; 60 | Paper.PART_CUT = [29, 86, 1]; 61 | Paper.CUT_A = [29, 86, 65]; 62 | Paper.CUT_B = [29, 86, 66]; 63 | JSESCPOSBuilder.Paper = Paper; 64 | class TextFormat { 65 | static CUSTOM_SIZE(width, height) { 66 | if (width < 0) 67 | throw "Min size 0"; 68 | if (width > 8) 69 | throw "Max size 7"; 70 | if (height < 0) 71 | throw "Min size 0"; 72 | if (height > 8) 73 | throw "Max size 7"; 74 | return [29, 33, (width * 16) + height]; 75 | } 76 | static HEIGHT(size) { 77 | if (size < 1) 78 | throw "Min size 1"; 79 | if (size > 7) 80 | throw "Max size 7"; 81 | return [size - 1]; 82 | } 83 | static WIDTH(size) { 84 | if (size < 1) 85 | throw "Min size 1"; 86 | if (size > 7) 87 | throw "Max size 7"; 88 | return [(size - 1) * 16]; 89 | } 90 | } 91 | TextFormat.NORMAL = [27, 33, 0]; 92 | TextFormat.TWO_HEIGHT = [27, 33, 16]; 93 | TextFormat.TWO_WIDTH = [27, 33, 32]; 94 | TextFormat.FOUR_SQUARE = [27, 33, 48]; 95 | TextFormat.UNDERL_OFF = [27, 45, 0]; 96 | TextFormat.UNDERL_ON = [27, 45, 1]; 97 | TextFormat.UNDERL2_ON = [27, 45, 2]; 98 | TextFormat.BOLD_OFF = [27, 69, 0]; 99 | TextFormat.BOLD_ON = [27, 69, 1]; 100 | TextFormat.ITALIC_OFF = [27, 53]; 101 | TextFormat.ITALIC_ON = [27, 52]; 102 | JSESCPOSBuilder.TextFormat = TextFormat; 103 | class BarcodeFormat { 104 | static HEIGHT(height) { 105 | return [29, 104, height]; 106 | } 107 | static WIDTH(size) { 108 | if (size < 1) 109 | throw "Min size 1"; 110 | if (size > 5) 111 | throw "Max size 5"; 112 | return [29, 119, size + 1]; 113 | } 114 | } 115 | BarcodeFormat.TXT_OFF = [29, 72, 0]; 116 | BarcodeFormat.TXT_ABV = [29, 72, 1]; 117 | BarcodeFormat.TXT_BLW = [29, 72, 2]; 118 | BarcodeFormat.TXT_BTH = [29, 72, 3]; 119 | BarcodeFormat.FONT_A = [29, 102, 0]; 120 | BarcodeFormat.FONT_B = [29, 102, 1]; 121 | BarcodeFormat.HEIGHT_DEFAULT = [29, 104, 100]; 122 | BarcodeFormat.WIDTH_DEFAULT = [29, 119, 1]; 123 | BarcodeFormat.UPC_A = [29, 107, 0]; 124 | BarcodeFormat.UPC_E = [29, 107, 1]; 125 | BarcodeFormat.EAN13 = [29, 107, 2]; 126 | BarcodeFormat.EAN8 = [29, 107, 3]; 127 | BarcodeFormat.CODE39 = [29, 107, 4]; 128 | BarcodeFormat.ITF = [29, 107, 5]; 129 | BarcodeFormat.CODABAR = [29, 107, 6]; 130 | BarcodeFormat.CODE93 = [29, 107, 72]; 131 | BarcodeFormat.CODE128 = [29, 107, 73]; 132 | JSESCPOSBuilder.BarcodeFormat = BarcodeFormat; 133 | class Code2DFormat { 134 | } 135 | Code2DFormat.TYPE_PDF417 = [29, 90, 0]; 136 | Code2DFormat.TYPE_DATAMATRIX = [29, 90, 1]; 137 | Code2DFormat.TYPE_QR = [29, 90, 2]; 138 | Code2DFormat.CODE2D = [27, 90]; 139 | Code2DFormat.QR_LEVEL_L = [76]; 140 | Code2DFormat.QR_LEVEL_M = [77]; 141 | Code2DFormat.QR_LEVEL_Q = [81]; 142 | Code2DFormat.QR_LEVEL_H = [72]; 143 | JSESCPOSBuilder.Code2DFormat = Code2DFormat; 144 | class ImageFormat { 145 | } 146 | ImageFormat.NORMAL = [29, 118, 48, 0]; 147 | ImageFormat.DOUBLE_WIDTH = [29, 118, 48, 1]; 148 | ImageFormat.DOUBLE_HEIGHT = [29, 118, 48, 2]; 149 | ImageFormat.QUAD = [29, 118, 48, 3]; 150 | JSESCPOSBuilder.ImageFormat = ImageFormat; 151 | class BitmapFormat { 152 | } 153 | BitmapFormat.S8 = [27, 42, 0]; 154 | BitmapFormat.D8 = [27, 42, 1]; 155 | BitmapFormat.S24 = [27, 42, 32]; 156 | BitmapFormat.D24 = [27, 42, 33]; 157 | JSESCPOSBuilder.BitmapFormat = BitmapFormat; 158 | class GSV0Format { 159 | } 160 | GSV0Format.NORMAL = [29, 118, 48, 0]; 161 | GSV0Format.DW = [29, 118, 48, 1]; 162 | GSV0Format.DH = [29, 118, 48, 2]; 163 | GSV0Format.DWDH = [29, 118, 48, 3]; 164 | JSESCPOSBuilder.GSV0Format = GSV0Format; 165 | class Color { 166 | } 167 | Color.BLACK = [27, 114, 0]; 168 | Color.RED = [27, 114, 1]; 169 | Color.REVERSE = [29, 66, 49]; 170 | Color.UNREVERSE = [29, 66, 48]; 171 | JSESCPOSBuilder.Color = Color; 172 | class Screen { 173 | } 174 | Screen.BS = [8]; 175 | Screen.HT = [9]; 176 | Screen.LF = [10]; 177 | Screen.US_LF = [31, 10]; 178 | Screen.HOM = [11]; 179 | Screen.CR = [13]; 180 | Screen.US_CR = [31, 13]; 181 | Screen.US_B = [31, 66]; 182 | Screen.US_$ = [31, 36]; 183 | Screen.CLR = [12]; 184 | Screen.CAN = [24]; 185 | Screen.US_MD1 = [31, 1]; 186 | Screen.US_MD2 = [31, 2]; 187 | Screen.US_MD3 = [31, 3]; 188 | Screen.US_C = [31, 67]; 189 | Screen.US_E = [31, 69]; 190 | Screen.US_T = [31, 84]; 191 | Screen.US_U = [31, 85]; 192 | Screen.US_X = [31, 88]; 193 | Screen.US_r = [31, 114]; 194 | Screen.US_v = [31, 118]; 195 | JSESCPOSBuilder.Screen = Screen; 196 | class Barcode1DOptions { 197 | constructor(width, height, include_parity = true, position = JSESCPOSBuilder.BarcodeTextPosition.Below, font = JSESCPOSBuilder.BarcodeFont.A) { 198 | this.position = JSESCPOSBuilder.BarcodeTextPosition.Below; 199 | this.include_parity = true; 200 | this.font = JSESCPOSBuilder.BarcodeFont.A; 201 | this.width = width; 202 | this.height = height; 203 | this.position = position; 204 | this.include_parity = include_parity; 205 | this.font = font; 206 | } 207 | } 208 | JSESCPOSBuilder.Barcode1DOptions = Barcode1DOptions; 209 | class BarcodePDF417Options { 210 | constructor(width = 3, height_multiplier = 3, data_column_count = 0, error_ratio = 0.1, truncated = false) { 211 | this.width = 3; 212 | this.height_multiplier = 3; 213 | this.data_column_count = 0; 214 | this.error_ratio = 0.1; 215 | this.truncated = false; 216 | this.width = width; 217 | this.height_multiplier = height_multiplier; 218 | this.data_column_count = data_column_count; 219 | this.error_ratio = error_ratio; 220 | this.truncated = truncated; 221 | } 222 | } 223 | JSESCPOSBuilder.BarcodePDF417Options = BarcodePDF417Options; 224 | class BarcodeQROptions { 225 | constructor(level = JSESCPOSBuilder.QRLevel.L, size = 6) { 226 | this.level = JSESCPOSBuilder.QRLevel.L; 227 | this.size = 6; 228 | this.level = level; 229 | this.size = size; 230 | } 231 | } 232 | JSESCPOSBuilder.BarcodeQROptions = BarcodeQROptions; 233 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 234 | })(Neodynamic || (Neodynamic = {})); 235 | var Neodynamic; 236 | (function (Neodynamic) { 237 | var JSESCPOSBuilder; 238 | (function (JSESCPOSBuilder) { 239 | class Document { 240 | constructor() { 241 | this._buffer = []; 242 | this.model = JSESCPOSBuilder.PrinterModel.Generic; 243 | this.encoding = 858; 244 | this.width = 48; 245 | JSESCPOSBuilder.Utils.check4CPTable(); 246 | } 247 | _addB(value) { 248 | for (var i = 0; i < value.length; i++) 249 | this._buffer = this._buffer.concat(value[i]); 250 | } 251 | setCharacterCodeTable(code_table) { 252 | if (!JSESCPOSBuilder.Utils.isValidUInt8(code_table)) 253 | throw "Invalid code table"; 254 | this._addB([ 255 | JSESCPOSBuilder.Constants.ESC, 256 | JSESCPOSBuilder.Constants.TAB, 257 | [code_table], 258 | ]); 259 | return this; 260 | } 261 | setPrintWidth(newWidth) { 262 | this.width = newWidth; 263 | this._addB([ 264 | JSESCPOSBuilder.Constants.GS, 265 | [87], 266 | JSESCPOSBuilder.Utils.int16ToArray(newWidth), 267 | ]); 268 | return this; 269 | } 270 | marginBottom(size) { 271 | if (!JSESCPOSBuilder.Utils.isValidUInt8(size)) 272 | throw "Invalid size"; 273 | this._addB([JSESCPOSBuilder.Margins.BOTTOM, [size]]); 274 | return this; 275 | } 276 | marginLeft(size) { 277 | if (!JSESCPOSBuilder.Utils.isValidUInt8(size)) 278 | throw "Invalid size"; 279 | this._addB([JSESCPOSBuilder.Margins.LEFT, [size]]); 280 | return this; 281 | } 282 | marginRight(size) { 283 | if (!JSESCPOSBuilder.Utils.isValidUInt8(size)) 284 | throw "Invalid size"; 285 | this._addB([JSESCPOSBuilder.Margins.RIGHT, [size]]); 286 | return this; 287 | } 288 | newLine() { 289 | this._addB([JSESCPOSBuilder.Constants.EOL]); 290 | return this; 291 | } 292 | drawLine(new_line = false) { 293 | if (new_line) 294 | this.newLine(); 295 | this._addB([JSESCPOSBuilder.Utils.repeat("-".charCodeAt(0), this.width)]); 296 | return this; 297 | } 298 | drawTable(data) { 299 | let cell_width = this.width / data.length; 300 | let text = ""; 301 | for (var i = 0; i < data.length; i++) { 302 | text += data[i].toString(); 303 | let spaces = cell_width - data[i].toString().length; 304 | text += new Array(spaces + 1).join(' '); 305 | } 306 | this._addB([cptable.utils.encode(this.encoding, text)]); 307 | return this; 308 | } 309 | feed(lines = 1) { 310 | this._addB(JSESCPOSBuilder.Utils.repeat(JSESCPOSBuilder.Constants.EOL, lines)); 311 | return this; 312 | } 313 | control(sequence) { 314 | let buf = []; 315 | switch (sequence) { 316 | case JSESCPOSBuilder.FeedControlSequence.CarriageReturn: 317 | buf = [JSESCPOSBuilder.FeedControlSequences.CR]; 318 | break; 319 | case JSESCPOSBuilder.FeedControlSequence.FormFeed: 320 | buf = [JSESCPOSBuilder.FeedControlSequences.FF]; 321 | break; 322 | case JSESCPOSBuilder.FeedControlSequence.HorizontalTab: 323 | buf = [JSESCPOSBuilder.FeedControlSequences.HT]; 324 | break; 325 | case JSESCPOSBuilder.FeedControlSequence.PrintFeedPaper: 326 | buf = [JSESCPOSBuilder.FeedControlSequences.GLF]; 327 | break; 328 | case JSESCPOSBuilder.FeedControlSequence.PrintLineFeed: 329 | buf = [JSESCPOSBuilder.FeedControlSequences.LF]; 330 | break; 331 | case JSESCPOSBuilder.FeedControlSequence.VerticalTab: 332 | buf = [JSESCPOSBuilder.FeedControlSequences.VT]; 333 | break; 334 | } 335 | this._addB(buf); 336 | return this; 337 | } 338 | align(alignment) { 339 | let buf = []; 340 | buf = buf.concat(JSESCPOSBuilder.Constants.TXT_ALIGNMENT); 341 | switch (alignment) { 342 | case JSESCPOSBuilder.TextAlignment.Center: 343 | buf.push(1); 344 | break; 345 | case JSESCPOSBuilder.TextAlignment.LeftJustification: 346 | buf.push(0); 347 | break; 348 | case JSESCPOSBuilder.TextAlignment.RightJustification: 349 | buf.push(2); 350 | break; 351 | } 352 | this._addB([buf]); 353 | return this; 354 | } 355 | font(family) { 356 | let buf = []; 357 | buf = buf.concat(JSESCPOSBuilder.Constants.TXT_FONT_FAMILY); 358 | switch (family) { 359 | case JSESCPOSBuilder.FontFamily.A: 360 | buf.push(0); 361 | break; 362 | case JSESCPOSBuilder.FontFamily.B: 363 | buf.push(1); 364 | break; 365 | case JSESCPOSBuilder.FontFamily.C: 366 | buf.push(2); 367 | break; 368 | } 369 | this._addB([buf]); 370 | return this; 371 | } 372 | style(styles) { 373 | let buf = []; 374 | if (styles.indexOf(JSESCPOSBuilder.FontStyle.Bold) > -1) 375 | buf.push(JSESCPOSBuilder.TextFormat.BOLD_ON); 376 | else 377 | buf.push(JSESCPOSBuilder.TextFormat.BOLD_OFF); 378 | if (styles.indexOf(JSESCPOSBuilder.FontStyle.Italic) > -1) 379 | buf.push(JSESCPOSBuilder.TextFormat.ITALIC_ON); 380 | else 381 | buf.push(JSESCPOSBuilder.TextFormat.ITALIC_OFF); 382 | if (styles.indexOf(JSESCPOSBuilder.FontStyle.Underline) > -1) 383 | buf.push(JSESCPOSBuilder.TextFormat.UNDERL_ON); 384 | else if (styles.indexOf(JSESCPOSBuilder.FontStyle.Underline2) > -1) 385 | buf.push(JSESCPOSBuilder.TextFormat.UNDERL2_ON); 386 | else 387 | buf.push(JSESCPOSBuilder.TextFormat.UNDERL_OFF); 388 | this._addB(buf); 389 | return this; 390 | } 391 | size(width, height) { 392 | let buf = []; 393 | buf = JSESCPOSBuilder.TextFormat.CUSTOM_SIZE(width, height); 394 | this._addB([buf]); 395 | return this; 396 | } 397 | charSpacing(value) { 398 | let buf = []; 399 | if (value || value === 0) { 400 | if (!JSESCPOSBuilder.Utils.isValidUInt8(value)) 401 | throw "Invalid value"; 402 | buf.push(JSESCPOSBuilder.CharacterSpacing.SET); 403 | buf.push([value]); 404 | } 405 | else { 406 | buf.push(JSESCPOSBuilder.CharacterSpacing.DEFAULT); 407 | } 408 | this._addB(buf); 409 | return this; 410 | } 411 | lineSpacing(value) { 412 | let buf = []; 413 | if (value || value === 0) { 414 | if (!JSESCPOSBuilder.Utils.isValidUInt8(value)) 415 | throw "Invalid value"; 416 | buf.push(JSESCPOSBuilder.LineSpacing.SET); 417 | buf.push([value]); 418 | } 419 | else { 420 | buf.push(JSESCPOSBuilder.LineSpacing.DEFAULT); 421 | } 422 | this._addB(buf); 423 | return this; 424 | } 425 | hardware(hardware) { 426 | let buf = []; 427 | switch (hardware) { 428 | case JSESCPOSBuilder.Hardware.Init: 429 | buf = JSESCPOSBuilder.HardwareOpt.INIT; 430 | break; 431 | case JSESCPOSBuilder.Hardware.Reset: 432 | buf = JSESCPOSBuilder.HardwareOpt.RESET; 433 | break; 434 | case JSESCPOSBuilder.Hardware.Select: 435 | buf = JSESCPOSBuilder.HardwareOpt.SELECT; 436 | break; 437 | } 438 | this._addB([buf]); 439 | return this; 440 | } 441 | linearBarcode(code, type, options = new JSESCPOSBuilder.Barcode1DOptions()) { 442 | let buf = []; 443 | if (options.width) 444 | buf.push(JSESCPOSBuilder.BarcodeFormat.WIDTH(options.width)); 445 | else 446 | buf.push(JSESCPOSBuilder.BarcodeFormat.WIDTH_DEFAULT); 447 | if (options.height) 448 | buf.push(JSESCPOSBuilder.BarcodeFormat.HEIGHT(options.height)); 449 | else 450 | buf.push(JSESCPOSBuilder.BarcodeFormat.HEIGHT_DEFAULT); 451 | switch (options.font) { 452 | case JSESCPOSBuilder.BarcodeFont.A: 453 | { 454 | buf.push(JSESCPOSBuilder.BarcodeFormat.FONT_A); 455 | } 456 | break; 457 | case JSESCPOSBuilder.BarcodeFont.B: 458 | { 459 | buf.push(JSESCPOSBuilder.BarcodeFormat.FONT_B); 460 | } 461 | break; 462 | } 463 | switch (options.position) { 464 | case JSESCPOSBuilder.BarcodeTextPosition.Above: 465 | { 466 | buf.push(JSESCPOSBuilder.BarcodeFormat.TXT_ABV); 467 | } 468 | break; 469 | case JSESCPOSBuilder.BarcodeTextPosition.AboveAndBelow: 470 | { 471 | buf.push(JSESCPOSBuilder.BarcodeFormat.TXT_BTH); 472 | } 473 | break; 474 | case JSESCPOSBuilder.BarcodeTextPosition.Below: 475 | { 476 | buf.push(JSESCPOSBuilder.BarcodeFormat.TXT_BLW); 477 | } 478 | break; 479 | case JSESCPOSBuilder.BarcodeTextPosition.Off: 480 | { 481 | buf.push(JSESCPOSBuilder.BarcodeFormat.TXT_OFF); 482 | } 483 | break; 484 | } 485 | switch (type) { 486 | case JSESCPOSBuilder.Barcode1DType.CODE39: 487 | { 488 | buf.push(JSESCPOSBuilder.BarcodeFormat.CODE39); 489 | } 490 | break; 491 | case JSESCPOSBuilder.Barcode1DType.ITF: 492 | { 493 | buf.push(JSESCPOSBuilder.BarcodeFormat.ITF); 494 | } 495 | break; 496 | case JSESCPOSBuilder.Barcode1DType.UPC_A: 497 | { 498 | buf.push(JSESCPOSBuilder.BarcodeFormat.UPC_A); 499 | } 500 | break; 501 | case JSESCPOSBuilder.Barcode1DType.UPC_E: 502 | { 503 | buf.push(JSESCPOSBuilder.BarcodeFormat.UPC_E); 504 | } 505 | break; 506 | case JSESCPOSBuilder.Barcode1DType.CODABAR: 507 | { 508 | buf.push(JSESCPOSBuilder.BarcodeFormat.CODABAR); 509 | } 510 | break; 511 | case JSESCPOSBuilder.Barcode1DType.CODE128: 512 | { 513 | buf.push(JSESCPOSBuilder.BarcodeFormat.CODE128); 514 | buf.push(JSESCPOSBuilder.Utils.codeLengthUInt16(code)); 515 | } 516 | break; 517 | case JSESCPOSBuilder.Barcode1DType.CODE93: 518 | { 519 | buf.push(JSESCPOSBuilder.BarcodeFormat.CODE93); 520 | buf.push(JSESCPOSBuilder.Utils.codeLengthUInt16(code)); 521 | } 522 | break; 523 | case JSESCPOSBuilder.Barcode1DType.EAN13: 524 | { 525 | buf.push(JSESCPOSBuilder.BarcodeFormat.EAN13); 526 | } 527 | break; 528 | case JSESCPOSBuilder.Barcode1DType.EAN8: 529 | { 530 | buf.push(JSESCPOSBuilder.BarcodeFormat.EAN8); 531 | } 532 | break; 533 | } 534 | buf.push(cptable.utils.encode(this.encoding, code)); 535 | if (options.include_parity && type in [JSESCPOSBuilder.Barcode1DType.EAN13, JSESCPOSBuilder.Barcode1DType.EAN8]) 536 | buf.push([JSESCPOSBuilder.Utils.getParityBit(code)]); 537 | buf.push([0]); 538 | this._addB(buf); 539 | return this; 540 | } 541 | _wrapperSend2DCodeData(func, code_type, data, modifier) { 542 | let buf = []; 543 | let header = JSESCPOSBuilder.Utils.int16ToArray((data != undefined ? data.length : 0) + (modifier != undefined ? 1 : 0) + 2); 544 | buf = [JSESCPOSBuilder.Constants.GS, [40, 107], header, [code_type, func]]; 545 | if (modifier != undefined) 546 | buf.push([modifier]); 547 | if (typeof (data) == 'string') 548 | buf.push(cptable.utils.encode(this.encoding, data)); 549 | else 550 | buf.push(data); 551 | this._addB(buf); 552 | } 553 | qrCode(code, options = new JSESCPOSBuilder.BarcodeQROptions()) { 554 | let ct = 49; 555 | this._wrapperSend2DCodeData(65, ct, [50, 0]); 556 | this._wrapperSend2DCodeData(67, ct, [options.size]); 557 | this._wrapperSend2DCodeData(69, ct, [48 + options.level]); 558 | this._wrapperSend2DCodeData(80, ct, code, 48); 559 | this._wrapperSend2DCodeData(81, ct, '', 48); 560 | return this; 561 | } 562 | pdf417(code, options = new JSESCPOSBuilder.BarcodePDF417Options()) { 563 | let ct = 48; 564 | this._wrapperSend2DCodeData(70, ct, [options.truncated ? 1 : 0]); 565 | this._wrapperSend2DCodeData(65, ct, [options.data_column_count]); 566 | this._wrapperSend2DCodeData(67, ct, [options.width]); 567 | this._wrapperSend2DCodeData(68, ct, [options.height_multiplier]); 568 | let error = Math.ceil(options.error_ratio * 10); 569 | this._wrapperSend2DCodeData(69, ct, [error], 49); 570 | this._wrapperSend2DCodeData(80, ct, code, 48); 571 | this._wrapperSend2DCodeData(81, ct, '', 48); 572 | return this; 573 | } 574 | cashDraw(pin = 2) { 575 | switch (pin) { 576 | case 2: 577 | { 578 | this._addB([JSESCPOSBuilder.CashDrawer.KICK_2]); 579 | } 580 | break; 581 | case 5: 582 | { 583 | this._addB([JSESCPOSBuilder.CashDrawer.KICK_2]); 584 | } 585 | break; 586 | default: 587 | { 588 | this._addB([JSESCPOSBuilder.CashDrawer.KICK_2]); 589 | } 590 | break; 591 | } 592 | return this; 593 | } 594 | beep(times, length) { 595 | this._addB([JSESCPOSBuilder.Constants.BEEP, [times], [length]]); 596 | return this; 597 | } 598 | cut(feed = 3, partial_cut = false) { 599 | let buf = []; 600 | this.feed(feed); 601 | if (partial_cut) 602 | buf.push(JSESCPOSBuilder.Paper.PART_CUT); 603 | else 604 | buf.push(JSESCPOSBuilder.Paper.FULL_CUT); 605 | this._addB(buf); 606 | return this; 607 | } 608 | setColorMode(color) { 609 | let buf = []; 610 | if (color) 611 | buf = [JSESCPOSBuilder.Color.RED]; 612 | else 613 | buf = [JSESCPOSBuilder.Color.BLACK]; 614 | this._addB(buf); 615 | return this; 616 | } 617 | reverseColors(reverse) { 618 | let buf = []; 619 | if (reverse) 620 | buf = JSESCPOSBuilder.Color.REVERSE; 621 | else 622 | buf = JSESCPOSBuilder.Color.UNREVERSE; 623 | this._addB([buf]); 624 | return this; 625 | } 626 | raw(data) { 627 | this._addB([data]); 628 | return this; 629 | } 630 | text(content, override_encoding) { 631 | if (!override_encoding) 632 | override_encoding = this.encoding; 633 | this._addB([cptable.utils.encode(override_encoding, content), [JSESCPOSBuilder.Constants.EOL]]); 634 | return this; 635 | } 636 | image(image, density = JSESCPOSBuilder.BitmapDensity.D24) { 637 | let n = 3; 638 | if ([JSESCPOSBuilder.BitmapDensity.D8, JSESCPOSBuilder.BitmapDensity.S8].indexOf(density) > -1) 639 | n = 1; 640 | let bitmap = image.toBitmap(n * 8); 641 | let header = []; 642 | switch (density) { 643 | case JSESCPOSBuilder.BitmapDensity.S8: 644 | { 645 | header = JSESCPOSBuilder.BitmapFormat.S8; 646 | } 647 | break; 648 | case JSESCPOSBuilder.BitmapDensity.D8: 649 | { 650 | header = JSESCPOSBuilder.BitmapFormat.D8; 651 | } 652 | break; 653 | case JSESCPOSBuilder.BitmapDensity.S24: 654 | { 655 | header = JSESCPOSBuilder.BitmapFormat.S24; 656 | } 657 | break; 658 | case JSESCPOSBuilder.BitmapDensity.D24: 659 | { 660 | header = JSESCPOSBuilder.BitmapFormat.D24; 661 | } 662 | break; 663 | } 664 | this.lineSpacing(0); 665 | let buf = []; 666 | for (var i = 0; i < bitmap.data.length; i++) { 667 | let line = bitmap.data[i]; 668 | buf.push(header); 669 | buf.push(JSESCPOSBuilder.Utils.int16ToArray(line.length / n)); 670 | buf.push(line); 671 | buf.push(JSESCPOSBuilder.Constants.EOL); 672 | } 673 | this._addB(buf); 674 | return this.lineSpacing(); 675 | } 676 | generateUInt8Array() { 677 | return new Uint8Array(this._buffer); 678 | } 679 | generateArray() { 680 | return this._buffer; 681 | } 682 | } 683 | JSESCPOSBuilder.Document = Document; 684 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 685 | })(Neodynamic || (Neodynamic = {})); 686 | var Neodynamic; 687 | (function (Neodynamic) { 688 | var JSESCPOSBuilder; 689 | (function (JSESCPOSBuilder) { 690 | let PrinterModel; 691 | (function (PrinterModel) { 692 | PrinterModel[PrinterModel["Generic"] = 0] = "Generic"; 693 | })(PrinterModel = JSESCPOSBuilder.PrinterModel || (JSESCPOSBuilder.PrinterModel = {})); 694 | let FeedControlSequence; 695 | (function (FeedControlSequence) { 696 | FeedControlSequence[FeedControlSequence["PrintLineFeed"] = 0] = "PrintLineFeed"; 697 | FeedControlSequence[FeedControlSequence["PrintFeedPaper"] = 1] = "PrintFeedPaper"; 698 | FeedControlSequence[FeedControlSequence["FormFeed"] = 2] = "FormFeed"; 699 | FeedControlSequence[FeedControlSequence["CarriageReturn"] = 3] = "CarriageReturn"; 700 | FeedControlSequence[FeedControlSequence["HorizontalTab"] = 4] = "HorizontalTab"; 701 | FeedControlSequence[FeedControlSequence["VerticalTab"] = 5] = "VerticalTab"; 702 | })(FeedControlSequence = JSESCPOSBuilder.FeedControlSequence || (JSESCPOSBuilder.FeedControlSequence = {})); 703 | let TextAlignment; 704 | (function (TextAlignment) { 705 | TextAlignment[TextAlignment["LeftJustification"] = 0] = "LeftJustification"; 706 | TextAlignment[TextAlignment["Center"] = 1] = "Center"; 707 | TextAlignment[TextAlignment["RightJustification"] = 2] = "RightJustification"; 708 | })(TextAlignment = JSESCPOSBuilder.TextAlignment || (JSESCPOSBuilder.TextAlignment = {})); 709 | let FontFamily; 710 | (function (FontFamily) { 711 | FontFamily[FontFamily["A"] = 0] = "A"; 712 | FontFamily[FontFamily["B"] = 1] = "B"; 713 | FontFamily[FontFamily["C"] = 2] = "C"; 714 | })(FontFamily = JSESCPOSBuilder.FontFamily || (JSESCPOSBuilder.FontFamily = {})); 715 | let FontStyle; 716 | (function (FontStyle) { 717 | FontStyle[FontStyle["Bold"] = 0] = "Bold"; 718 | FontStyle[FontStyle["Italic"] = 1] = "Italic"; 719 | FontStyle[FontStyle["Underline"] = 2] = "Underline"; 720 | FontStyle[FontStyle["Underline2"] = 3] = "Underline2"; 721 | })(FontStyle = JSESCPOSBuilder.FontStyle || (JSESCPOSBuilder.FontStyle = {})); 722 | let Hardware; 723 | (function (Hardware) { 724 | Hardware[Hardware["Init"] = 0] = "Init"; 725 | Hardware[Hardware["Select"] = 1] = "Select"; 726 | Hardware[Hardware["Reset"] = 2] = "Reset"; 727 | })(Hardware = JSESCPOSBuilder.Hardware || (JSESCPOSBuilder.Hardware = {})); 728 | let Barcode1DType; 729 | (function (Barcode1DType) { 730 | Barcode1DType[Barcode1DType["UPC_A"] = 0] = "UPC_A"; 731 | Barcode1DType[Barcode1DType["UPC_E"] = 1] = "UPC_E"; 732 | Barcode1DType[Barcode1DType["EAN13"] = 2] = "EAN13"; 733 | Barcode1DType[Barcode1DType["EAN8"] = 3] = "EAN8"; 734 | Barcode1DType[Barcode1DType["CODE39"] = 4] = "CODE39"; 735 | Barcode1DType[Barcode1DType["ITF"] = 5] = "ITF"; 736 | Barcode1DType[Barcode1DType["CODE93"] = 6] = "CODE93"; 737 | Barcode1DType[Barcode1DType["CODE128"] = 7] = "CODE128"; 738 | Barcode1DType[Barcode1DType["CODABAR"] = 8] = "CODABAR"; 739 | })(Barcode1DType = JSESCPOSBuilder.Barcode1DType || (JSESCPOSBuilder.Barcode1DType = {})); 740 | let BarcodeTextPosition; 741 | (function (BarcodeTextPosition) { 742 | BarcodeTextPosition[BarcodeTextPosition["Off"] = 0] = "Off"; 743 | BarcodeTextPosition[BarcodeTextPosition["Above"] = 1] = "Above"; 744 | BarcodeTextPosition[BarcodeTextPosition["Below"] = 2] = "Below"; 745 | BarcodeTextPosition[BarcodeTextPosition["AboveAndBelow"] = 3] = "AboveAndBelow"; 746 | })(BarcodeTextPosition = JSESCPOSBuilder.BarcodeTextPosition || (JSESCPOSBuilder.BarcodeTextPosition = {})); 747 | let BarcodeFont; 748 | (function (BarcodeFont) { 749 | BarcodeFont[BarcodeFont["A"] = 0] = "A"; 750 | BarcodeFont[BarcodeFont["B"] = 1] = "B"; 751 | })(BarcodeFont = JSESCPOSBuilder.BarcodeFont || (JSESCPOSBuilder.BarcodeFont = {})); 752 | let QRLevel; 753 | (function (QRLevel) { 754 | QRLevel[QRLevel["L"] = 0] = "L"; 755 | QRLevel[QRLevel["M"] = 1] = "M"; 756 | QRLevel[QRLevel["Q"] = 2] = "Q"; 757 | QRLevel[QRLevel["H"] = 3] = "H"; 758 | })(QRLevel = JSESCPOSBuilder.QRLevel || (JSESCPOSBuilder.QRLevel = {})); 759 | let BitmapDensity; 760 | (function (BitmapDensity) { 761 | BitmapDensity[BitmapDensity["S8"] = 0] = "S8"; 762 | BitmapDensity[BitmapDensity["D8"] = 1] = "D8"; 763 | BitmapDensity[BitmapDensity["S24"] = 2] = "S24"; 764 | BitmapDensity[BitmapDensity["D24"] = 3] = "D24"; 765 | })(BitmapDensity = JSESCPOSBuilder.BitmapDensity || (JSESCPOSBuilder.BitmapDensity = {})); 766 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 767 | })(Neodynamic || (Neodynamic = {})); 768 | var Neodynamic; 769 | (function (Neodynamic) { 770 | var JSESCPOSBuilder; 771 | (function (JSESCPOSBuilder) { 772 | class GetPixels { 773 | static getPixels(b64_image) { 774 | return new Promise((ok, err) => { 775 | let img = new Image(); 776 | img.crossOrigin = "Anonymous"; 777 | img.onload = () => { 778 | let canvas = document.createElement('canvas'); 779 | canvas.width = img.width; 780 | canvas.height = img.height; 781 | let context = canvas.getContext('2d'); 782 | context.drawImage(img, 0, 0); 783 | let pixels = context.getImageData(0, 0, img.width, img.height); 784 | ok({ data: new Uint8Array(pixels.data), shape: [img.width, img.height, 4], stride: [4, 4 * img.width, 1] }); 785 | }; 786 | img.onerror = (e) => { err(e); }; 787 | img.src = b64_image; 788 | }); 789 | } 790 | } 791 | JSESCPOSBuilder.GetPixels = GetPixels; 792 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 793 | })(Neodynamic || (Neodynamic = {})); 794 | var Neodynamic; 795 | (function (Neodynamic) { 796 | var JSESCPOSBuilder; 797 | (function (JSESCPOSBuilder) { 798 | class ESCPOSImageSize { 799 | constructor(width, height, colors) { 800 | this.width = 0; 801 | this.height = 0; 802 | this.colors = 0; 803 | if (width) 804 | this.width = width; 805 | if (height) 806 | this.height = height; 807 | if (colors) 808 | this.colors = colors; 809 | } 810 | } 811 | JSESCPOSBuilder.ESCPOSImageSize = ESCPOSImageSize; 812 | class ESCPOSImage { 813 | constructor(pixels) { 814 | this.data = []; 815 | this.pixels = pixels; 816 | if (!this.size) 817 | throw "Invalid size"; 818 | let temp_arr = []; 819 | for (var i = 0; i < this.pixels.data.length; i += this.size.colors) { 820 | let color_arr = new Array(this.size.colors).fill(0); 821 | let d = this.rgb(color_arr.map((_, b) => this.pixels.data[i + b])); 822 | temp_arr.push(d); 823 | } 824 | ; 825 | this.data = temp_arr.map((pixel) => { 826 | if (pixel.a == 0) 827 | return 0; 828 | return pixel.r !== 0xFF || pixel.g !== 0xFF || pixel.b !== 0xFF ? 1 : 0; 829 | }); 830 | } 831 | rgb(pixel) { 832 | return { 833 | r: pixel[0], 834 | g: pixel[1], 835 | b: pixel[2], 836 | a: pixel[3] 837 | }; 838 | } 839 | static load(b64_image) { 840 | return new Promise((ok, err) => { 841 | JSESCPOSBuilder.GetPixels.getPixels(b64_image) 842 | .then((value) => { 843 | ok(new ESCPOSImage(value)); 844 | }) 845 | .catch((reason) => { 846 | err(reason); 847 | }); 848 | }); 849 | } 850 | get size() { 851 | if (!this.pixels) 852 | return undefined; 853 | return new ESCPOSImageSize(this.pixels.shape[0], this.pixels.shape[1], this.pixels.shape[2]); 854 | } 855 | toBitmap(density) { 856 | if (!this.size) 857 | return undefined; 858 | density = density || 24; 859 | var ld = []; 860 | var result = []; 861 | var x, y, b, l, i; 862 | var c = density / 8; 863 | var n = Math.ceil(this.size.height / density); 864 | for (y = 0; y < n; y++) { 865 | ld = []; 866 | result[y] = []; 867 | for (x = 0; x < this.size.width; x++) { 868 | for (b = 0; b < density; b++) { 869 | i = x * c + (b >> 3); 870 | if (ld[i] === undefined) { 871 | ld[i] = 0; 872 | } 873 | l = y * density + b; 874 | if (l < this.size.height) { 875 | if (this.data[l * this.size.width + x]) { 876 | ld[i] += (0x80 >> (b & 0x7)); 877 | } 878 | } 879 | } 880 | } 881 | result[y] = ld; 882 | } 883 | return { 884 | data: result, 885 | density: density 886 | }; 887 | } 888 | toRaster() { 889 | if (!this.size) 890 | return undefined; 891 | var result = []; 892 | var width = this.size.width; 893 | var height = this.size.height; 894 | var data = this.data; 895 | var n = Math.ceil(width / 8); 896 | var x, y, b, c, i; 897 | for (y = 0; y < height; y++) { 898 | for (x = 0; x < n; x++) { 899 | for (b = 0; b < 8; b++) { 900 | i = x * 8 + b; 901 | if (result[y * n + x] === undefined) { 902 | result[y * n + x] = 0; 903 | } 904 | c = x * 8 + b; 905 | if (c < width) { 906 | if (data[y * width + i]) { 907 | result[y * n + x] += (0x80 >> (b & 0x7)); 908 | } 909 | } 910 | } 911 | } 912 | } 913 | return { 914 | data: result, 915 | width: n, 916 | height: height 917 | }; 918 | } 919 | } 920 | JSESCPOSBuilder.ESCPOSImage = ESCPOSImage; 921 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 922 | })(Neodynamic || (Neodynamic = {})); 923 | var Neodynamic; 924 | (function (Neodynamic) { 925 | var JSESCPOSBuilder; 926 | (function (JSESCPOSBuilder) { 927 | class Utils { 928 | static isValidUInt8(value) { 929 | return value == new Uint8Array([value])[0]; 930 | } 931 | static repeat(value, count) { 932 | let buf = []; 933 | for (var i = 0; i < count; i++) 934 | buf.push(value); 935 | return buf; 936 | } 937 | static getParityBit(code) { 938 | let parity = 0; 939 | let code_r = code.split('').reverse().join(''); 940 | for (var i = 0; i < code_r.length; i++) { 941 | parity += parseInt(code_r.charAt(i), 10) * Math.pow(3, ((i + 1) % 2)); 942 | } 943 | return ((10 - (parity % 10)) % 10).toString().charCodeAt(0); 944 | } 945 | static check4CPTable() { 946 | if (!('cptable' in window)) { 947 | throw "cptable.js and cputils.js files from " + 948 | "https://github.com/SheetJS/js-codepage" + 949 | "project are missing"; 950 | } 951 | } 952 | static int32ToArray(number) { 953 | return [number & 0xFF, 954 | (number >> 8) & 0xFF, 955 | (number >> 16) & 0xFF, 956 | (number >> 24) & 0xFF]; 957 | } 958 | static int16ToArray(number) { 959 | return [number & 0xFF, 960 | (number >> 8) & 0xFF]; 961 | } 962 | static codeLengthUInt16(code) { 963 | return this.int16ToArray(code.length); 964 | } 965 | } 966 | JSESCPOSBuilder.Utils = Utils; 967 | })(JSESCPOSBuilder = Neodynamic.JSESCPOSBuilder || (Neodynamic.JSESCPOSBuilder = {})); 968 | })(Neodynamic || (Neodynamic = {})); 969 | --------------------------------------------------------------------------------