├── readme └── demo.gif ├── library.properties ├── License.txt ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── keywords.txt ├── examples ├── first_view_esp32 │ └── first_view_esp32.ino ├── bitmap_printing │ └── bitmap_printing.ino └── first_view_arduino │ └── first_view_arduino.ino ├── Readme.md ├── TPrinter.h └── TPrinter.cpp /readme/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryWorlds/ThermalPrinter/HEAD/readme/demo.gif -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ThermalPrinter library by BinaryWorlds 2 | version=1.2 3 | author=BinaryWorlds 4 | maintainer= 5 | sentence=ThermalPrinter library for arduino and esp32 6 | paragraph=ThermalPrinter library for arduino and esp32 7 | category=Device Control 8 | url=https://github.com/BinaryWorlds/ThermalPrinter 9 | architectures=* 10 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | made by BinaryWorlds 2 | Not for commercial use, in other case by free to use it. 3 | Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter 4 | 5 | I am not responsible for errors in the library. I deliver it "as it is". 6 | I will be grateful for all suggestions. 7 | 8 | Tested on firmware 2.69 and JP-QR701 9 | Some features may not work on the older firmware. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | Printer model: e.g JP-QR701 11 | Printer firmware: e.g 2.69 12 | Library relase: e.g v1.0 13 | 14 | 15 | **Describe the bug** 16 | A clear and concise description of what the bug is. 17 | 18 | **To Reproduce** 19 | Paste simple code(.ino) making bug - not your whole project. 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | keywords.txt - keywords file for the ThermalPrinter 2 | created by BinaryWorlds 3 | https://github.com/BinaryWorlds 4 | ***************************************************** 5 | DATATYPES (KEYWORD1) 6 | 7 | Tprinter KEYWORD1 8 | ***************************************************** 9 | METHOD AND FUNCTIONS (KEYWORD2) 10 | 11 | write KEYWORD2 12 | feed KEYWORD2 13 | enableDtr KEYWORD2 14 | disableDtr KEYWORD2 15 | wait KEYWORD2 16 | setDelay KEYWORD2 17 | setCodePage KEYWORD2 18 | setCharset KEYWORD2 19 | autoCalculate KEYWORD2 20 | calculatePrintTime KEYWORD2 21 | setTimes KEYWORD2 22 | setHeat KEYWORD2 23 | setMode KEYWORD2 24 | unsetMode KEYWORD2 25 | invert KEYWORD2 26 | justify KEYWORD2 27 | underline KEYWORD2 28 | setInterline KEYWORD2 29 | setCharspacing KEYWORD2 30 | setTabs KEYWORD2 31 | clearTabs KEYWORD2 32 | tab KEYWORD2 33 | reset KEYWORD2 34 | begin KEYWORD2 35 | offline KEYWORD2 36 | online KEYWORD2 37 | identifyChars KEYWORD2 38 | printFromSerial KEYWORD2 39 | printCharset KEYWORD2 40 | printCodepage KEYWORD2 41 | printPosition KEYWORD2 42 | printBitmap KEYWORD2 -------------------------------------------------------------------------------- /examples/first_view_esp32/first_view_esp32.ino: -------------------------------------------------------------------------------- 1 | // made by BinaryWorlds 2 | // Not for commercial use, in other case by free to use it. 3 | // Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter 4 | 5 | // I am not responsible for errors in the library. I deliver it "as it is". 6 | // I will be grateful for all suggestions. 7 | 8 | // Tested on firmware 2.69 and JP-QR701 9 | // Some features may not work on the older firmware. 10 | 11 | #include 12 | #include // if error you can also use SoftwareSerial, check first_view_arduino 13 | 14 | #include "TPrinter.h" 15 | 16 | // You need to use max3485(for 3V3 logic lvl) or similar, if you have printer with rs232. 17 | // If you use esp32 or other MCU with 3v3 logic level you can try with logic level converter. 18 | 19 | // Check which pin pairs are responsible for communication on your board! 20 | const byte rxPin = 16; 21 | const byte txPin = 17; 22 | const int printerBaudrate = 9600; // or 19200 usually 23 | 24 | const byte dtrPin = 4; // if used 25 | 26 | HardwareSerial mySerial(1); 27 | Tprinter myPrinter(&mySerial, printerBaudrate); 28 | // you can assign here other stream like Serial1, Serial2, Serial3 etc 29 | 30 | void setup() { 31 | micros(); 32 | Serial.begin(9600); // monitor 33 | mySerial.begin(printerBaudrate, SERIAL_8N1, rxPin, txPin); // must be 8N1 mode 34 | myPrinter.begin(); // you can edit what be happen in Tprinter.cpp, like delay time(2s) 35 | myPrinter.enableDtr(dtrPin, LOW); // pinNR, busyState; 36 | // my printer is busy when DTR is LOW, 37 | // there is a high probability that you should change it to HIGH; 38 | // if wrong - print will no start 39 | 40 | // if you dont enable checking dtr, you should call this: 41 | // myPrinter.autoCalculate(); 42 | 43 | // or you can set it manually using this: 44 | // myPrinter.autoCalculate(0); // turn off 45 | // myPrinter.setTimes(30000, 3000); // oneDotHeight_printTime, oneDotHeight_feedTime in micros 46 | // last is worst option 47 | 48 | 49 | myPrinter.println("charset:"); 50 | myPrinter.printCharset(); 51 | 52 | myPrinter.println("codepage:"); 53 | myPrinter.printCodepage(); 54 | 55 | myPrinter.justify('C'); 56 | myPrinter.println("center"); 57 | myPrinter.justify('R'); 58 | myPrinter.println("right"); 59 | myPrinter.justify('L'); 60 | myPrinter.println("left"); 61 | 62 | uint8_t list[] = {5, 10, 15, 20, 25}; 63 | myPrinter.setTabs(list, 5); 64 | myPrinter.print("1"); 65 | myPrinter.tab(); 66 | myPrinter.print("2"); 67 | myPrinter.tab(); 68 | myPrinter.print("3"); 69 | myPrinter.tab(); 70 | myPrinter.print("4"); 71 | myPrinter.println(); 72 | 73 | myPrinter.setMode(FONT_B, DOUBLE_WIDTH, DOUBLE_HEIGHT); 74 | myPrinter.println("FONT_B, bigger"); 75 | myPrinter.unsetMode(FONT_B); 76 | myPrinter.println("FONT_A, bigger"); 77 | 78 | myPrinter.feed(6); 79 | myPrinter.identifyChars("ą ę"); // UTF-8 80 | } 81 | 82 | void loop() { 83 | myPrinter.printFromSerial(); // open monitor and print something 84 | } 85 | -------------------------------------------------------------------------------- /examples/bitmap_printing/bitmap_printing.ino: -------------------------------------------------------------------------------- 1 | // made by BinaryWorlds 2 | // Not for commercial use, in other case by free to use it. 3 | // Just copy this text and link to oryginal repository: 4 | // https://github.com/BinaryWorlds/ThermalPrinter 5 | 6 | // I am not responsible for errors in the library. I deliver it "as it is". 7 | // I will be grateful for all suggestions. 8 | 9 | // Tested on firmware 2.69 and JP-QR701 10 | // Some features may not work on the older firmware. 11 | 12 | #include 13 | #include 14 | 15 | #include "TPrinter.h" 16 | 17 | const uint8_t bitmapWidth = 40; 18 | const uint8_t bitmapHeight = 37; 19 | 20 | // link to repo 21 | uint8_t qrcode[] = { 22 | 0x7F, 0x2, 0x72, 0x1D, 0xFC, 0x41, 0x5, 0x38, 0xE1, 0x4, 0x5D, 0x75, 0x73, 0x51, 0x74, 0x5D, 23 | 0x25, 0x0, 0x35, 0x74, 0x5D, 0x4E, 0xB7, 0x99, 0x74, 0x41, 0x7C, 0x8F, 0x45, 0x4, 0x7F, 0x55, 24 | 0x55, 0x55, 0xFC, 0x0, 0x27, 0x2E, 0x20, 0x0, 0x25, 0x46, 0xE3, 0x6E, 0xD0, 0xE, 0xBE, 0x87, 25 | 0x91, 0x8, 0x33, 0x95, 0xC7, 0xFA, 0x60, 0x20, 0xF1, 0x9A, 0x5E, 0xF8, 0xB, 0xB, 0x93, 0x43, 26 | 0x8C, 0x3A, 0xA7, 0x28, 0xBE, 0x50, 0x7D, 0x8B, 0x6F, 0x8D, 0x30, 0x34, 0xD2, 0xB2, 0xD5, 0x9C, 27 | 0x73, 0xEC, 0x2C, 0x3, 0xB8, 0x78, 0xC, 0x21, 0x6D, 0xC0, 0x3, 0xEA, 0xCA, 0xCB, 0x80, 0x56, 28 | 0x5E, 0xDE, 0x9E, 0xDC, 0x63, 0xAA, 0x3, 0xB, 0x18, 0x2, 0x1A, 0x50, 0xB8, 0x48, 0x2B, 0x8F, 29 | 0xFD, 0x8E, 0x0, 0x28, 0x57, 0x63, 0x94, 0xB0, 0x23, 0xA7, 0x63, 0x39, 0x5C, 0x4C, 0x77, 0x7A, 30 | 0x27, 0xF0, 0x1D, 0xA4, 0x0, 0xF6, 0xA0, 0x2, 0x4A, 0xA7, 0x91, 0x8, 0x67, 0x7D, 0xA7, 0x8F, 31 | 0xC8, 0x0, 0x72, 0xE3, 0xBC, 0x60, 0x7F, 0x2C, 0x80, 0xE5, 0x78, 0x41, 0x30, 0x4D, 0x84, 0x5C, 32 | 0x5D, 0x41, 0x69, 0xC7, 0xF4, 0x5D, 0x11, 0xFC, 0x9, 0x70, 0x5D, 0x2D, 0x46, 0x15, 0x88, 0x41, 33 | 0x6B, 0x33, 0x4A, 0xD8, 0x7F, 0x1D, 0xF, 0xA8, 0x1C}; 34 | // 185 bytes length 35 | // 40 * 37 * 8 = 1480 36 | 37 | const byte rxPin = 16; 38 | const byte txPin = 17; 39 | const byte dtrPin = 27; // optional 40 | const byte rsePin = 4; // direction of transmission, max3485 41 | 42 | HardwareSerial mySerial(1); 43 | Tprinter myPrinter(&mySerial, 9600); 44 | 45 | void setup() { 46 | micros(); 47 | mySerial.begin(9600, SERIAL_8N1, rxPin, txPin); 48 | 49 | pinMode(rsePin, OUTPUT); // optional 50 | digitalWrite(rsePin, HIGH); // optional 51 | 52 | // myPrinter.enableDtr(dtrPin, LOW); 53 | 54 | myPrinter.begin(); 55 | myPrinter.setHeat(1, 224, 40); // in begin setHeat was called with val: 0,255,0 56 | myPrinter.justify('C'); // only text 57 | 58 | myPrinter.printBitmap(qrcode, bitmapWidth, bitmapHeight); 59 | myPrinter.feed(1); 60 | myPrinter.println("orginal size"); 61 | 62 | myPrinter.printBitmap(qrcode, bitmapWidth, bitmapHeight, 5); 63 | myPrinter.feed(1); 64 | myPrinter.println("5x bigger"); 65 | 66 | myPrinter.printBitmap(qrcode, bitmapWidth, bitmapHeight, 0); 67 | myPrinter.feed(1); 68 | myPrinter.println("max size"); 69 | 70 | myPrinter.printBitmap(qrcode, bitmapWidth, bitmapHeight, 1, false); 71 | myPrinter.feed(1); 72 | myPrinter.println("original size, not centered"); 73 | } 74 | void loop() {} -------------------------------------------------------------------------------- /examples/first_view_arduino/first_view_arduino.ino: -------------------------------------------------------------------------------- 1 | // made by BinaryWorlds 2 | // Not for commercial use, in other case by free to use it. 3 | // Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter 4 | 5 | // I am not responsible for errors in the library. I deliver it "as it is". 6 | // I will be grateful for all suggestions. 7 | 8 | // Tested on firmware 2.69 and JP-QR701 9 | // Some features may not work on the older firmware. 10 | 11 | #include 12 | #include // if error you can also use HardwareSerial.h, after adding library 13 | 14 | #include "TPrinter.h" 15 | 16 | // You need to use max3485(for 3V3 logic lvl) or similar, if you have printer with rs232. 17 | // If you use esp32 or other MCU with 3v3 logic level you can try with logic level converter. 18 | 19 | // Check which pin pairs are responsible for communication on your board! 20 | 21 | const byte rxPin = 10; // Not all pins of arduino support interrupts, check it! 22 | const byte txPin = 11; 23 | const int printerBaudrate = 9600; // or 19200 usually 24 | 25 | const byte dtrPin = 4; // if used 26 | 27 | SoftwareSerial mySerial(rxPin, txPin); 28 | Tprinter myPrinter(&mySerial, printerBaudrate); 29 | // you can assign here other stream like Serial1, Serial2, Serial3 etc 30 | 31 | void setup() { 32 | micros(); 33 | pinMode(rxPin, INPUT); 34 | pinMode(txPin, OUTPUT); 35 | Serial.begin(9600); // monitor 36 | mySerial.begin(printerBaudrate); // must be 8N1 mode 37 | myPrinter.begin(); // you can edit what be happen in Tprinter.cpp, like delay time(2s) 38 | myPrinter.enableDtr(dtrPin, LOW); // pinNR, busyState; 39 | // my printer is busy when DTR is LOW, 40 | // there is a high probability that you should change it to HIGH; 41 | // if wrong - print will no start 42 | 43 | // if you dont enable checking dtr, you should call this: 44 | // myPrinter.autoCalculate(); 45 | 46 | // or you can set it manually using this: 47 | // myPrinter.autoCalculate(0); // turn off 48 | // myPrinter.setTimes(30000, 3000); // oneDotHeight_printTime, oneDotHeight_feedTime in micros 49 | // last is worst option 50 | 51 | 52 | myPrinter.println("charset:"); 53 | myPrinter.printCharset(); 54 | 55 | myPrinter.println("codepage:"); 56 | myPrinter.printCodepage(); 57 | 58 | myPrinter.justify('C'); 59 | myPrinter.println("center"); 60 | myPrinter.justify('R'); 61 | myPrinter.println("right"); 62 | myPrinter.justify('L'); 63 | myPrinter.println("left"); 64 | 65 | uint8_t list[] = {5, 10, 15, 20, 25}; 66 | myPrinter.setTabs(list, 5); 67 | myPrinter.print("1"); 68 | myPrinter.tab(); 69 | myPrinter.print("2"); 70 | myPrinter.tab(); 71 | myPrinter.print("3"); 72 | myPrinter.tab(); 73 | myPrinter.print("4"); 74 | myPrinter.println(); 75 | 76 | myPrinter.setMode(FONT_B, DOUBLE_WIDTH, DOUBLE_HEIGHT); 77 | myPrinter.println("FONT_B, bigger"); 78 | myPrinter.unsetMode(FONT_B); 79 | myPrinter.println("FONT_A, bigger"); 80 | 81 | myPrinter.feed(6); 82 | myPrinter.identifyChars("ą ę"); // UTF-8 83 | } 84 | 85 | void loop() { 86 | myPrinter.printFromSerial(); // open monitor and print something 87 | } -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |

Thermal Printer library for arduino/esp32

2 | 3 | # Table of Contents 4 | 5 | - [Introduction](#introduction) 6 | - [Quick-start](#quick-start) 7 | - [Features](#features) 8 | 9 |
demo gif
10 | 11 | # Introduction 12 | 13 | A printout exactly as you planned! 14 | I decided to create a more functional library than the popular Adafruit library. 15 | Less errors, easier start - just use! 16 | I will be grateful for feedback. 17 | 18 | Created by BinaryWorlds @2019 19 | 20 | Tested on firmware 2.69 and JP-QR701 21 | Some features may not work on the older firmware. 22 | 23 | Check the comments in [TPrinter.h](TPrinter.h) and [TPrinter.cpp](TPrinter.cpp) to learn more. 24 | 25 | # Quick start 26 | 27 | Check examples. 28 | 29 | 1. Import library: 30 | 31 | ``` 32 | #include "TPrinter.h" 33 | #include // or SoftwareSerial 34 | ``` 35 | 36 | 2. Set baudrate and pins. 37 | 38 | ``` 39 | const int printerBaudrate = 9600; // or 19200 usually 40 | const byte rxPin = 16; // check datasheet of your board 41 | const byte txPin = 17; // check datasheet of your board 42 | const byte dtrPin = 4; // if used 43 | ``` 44 | 45 | 3. Init 46 | 47 | ``` 48 | HardwareSerial mySerial(1); 49 | Tprinter myPrinter(&mySerial, printerBaudrate); 50 | 51 | void setup() { 52 | micros(); 53 | mySerial.begin(printerBaudrate, SERIAL_8N1, rxPin, txPin); // must be 8N1 mode 54 | myPrinter.begin(); 55 | } 56 | ``` 57 | 58 | # Features 59 | 60 | - [Waiting for end of print process](#waiting-for-end-of-print-process) 61 | - [Change heating parametrs](#change-heating-parametrs) 62 | - [Print bitmap - scalable and centered](#print-bitmap---scalable-and-centered) 63 | 64 | ## Waiting for end of print process 65 | 66 | Mode, choose one: 67 | 68 | 1. By checking DTR pin 69 | If enabled and set wrong busyState - print will no start. 70 | 71 | ``` 72 | myPrinter.enableDtr(dtrPin, HIGH); // pinNR, busyState - default LOW; 73 | ``` 74 | 75 | ``` 76 | disableDtr(); // disable checking DTR pin 77 | ``` 78 | 79 | 2. Calculate print time basing on current heating parametrs (default). 80 | Fast as DTR(similar time). 81 | 82 | ``` 83 | myPrinter.autoCalculate(true); // false - off 84 | ``` 85 | 86 | 3. Set constant time as in Adafruif library (worst option). 87 | This mode is active, if DTR and autocalculate is disabled. 88 | 89 | ``` 90 | myPrinter.autoCalculate(false); // turn off default mode 91 | 92 | myPrinter.setTimes(30000, 3000); 93 | // oneDotHeight_printTime, default: 30000, 94 | // oneDotHeight_feedTime, default: 3000 95 | // in micros 96 | ``` 97 | 98 | ## Change heating parametrs 99 | 100 | ``` 101 | myPrinter.setHeat(1, 224, 40); // default: 0,255,0 called in begin 102 | ``` 103 | 104 | Best quality: the smallest number of dots burned, the longest heating time 105 | 106 | - dots: default 9 (80dots) becouse (9+1)\* 8; units: 8 dots; 107 | - time: default 80 (800 us); units: 10 us 108 | - interval: default 2 (20us); units: 10 us 109 | 110 | (default in printer) 111 | 112 | ## Print bitmap - scalable and centered 113 | 114 | ``` 115 | printBitmap(*bitmap, width, height, scale = 1, center = true) 116 | ``` 117 | 118 | - bitmap - uint8_t array, each bit in byte - one printed dot(scale 1) 119 | - width of bitmap - must be a multiple of 8 120 | for example, if you try to print 121 | [Adarfruit logo](https://github.com/adafruit/Adafruit-Thermal-Printer-Library/blob/master/examples/A_printertest/adalogo.h) 122 | set width to 80. It's real size of this image. adalogo_data has 750 bytes length. 123 | 80 dots width \* 75 dots height = 6000 dots 124 | 6000 dots / 8 = 750 bytes 125 | Each line in example have 5 white dots at right side. 126 | This is because the data is sent in bytes 127 | - height of bitmap - real value, in above example - 75 128 | - scale - default 1, if 0 or greater than the maximum possible scale - the image is printed at it's maximum size 129 | - center - default true 130 | 131 | 132 | -------------------------------------------------------------------------------- /TPrinter.h: -------------------------------------------------------------------------------- 1 | // made by BinaryWorlds 2 | // Not for commercial use, in other case by free to use it. 3 | // Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter 4 | 5 | // I am not responsible for errors in the library. I deliver it "as it is". 6 | // I will be grateful for all suggestions. 7 | 8 | // Tested on firmware 2.69 and JP-QR701 9 | // Some features may not work on the older firmware. 10 | 11 | #ifndef TPrinter_h 12 | #define TPrinter_h 13 | #include "Arduino.h" 14 | 15 | #define A_GS 29 16 | #define A_DC2 18 // Device control 2 17 | #define A_HT 9 // HorizontalTab 18 | #define A_LF 10 // 0x0A Line feed 19 | #define A_CR 13 // 0x0D Carriage return 20 | #define A_SPACE 32 // 0x20 Space 21 | #define A_ESC 27 // 0x1B Escape 22 | #define A_FS 28 // 0x1C Field separator 23 | #define A_FF 14 // 0x0C Form feed 24 | #define A_STAR 42 // 0x2A Star sign 25 | 26 | #define FONT_B 1 // Font B: 9x17, Standard font A: 12x24 27 | #define DARK_MODE (1 << 1) // anti-white mode, didn't work? 28 | #define UPSIDE_DOWN (1 << 2) // didn't work?, use invert(bool); 29 | #define BOLD (1 << 3) 30 | #define DOUBLE_HEIGHT (1 << 4) 31 | #define DOUBLE_WIDTH (1 << 5) 32 | #define STRIKEOUT (1 << 6) // didn't work? 33 | 34 | // from translator 35 | #define CODEPAGE_CP437 0 // USA, European Standard 36 | #define CODEPAGE_KATAKANA 1 37 | #define CODEPAGE_CP850 2 // Multilingual 38 | #define CODEPAGE_CP860 3 // Portugal 39 | #define CODEPAGE_CP863 4 // Canada-French 40 | #define CODEPAGE_CP865 5 // Nordic 41 | #define CODEPAGE_WCP1251 6 // Slavic 42 | #define CODEPAGE_CP866 7 // Slavic 2 43 | #define CODEPAGE_MIK 8 // Slavic/Bulgarian 44 | #define CODEPAGE_CP755 9 // East Europe, Latvia 2 45 | #define CODEPAGE_IRAN 10 // Persia 46 | #define CODEPAGE_CP862 15 // Hebrew 47 | #define CODEPAGE_WCP1252 16 // Latin 1 48 | #define CODEPAGE_WCP1253 17 // Greece 49 | #define CODEPAGE_CP852 18 // Latin 2 50 | #define CODEPAGE_CP858 19 // Multilingual Latin 1 + ? 51 | #define CODEPAGE_IRAN2 20 // Perisan 52 | #define CODEPAGE_LATVIA 21 53 | #define CODEPAGE_CP864 22 // Arabic 54 | #define CODEPAGE_ISO_8859_1 23 // Western Europe 55 | #define CODEPAGE_CP737 24 // Greece 56 | #define CODEPAGE_WCP1257 25 // Baltic 57 | #define CODEPAGE_THAI 26 58 | #define CODEPAGE_CP720 27 // Arabic 59 | #define CODEPAGE_CP855 28 60 | #define CODEPAGE_CP857 29 // Turkish 61 | #define CODEPAGE_WCP1250 30 // Central Europe 62 | #define CODEPAGE_CP775 31 63 | #define CODEPAGE_WCP1254 32 // Turkish 64 | #define CODEPAGE_WCP1255 33 // Hebrew 65 | #define CODEPAGE_WCP1256 34 // Arabic 66 | #define CODEPAGE_WCP1258 35 // Vietnamese 67 | #define CODEPAGE_ISO_8859_2 36 // Latin 2 68 | #define CODEPAGE_ISO_8859_3 37 // Latin 3 69 | #define CODEPAGE_ISO_8859_4 38 // Baltic 70 | #define CODEPAGE_ISO_8859_5 39 // Slavic 71 | #define CODEPAGE_ISO_8859_6 40 // Arabic 72 | #define CODEPAGE_ISO_8859_7 41 // Greek 73 | #define CODEPAGE_ISO_8859_8 42 // Hebrew 74 | #define CODEPAGE_ISO_8859_9 43 // Turkish 75 | #define CODEPAGE_ISO_8859_15 44 // Latin 9 76 | #define CODEPAGE_THAI2 45 77 | #define CODEPAGE_CP856 46 78 | #define CODEPAGE_CP874 47 79 | 80 | #define CHARSET_USA 0 81 | #define CHARSET_FRANCE 1 82 | #define CHARSET_GERMANY 2 83 | #define CHARSET_UK 3 84 | #define CHARSET_DENMARK1 4 85 | #define CHARSET_SWEDEN 5 86 | #define CHARSET_ITALY 6 87 | #define CHARSET_SPAIN_1 7 88 | #define CHARSET_JAPAN 8 89 | #define CHARSET_NORWAY 9 90 | #define CHARSET_DENMARK_2 10 91 | #define CHARSET_SPAIN2 11 92 | #define CHARSET_LATIN_AMERICA 12 93 | #define CHARSET_SOUTH_KOREA 13 94 | #define CHARSET_SLOVENIA 14 95 | #define CHARSET_CHINA 15 96 | 97 | class Tprinter : public Print { 98 | private: 99 | Stream *stream; 100 | 101 | int baudrate{9600}; // 19200 102 | 103 | bool 104 | busyState = HIGH, 105 | calculateMode{true}, 106 | dtrEnabled{false}; 107 | // tested: 108 | // when printer stop being busy, it's doesn't mean end of printing 109 | // dtr pin informs about the availability of the printer's firmware - propably; 110 | // keep it in mind, 111 | // it's a big difference when you don't use dtr pin and the time needed for printing is calculated 112 | 113 | const uint16_t widthInDots = {384}; // to calculate aboslute position, when using some functions like setCharSpacing 114 | const uint8_t printerBufferLimit = {255}; // bytes 115 | 116 | uint16_t 117 | cursor{}, // actual position, n of 384 118 | tabs[32] = {}; // default in printer: 8,16,24,32 (*12dots) - doesn't work in my case 119 | uint8_t 120 | dtrPin{}, 121 | tabsAmount = {0}, 122 | widthMax{32}, // max chars per line 123 | charHeight{24}, // dots 124 | charWidth{12}, // dots 125 | interlineHeight{6}, // dots 126 | charSpacing{}, // dots 127 | printMode{}, 128 | heating_dots{9}, 129 | heating_time{80}, 130 | heating_interval{2}; 131 | unsigned long 132 | endPoint{}, 133 | char_send_time{}, 134 | oneDotHeight_printTime{40000}, 135 | oneDotHeight_feedTime{3000}, 136 | feed_time{63000}, // for 6 dot interline 137 | print_time{720000}; // for 24 high dot 138 | 139 | void update(), 140 | initBitmapData(uint8_t rowsInPackage, uint8_t bytesPerRow), 141 | sendBitmapByte(uint8_t byteToSend), 142 | setDelayBitmap(uint16_t width, uint16_t height, uint16_t blackPixels); 143 | 144 | public: 145 | Tprinter(Stream *s, int baud = 9600); 146 | 147 | size_t write(uint8_t sign); // from inherited Print class, you can use println() ... 148 | 149 | void feed(uint8_t n = 1), // feed n lines 150 | enableDtr(uint8_t dtr, bool busy = HIGH), // pin nr, printer busy when DTR is HIGH or LOW 151 | disableDtr(bool mode = 1), // 1 - INPUT_PULLUP, 0 - INPUT_PULLDOWN 152 | 153 | wait(), 154 | setDelay(unsigned long time), // microseconds; ignored if Dtr pin is enabled 155 | 156 | setCodePage(uint8_t page = 36), 157 | setCharset(uint8_t val = 14), 158 | 159 | autoCalculate(bool val = true), 160 | // true - ON; 161 | // calculate on the basis of heating points, time and interval 162 | // every time when you change printMode or heating parameters 163 | 164 | // false - off 165 | // calculate on the basis of oneDotHeight_printTime and oneDotHeight_feedTime 166 | // you can change values above using setTimes 167 | 168 | calculatePrintTime(), // ignored if Dtr pin is enabled 169 | setTimes(unsigned long p = 30000, unsigned long f = 3000), // ignored if Dtr pin is enabled or autoCalculate is ON 170 | setHeat(uint8_t n1 = 0, uint8_t n2 = 255, uint8_t n3 = 0), 171 | // best quality: the smallest number of dots burned, the longest heating time 172 | // dots: default 9 (80dots) becouse (9+1)* 8; units: 8 dots; 173 | // time: default 80 (800 us); units: 10 us 174 | // interval: default 2 (20us); units :10 us 175 | 176 | setMode(uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0), 177 | unsetMode(uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0, uint8_t = 0), 178 | 179 | invert(bool n = 0), // 1 - invert ON 180 | justify(char val), // 'L' - Left 'C' - center 'R' - right 181 | underline(uint8_t n), // off 0 - 2 max 182 | setInterline(uint8_t n), // default: 6,after call begin() set to 0 183 | setCharSpacing(uint8_t n = 0), // n x 0.125 millimeters(1dot); x2 if double width 184 | setTabs(uint8_t *tab = 0, uint8_t size = 0), 185 | clearTabs(), 186 | tab(), 187 | 188 | reset(), 189 | begin(), // simply start; edit default value for your preference; 190 | offline(), 191 | online(), 192 | 193 | printCharset(), // print chars, 0x23-0x7E range 194 | printCodepage(), // print chars, 0x80-0xFF range 195 | printBitmap(uint8_t *bitmap, uint16_t width, uint16_t height, uint8_t scale = 1, bool center = true), 196 | // scale: default - 1, orginal size; if 0 or bigger than possible - max possible scale 197 | // center: if not set or true - centered 198 | 199 | // use below only if printer use hardware serial 200 | identifyChars(char *tab), // require Serial.print(baudrate); in void setup() 201 | printFromSerial(); // require Serial.print(baudrate); in void setup() 202 | uint16_t printPosition(); // require Serial.print(baudrate); in void setup(); 203 | }; 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /TPrinter.cpp: -------------------------------------------------------------------------------- 1 | // made by BinaryWorlds 2 | // Not for commercial use, in other case by free to use it. 3 | // Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter 4 | 5 | // I am not responsible for errors in the library. I deliver it "as it is". 6 | // I will be grateful for all suggestions. 7 | 8 | // Tested on firmware 2.69 and JP-QR701 9 | // Some features may not work on the older firmware. 10 | 11 | #include "TPrinter.h" 12 | 13 | Tprinter::Tprinter(Stream *s, int baud) : stream(s), baudrate(baud) { 14 | char_send_time = (11 * 1000000 / baud); // for 8N1 15 | } 16 | 17 | // private 18 | void Tprinter::update() { 19 | charHeight = (printMode & FONT_B) ? 17 : 24; // B : A 20 | charWidth = (printMode & FONT_B) ? 9 : 12; 21 | widthMax = (printMode & FONT_B) ? 42 : 32; 22 | if (printMode & DOUBLE_WIDTH) { 23 | charWidth *= 2; 24 | widthMax /= 2; 25 | } 26 | if (printMode & DOUBLE_HEIGHT) charHeight *= 2; 27 | if (calculateMode) { 28 | calculatePrintTime(); 29 | } else { 30 | print_time = charHeight * oneDotHeight_printTime; 31 | feed_time = (charHeight + interlineHeight) * oneDotHeight_feedTime; 32 | } 33 | } 34 | 35 | size_t Tprinter::write(uint8_t sign) { 36 | if (sign != A_CR) { 37 | wait(); 38 | unsigned long val = char_send_time; 39 | stream->write(sign); 40 | cursor += charWidth + charSpacing; 41 | if (printMode & DOUBLE_WIDTH) cursor += charSpacing; 42 | if ((widthInDots - cursor) < charWidth && sign != '\n') stream->write(sign = '\n'); 43 | // force the printout of a new line; 44 | // printer print a line after took widthMax + 1 char 45 | 46 | if (sign == '\n') { 47 | if (calculateMode) { 48 | val += (cursor * print_time) / widthInDots + feed_time; 49 | } else { 50 | val += print_time + feed_time; // max time 51 | } 52 | cursor = 0; 53 | } 54 | setDelay(val); 55 | // printPosition(); 56 | } 57 | return 1; 58 | } 59 | 60 | void Tprinter::feed(uint8_t n) { 61 | wait(); 62 | stream->write(A_ESC); 63 | stream->write('d'); 64 | stream->write(n); 65 | setDelay(3 * char_send_time + feed_time * n); 66 | cursor = 0; 67 | } 68 | 69 | void Tprinter::enableDtr(uint8_t dtr, bool busy) { 70 | if (dtrEnabled && dtrPin != dtr) disableDtr(); // useless but possible 71 | dtrPin = dtr; 72 | busyState = busy; 73 | pinMode(dtrPin, INPUT_PULLUP); 74 | dtrEnabled = true; 75 | wait(); 76 | stream->write(A_GS); 77 | stream->write('a'); 78 | stream->write(uint8_t(1 << 5)); 79 | setDelay(3 * char_send_time); 80 | } 81 | 82 | void Tprinter::disableDtr(bool mode) { 83 | // if pin unused - pull them for decrease(vs INPUT mode) 84 | // EMI, noisy and power concumption 85 | #ifdef INPUT_PULLDOWN 86 | if (mode) { 87 | pinMode(dtrPin, INPUT_PULLUP); 88 | } else { 89 | pinMode(dtrPin, INPUT_PULLDOWN); 90 | } 91 | #else 92 | pinMode(dtrPin, INPUT_PULLUP); 93 | #endif 94 | dtrEnabled = false; 95 | } 96 | 97 | void Tprinter::wait() { 98 | if (dtrEnabled) { 99 | while (digitalRead(dtrPin) == busyState) { 100 | }; // 0 - my printer busy, check your printer 101 | } else { 102 | while (long(micros() - endPoint) < 0) { 103 | }; 104 | } 105 | } 106 | 107 | void Tprinter::setDelay(unsigned long time) { 108 | if (!dtrEnabled) endPoint = (micros() + time); 109 | } 110 | 111 | void Tprinter::setCodePage(uint8_t page) { 112 | // Set the same encoding in text editor as in the printer! 113 | if (page > 47) page = 47; 114 | 115 | wait(); 116 | stream->write(A_FS); 117 | stream->write('.'); // kanji mode off 118 | 119 | stream->write(A_ESC); 120 | stream->write('t'); 121 | stream->write(page); 122 | setDelay(5 * char_send_time); 123 | } 124 | 125 | void Tprinter::setCharset(uint8_t val) { 126 | if (val > 15) val = 15; 127 | wait(); 128 | 129 | stream->write(A_ESC); 130 | stream->write('R'); 131 | stream->write(val); 132 | setDelay(3 * char_send_time); 133 | } 134 | 135 | void Tprinter::autoCalculate(bool val) { 136 | calculateMode = val; 137 | update(); 138 | } 139 | 140 | void Tprinter::calculatePrintTime() { 141 | print_time = ((widthInDots * charHeight) / ((heating_dots + 1) * 8)) * 10 * (heating_time + heating_interval) / 2; 142 | // rarely all dots are printed 143 | } 144 | 145 | void Tprinter::setTimes(unsigned long p, unsigned long f) { 146 | oneDotHeight_printTime = p; 147 | oneDotHeight_feedTime = f; 148 | 149 | if (!calculateMode) { 150 | print_time = p * charHeight; 151 | feed_time = f * (interlineHeight + charHeight); 152 | } 153 | } 154 | 155 | void Tprinter::setHeat(uint8_t n1, uint8_t n2, uint8_t n3) { 156 | wait(); 157 | stream->write(A_ESC); 158 | stream->write('7'); 159 | stream->write(heating_dots = n1); 160 | stream->write(heating_time = n2); 161 | stream->write(heating_interval = n3); 162 | setDelay(5 * char_send_time); 163 | if (calculateMode) calculatePrintTime(); 164 | } 165 | 166 | void Tprinter::setMode(uint8_t m1, uint8_t m2, uint8_t m3, uint8_t m4, uint8_t m5, uint8_t m6, uint8_t m7) { 167 | wait(); 168 | printMode |= (m1 + m2 + m3 + m4 + m5 + m6 + m7); 169 | stream->write(A_ESC); 170 | stream->write('!'); 171 | stream->write(printMode); 172 | setDelay(3 * char_send_time); 173 | update(); 174 | } 175 | 176 | void Tprinter::unsetMode(uint8_t m1, uint8_t m2, uint8_t m3, uint8_t m4, uint8_t m5, uint8_t m6, uint8_t m7) { 177 | wait(); 178 | printMode &= ~(m1 + m2 + m3 + m4 + m5 + m6 + m7); 179 | stream->write(A_ESC); 180 | stream->write('!'); 181 | stream->write(printMode); 182 | setDelay(3 * char_send_time); 183 | 184 | update(); 185 | } 186 | 187 | void Tprinter::invert(bool n) { 188 | wait(); 189 | stream->write(A_ESC); 190 | stream->write('{'); 191 | stream->write(n); 192 | setDelay(3 * char_send_time); 193 | } 194 | 195 | void Tprinter::justify(char val) { 196 | uint8_t set{}; 197 | wait(); 198 | 199 | switch (val) { 200 | case 'L': 201 | set = 0; 202 | break; 203 | case 'C': 204 | set = 1; 205 | break; 206 | case 'R': 207 | set = 2; 208 | break; 209 | } 210 | stream->write(A_ESC); 211 | stream->write('a'); 212 | stream->write(set); 213 | setDelay(3 * char_send_time); 214 | } 215 | 216 | void Tprinter::underline(uint8_t n) { 217 | if (n > 2) n = 2; 218 | wait(); 219 | stream->write(A_ESC); 220 | stream->write('-'); 221 | stream->write(n); 222 | setDelay(3 * char_send_time); 223 | } 224 | 225 | void Tprinter::setInterline(uint8_t n) { 226 | // ESC '2' - back to default 227 | wait(); 228 | stream->write(A_ESC); 229 | stream->write('3'); 230 | if (n + charHeight >= 255) { 231 | interlineHeight = 255; 232 | } else { 233 | interlineHeight = n + charHeight; 234 | } 235 | stream->write(interlineHeight); 236 | interlineHeight -= charHeight; 237 | 238 | update(); 239 | setDelay(3 * char_send_time); 240 | } 241 | 242 | void Tprinter::setCharSpacing(uint8_t n) { 243 | // printer default: 0 244 | wait(); 245 | stream->write(A_ESC); 246 | stream->write(A_SPACE); 247 | stream->write(charSpacing = n); 248 | setDelay(3 * char_send_time); 249 | } 250 | 251 | void Tprinter::setTabs(uint8_t *tab, uint8_t size) { 252 | // Enter values ​​in ascending order. 253 | // The next value can't be equal to or less than the previous one 254 | // - the printer will consider it as a data 255 | // (will finish setting the tabs) 256 | // sets as absolute position; 257 | tabs[tabsAmount = 0] = 0; 258 | wait(); 259 | stream->write(A_ESC); 260 | stream->write('D'); 261 | 262 | for (uint8_t i = 0; i < size; i++) { 263 | if (tab[i] < widthMax && tab[i] > (tabs[tabsAmount] / charWidth) && tabsAmount < 32) { 264 | stream->write(tab[i]); 265 | tabs[tabsAmount++] = tab[i] * charWidth; 266 | } 267 | } 268 | stream->write((uint8_t)0); // from datasheet - end of list 269 | cursor = 0; 270 | setDelay((tabsAmount + 3) * char_send_time); 271 | } 272 | 273 | void Tprinter::tab() { 274 | // If you don't set the next horizontal tab position 275 | // (bigger than actual cursor position), 276 | // the command is ignored. 277 | for (uint8_t i = 0; i < tabsAmount; i++) { 278 | if (tabs[i] > cursor) { 279 | cursor = tabs[i]; 280 | break; 281 | } 282 | } 283 | stream->write(A_HT); 284 | 285 | if ((widthInDots - cursor) < charWidth) { 286 | setDelay(char_send_time + print_time + feed_time); 287 | cursor = 0; // printer go newline 288 | } else { 289 | setDelay(char_send_time); 290 | } 291 | } 292 | 293 | void Tprinter::clearTabs() { 294 | stream->write(A_ESC); 295 | stream->write('D'); 296 | stream->write('0'); 297 | setDelay(3 * char_send_time); 298 | 299 | tabs[tabsAmount = 0] = 0; 300 | } 301 | 302 | void Tprinter::reset() { 303 | stream->write(A_ESC); 304 | stream->write('@'); 305 | setDelay(2 * char_send_time); 306 | 307 | cursor = 0; 308 | tabs[tabsAmount = 0] = 0; 309 | interlineHeight = 6; 310 | printMode = 0; 311 | charSpacing = 0; 312 | heating_dots = 9; 313 | heating_time = 80; 314 | heating_interval = 2; 315 | update(); 316 | } 317 | 318 | void Tprinter::begin() { 319 | setDelay(2000000); // 2s 320 | wait(); 321 | reset(); 322 | online(); 323 | setHeat(); 324 | setCodePage(); 325 | setCharset(); 326 | setInterline(0); // save paper during testing 327 | uint8_t list[] = {4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48}; 328 | setTabs(list, 12); // if widthMax == 32, last tab is 28 329 | } 330 | 331 | void Tprinter::offline() { 332 | wait(); 333 | stream->write(A_ESC); 334 | stream->write('='); 335 | stream->write((uint8_t)0); 336 | setDelay(3 * char_send_time); 337 | } 338 | 339 | void Tprinter::online() { 340 | wait(); 341 | stream->write(A_ESC); 342 | stream->write('='); 343 | stream->write((uint8_t)1); 344 | setDelay(3 * char_send_time); 345 | } 346 | 347 | // for test 348 | void Tprinter::identifyChars(char *tab) { 349 | // dont use it in the same time with printFromSerial() 350 | int i{}; 351 | Serial.println(); 352 | Serial.println(F("Separate letters with a space, e.g \"ą ć d\"!")); 353 | do { 354 | if (tab[i] != A_SPACE) { 355 | int val = i; 356 | while (tab[i] != A_SPACE && tab[i] != 0) { 357 | Serial.print(tab[i]); 358 | i++; 359 | } 360 | Serial.print(F(" HEX: ")); 361 | while (val != i) { 362 | Serial.print(tab[val], HEX); 363 | val++; 364 | } 365 | Serial.println(); 366 | } else { 367 | i++; 368 | } 369 | } while (tab[i] != 0); // end of string 370 | } 371 | 372 | void Tprinter::printFromSerial() { 373 | // you can use it e.g for test; 374 | // require Serial.begin(baudrate) in void setup() 375 | wait(); 376 | while (Serial.available()) { 377 | char sign{}; 378 | sign = (char)Serial.read(); 379 | print(sign); 380 | } 381 | } 382 | 383 | void Tprinter::printCharset() { 384 | wait(); 385 | println(); 386 | print(F(" 01234567 89ABCDEF")); 387 | for (uint8_t i = 32; i < 128; i++) { 388 | if ((i % 16) == 0) { 389 | println(); 390 | print(i / 16, DEC); 391 | print(F("- ")); 392 | } 393 | write(i); 394 | if ((i % 16) == 7) print(F(" ")); 395 | } 396 | println(); 397 | } 398 | 399 | void Tprinter::printCodepage() { 400 | wait(); 401 | println(); 402 | print(F(" 01234567 89ABCDEF")); 403 | for (uint8_t i = 128; i < 255; i++) { 404 | if ((i % 16) == 0) { 405 | println(); 406 | char val = 'A'; 407 | val += i / 16 - 10; 408 | if (i / 16 < 10) { 409 | print(i / 16, DEC); 410 | } else { 411 | print(val); 412 | } 413 | print(F("- ")); 414 | } 415 | write(i); 416 | if ((i % 16) == 7) print(F(" ")); 417 | } 418 | println(); 419 | } 420 | 421 | uint16_t Tprinter::printPosition() { 422 | Serial.print("Actual position: "); 423 | Serial.println(cursor, DEC); 424 | return cursor; 425 | } 426 | 427 | // private 428 | void Tprinter::initBitmapData(uint8_t rowsInPackage, uint8_t bytesPerRow) { 429 | wait(); 430 | stream->write(A_DC2); 431 | stream->write(A_STAR); 432 | stream->write(rowsInPackage); 433 | stream->write(bytesPerRow); 434 | setDelay(4 * char_send_time); 435 | } 436 | 437 | // private 438 | void Tprinter::sendBitmapByte(uint8_t byteToSend) { 439 | wait(); 440 | stream->write(byteToSend); 441 | setDelay(char_send_time); 442 | } 443 | 444 | // private 445 | void Tprinter::setDelayBitmap(uint16_t width, uint16_t height, uint16_t blackPixels) { 446 | if (dtrEnabled) return; 447 | if (calculateMode) { 448 | uint16_t totalPixels = width * height; 449 | unsigned long time = 450 | (blackPixels / totalPixels) * 451 | (((totalPixels / ((heating_dots + 1) * 8)) * 10 * (heating_time + heating_interval))); 452 | setDelay(time); 453 | return; 454 | } 455 | setDelay((oneDotHeight_printTime + oneDotHeight_feedTime) * height); 456 | } 457 | 458 | void Tprinter::printBitmap(uint8_t *bitmap, uint16_t width, uint16_t height, uint8_t scale, bool center) { 459 | uint8_t maxScale = widthInDots / width; // widthInDots = 384; 460 | if (scale == 0 || scale > maxScale) scale = maxScale; 461 | 462 | bool isMarginAdded = {}; 463 | const uint8_t marginWidth = center ? (widthInDots - scale * width) / 2 : 0; 464 | uint8_t marginCounter = {}; 465 | 466 | const uint8_t bytesPerRow = (scale * width + marginWidth + 7) / 8; 467 | 468 | const uint8_t bufferSize = (printerBufferLimit / bytesPerRow) * bytesPerRow; 469 | uint8_t bufferFillLevel = {}; 470 | 471 | uint8_t rowsInPackage = bufferSize / bytesPerRow; 472 | uint16_t totalRowsToSend = height * scale; 473 | const uint16_t printedWidth = width * scale + marginWidth; 474 | uint16_t currentDotNr = {}; 475 | 476 | uint8_t dot = {}; 477 | uint8_t byteToSend = {}; 478 | uint8_t offset = {7}; 479 | 480 | uint16_t burned{}; 481 | 482 | feed(1); 483 | 484 | for (uint16_t row = 0; row < height; row++) { 485 | for (uint8_t rowFat = 0; rowFat < scale; rowFat++) { 486 | isMarginAdded = false; 487 | marginCounter = 0; 488 | 489 | for (uint16_t column = 0; column < width; column++) { 490 | if (center && !isMarginAdded && marginCounter == marginWidth) { 491 | isMarginAdded = true; 492 | column = 0; 493 | } 494 | if (center && !isMarginAdded) { 495 | column = 0; 496 | dot = 0; 497 | marginCounter++; 498 | } else { 499 | dot = bitRead(bitmap[(row * width + column) / 8], 7 - (row * width + column) % 8); 500 | } 501 | 502 | for (uint8_t columnFat = 0; columnFat < scale; columnFat++) { 503 | if (center && !isMarginAdded) columnFat = scale; 504 | byteToSend |= dot << offset; 505 | currentDotNr++; 506 | if (!dtrEnabled && dot) burned++; 507 | if (currentDotNr == printedWidth) { // end of line 508 | offset = 0; 509 | currentDotNr = 0; 510 | } 511 | if (offset == 0) { 512 | if (bufferFillLevel == 0) { 513 | if (rowsInPackage > totalRowsToSend) rowsInPackage = totalRowsToSend; 514 | initBitmapData(rowsInPackage, bytesPerRow); 515 | } 516 | 517 | sendBitmapByte(byteToSend); 518 | offset = 7; 519 | byteToSend = 0; 520 | bufferFillLevel++; 521 | 522 | if (bufferFillLevel == bufferSize) { 523 | setDelayBitmap(printedWidth, rowsInPackage, burned); 524 | totalRowsToSend -= rowsInPackage; 525 | bufferFillLevel = 0; 526 | burned = 0; 527 | } 528 | } else { 529 | offset--; 530 | } 531 | } 532 | } 533 | } 534 | } 535 | } 536 | --------------------------------------------------------------------------------