├── .idea
├── .name
├── .gitignore
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── compiler.xml
├── vcs.xml
├── misc.xml
├── gradle.xml
└── jarRepositories.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── logo.png
│ │ │ │ ├── logo2.png
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── themes.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── khairo
│ │ │ └── printer
│ │ │ ├── utils
│ │ │ └── Extensions.kt
│ │ │ └── ui
│ │ │ └── MainActivity.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── khairo
│ │ │ └── printer
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── khairo
│ │ └── printer
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── escposprinter
├── consumer-rules.pro
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── khairo
│ │ │ │ ├── async
│ │ │ │ ├── AsyncTcpEscPosPrint.kt
│ │ │ │ ├── AsyncUsbEscPosPrint.kt
│ │ │ │ ├── AsyncEscPosPrinter.kt
│ │ │ │ ├── AsyncBluetoothEscPosPrint.kt
│ │ │ │ └── AsyncEscPosPrint.kt
│ │ │ │ ├── escposprinter
│ │ │ │ ├── exceptions
│ │ │ │ │ ├── EscPosParserException.kt
│ │ │ │ │ ├── EscPosBarcodeException.kt
│ │ │ │ │ ├── EscPosEncodingException.kt
│ │ │ │ │ └── EscPosConnectionException.kt
│ │ │ │ ├── EscPosCharsetEncoding.kt
│ │ │ │ ├── textparser
│ │ │ │ │ ├── IPrinterTextParserElement.kt
│ │ │ │ │ ├── CoroutinesIPrinterTextParserElement.kt
│ │ │ │ │ ├── PrinterTextParserQRCode.kt
│ │ │ │ │ ├── CoroutinesPrinterTextParserQRCode.kt
│ │ │ │ │ ├── PrinterTextParserTag.kt
│ │ │ │ │ ├── PrinterTextParserLine.kt
│ │ │ │ │ ├── PrinterTextParserString.kt
│ │ │ │ │ ├── CoroutinesPrinterTextParserLine.kt
│ │ │ │ │ ├── CoroutinesPrinterTextParserString.kt
│ │ │ │ │ ├── PrinterTextParserBarcode.kt
│ │ │ │ │ ├── CoroutinesPrinterTextParserBarcode.kt
│ │ │ │ │ ├── PrinterTextParserImg.java
│ │ │ │ │ ├── CoroutinesPrinterTextParserImg.kt
│ │ │ │ │ ├── PrinterTextParser.kt
│ │ │ │ │ ├── CoroutinesPrinterTextParser.kt
│ │ │ │ │ └── PrinterTextParserColumn.kt
│ │ │ │ ├── barcode
│ │ │ │ │ ├── BarcodeEAN8.kt
│ │ │ │ │ ├── BarcodeUPCA.kt
│ │ │ │ │ ├── BarcodeEAN13.kt
│ │ │ │ │ ├── Barcode128.kt
│ │ │ │ │ ├── BarcodeUPCE.kt
│ │ │ │ │ ├── Barcode.kt
│ │ │ │ │ └── BarcodeNumber.kt
│ │ │ │ ├── connection
│ │ │ │ │ ├── usb
│ │ │ │ │ │ ├── UsbConnections.kt
│ │ │ │ │ │ ├── UsbDeviceHelper.kt
│ │ │ │ │ │ ├── UsbPrintersConnections.kt
│ │ │ │ │ │ ├── UsbConnection.kt
│ │ │ │ │ │ └── UsbOutputStream.kt
│ │ │ │ │ ├── bluetooth
│ │ │ │ │ │ ├── BluetoothConnections.kt
│ │ │ │ │ │ ├── BluetoothPrintersConnections.kt
│ │ │ │ │ │ └── BluetoothConnection.kt
│ │ │ │ │ ├── DeviceConnection.kt
│ │ │ │ │ └── tcp
│ │ │ │ │ │ ├── TcpConnection.kt
│ │ │ │ │ │ └── TcpDeviceConnection.kt
│ │ │ │ ├── EscPosPrinterSize.kt
│ │ │ │ ├── CoroutinesEscPosPrinter.kt
│ │ │ │ └── EscPosPrinter.java
│ │ │ │ ├── common
│ │ │ │ └── App.kt
│ │ │ │ ├── coroutines
│ │ │ │ ├── CoroutinesEscPosPrinter.kt
│ │ │ │ └── CoroutinesEscPosPrint.kt
│ │ │ │ └── exeption
│ │ │ │ └── PrintingException.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dantsu
│ │ │ └── escposprinter
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── dantsu
│ │ └── escposprinter
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
├── LICENSE
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | Printer
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/escposprinter/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/escposprinter/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':escposprinter'
2 | include ':app'
3 | rootProject.name = "Printer"
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/drawable/logo.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/drawable/logo2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/escposprinter/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ThermalPrinter ESC POS Bluetooth
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KhairoHumsi/Printer-ktx/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/async/AsyncTcpEscPosPrint.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.async
2 |
3 | import android.content.Context
4 |
5 | class AsyncTcpEscPosPrint(context: Context) : AsyncEscPosPrint(context)
6 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/async/AsyncUsbEscPosPrint.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.async
2 |
3 | import android.content.Context
4 |
5 | class AsyncUsbEscPosPrint(context: Context?) : AsyncEscPosPrint(context)
6 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/exceptions/EscPosParserException.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.exceptions
2 |
3 | class EscPosParserException(errorMessage: String?) : Exception(errorMessage)
4 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/exceptions/EscPosBarcodeException.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.exceptions
2 |
3 | class EscPosBarcodeException(errorMessage: String?) : Exception(errorMessage)
4 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/exceptions/EscPosEncodingException.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.exceptions
2 |
3 | class EscPosEncodingException(errorMessage: String?) : Exception(errorMessage)
4 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/exceptions/EscPosConnectionException.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.exceptions
2 |
3 | class EscPosConnectionException(errorMessage: String?) : Exception(errorMessage)
4 |
5 |
6 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/EscPosCharsetEncoding.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter
2 |
3 | class EscPosCharsetEncoding(val name: String, escPosCharsetId: Int) {
4 | val command: ByteArray = byteArrayOf(0x1B, 0x74, escPosCharsetId.toByte())
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Dec 17 14:55:25 EET 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/common/App.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.common
2 |
3 | import android.app.Application
4 |
5 | class App: Application() {
6 | override fun onCreate() {
7 | super.onCreate()
8 |
9 | instance = this
10 | }
11 |
12 | companion object {
13 | lateinit var instance: App
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/escposprinter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/test/java/com/khairo/printer/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.printer
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/IPrinterTextParserElement.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
5 |
6 | interface IPrinterTextParserElement {
7 | @Throws(EscPosEncodingException::class)
8 | fun length(): Int
9 |
10 | @Throws(EscPosEncodingException::class)
11 | fun print(printerSocket: EscPosPrinterCommands?): IPrinterTextParserElement?
12 | }
13 |
--------------------------------------------------------------------------------
/escposprinter/src/test/java/com/dantsu/escposprinter/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Printer
3 | Click to print !
4 | Print by bluetooth !
5 | Print by USB !
6 | IP :
7 | 192.168.1.160
8 | Port :
9 | 9100
10 | Print by TCP !
11 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesIPrinterTextParserElement.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.CoroutinesEscPosPrinterCommands
4 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
5 |
6 | interface CoroutinesIPrinterTextParserElement {
7 | @Throws(EscPosEncodingException::class)
8 | fun length(): Int
9 |
10 | @Throws(EscPosEncodingException::class)
11 | suspend fun print(printerSocket: CoroutinesEscPosPrinterCommands?): CoroutinesIPrinterTextParserElement?
12 | }
13 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/BarcodeEAN8.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterSize
5 |
6 | class BarcodeEAN8(
7 | printerSize: EscPosPrinterSize,
8 | code: String,
9 | widthMM: Float,
10 | heightMM: Float,
11 | textPosition: Int
12 | ) : BarcodeNumber(
13 | printerSize,
14 | EscPosPrinterCommands.BARCODE_TYPE_EAN8,
15 | code,
16 | widthMM,
17 | heightMM,
18 | textPosition
19 | ) {
20 | override fun getCodeLength(): Int = 8
21 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/async/AsyncEscPosPrinter.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.async
2 |
3 | import com.khairo.escposprinter.EscPosPrinterSize
4 | import com.khairo.escposprinter.connection.DeviceConnection
5 |
6 | class AsyncEscPosPrinter(val printerConnection: DeviceConnection, printerDpi: Int, printerWidthMM: Float, printerNbrCharactersPerLine: Int) : EscPosPrinterSize(printerDpi, printerWidthMM, printerNbrCharactersPerLine) {
7 | var textToPrint = ""
8 |
9 | fun setTextToPrint(textToPrint: String): AsyncEscPosPrinter {
10 | this.textToPrint = textToPrint
11 | return this
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/BarcodeUPCA.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterSize
5 |
6 | class BarcodeUPCA(
7 | printerSize: EscPosPrinterSize,
8 | code: String,
9 | widthMM: Float,
10 | heightMM: Float,
11 | textPosition: Int
12 | ) : BarcodeNumber(
13 | printerSize,
14 | EscPosPrinterCommands.BARCODE_TYPE_UPCA,
15 | code,
16 | widthMM,
17 | heightMM,
18 | textPosition
19 | ) {
20 | override fun getCodeLength(): Int {
21 | return 12
22 | }
23 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/BarcodeEAN13.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterSize
5 |
6 | class BarcodeEAN13(
7 | printerSize: EscPosPrinterSize,
8 | code: String,
9 | widthMM: Float,
10 | heightMM: Float,
11 | textPosition: Int
12 | ) : BarcodeNumber(
13 | printerSize,
14 | EscPosPrinterCommands.BARCODE_TYPE_EAN13,
15 | code,
16 | widthMM,
17 | heightMM,
18 | textPosition
19 | ) {
20 | override fun getCodeLength(): Int {
21 | return 13
22 | }
23 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/coroutines/CoroutinesEscPosPrinter.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.coroutines
2 |
3 | import com.khairo.escposprinter.EscPosPrinterSize
4 | import com.khairo.escposprinter.connection.tcp.TcpDeviceConnection
5 |
6 | class CoroutinesEscPosPrinter(
7 | val printerConnection: TcpDeviceConnection,
8 | printerDpi: Int,
9 | printerWidthMM: Float,
10 | printerNbrCharactersPerLine: Int
11 | ) : EscPosPrinterSize(printerDpi, printerWidthMM, printerNbrCharactersPerLine) {
12 | var textToPrint = ""
13 |
14 | fun setTextToPrint(textToPrint: String): CoroutinesEscPosPrinter {
15 | this.textToPrint = textToPrint
16 | return this
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/Barcode128.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterCommands.*
5 | import com.khairo.escposprinter.EscPosPrinterSize
6 |
7 | class Barcode128(
8 | printerSize: EscPosPrinterSize,
9 | code: String,
10 | widthMM: Float,
11 | heightMM: Float,
12 | textPosition: Int
13 | ) : Barcode(
14 | printerSize,
15 | BARCODE_TYPE_128,
16 | code,
17 | widthMM,
18 | heightMM,
19 | textPosition
20 | ) {
21 |
22 | override fun getCodeLength(): Int {
23 | return code.length
24 | }
25 |
26 | override fun getColsCount(): Int {
27 | return (this.getCodeLength() + 5) * 11
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/khairo/printer/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.printer
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.khairo.printer", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/escposprinter/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/async/AsyncBluetoothEscPosPrint.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.async
2 |
3 | import android.content.Context
4 | import com.khairo.escposprinter.connection.bluetooth.BluetoothPrintersConnections
5 |
6 | class AsyncBluetoothEscPosPrint(context: Context?) : AsyncEscPosPrint(context) {
7 | override fun doInBackground(vararg printersData: AsyncEscPosPrinter): Int {
8 | if (printersData.isEmpty()) return FINISH_NO_PRINTER
9 |
10 | var printerData: AsyncEscPosPrinter = printersData[0]
11 |
12 | printerData = AsyncEscPosPrinter(
13 | BluetoothPrintersConnections.selectFirstPaired()!!,
14 | printerData.printerDpi,
15 | printerData.printerWidthMM,
16 | printerData.printerNbrCharactersPerLine
17 | )
18 | printerData.textToPrint = printerData.textToPrint
19 | return super.doInBackground(*printersData)
20 | }
21 | }
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
--------------------------------------------------------------------------------
/escposprinter/src/androidTest/java/com/dantsu/escposprinter/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 | import androidx.test.platform.app.InstrumentationRegistry;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android usbDevice.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("com.khairo.thermalprinter_escpos.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/usb/UsbConnections.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.usb
2 |
3 | import android.content.Context
4 | import android.hardware.usb.UsbDevice
5 | import android.hardware.usb.UsbManager
6 |
7 | open class UsbConnections(context: Context) {
8 | protected var usbManager: UsbManager =
9 | context.getSystemService(Context.USB_SERVICE) as UsbManager
10 |
11 | /**
12 | * Get a list of USB devices available.
13 | *
14 | * @return Return an array of UsbConnection instance
15 | */
16 | open fun getList(): Array? {
17 | val devicesList: Collection = usbManager.deviceList.values
18 | val usbDevices = arrayOfNulls(devicesList.size)
19 | if (devicesList.isNotEmpty()) {
20 | var i = 0
21 | for (device in devicesList) {
22 | usbDevices[i++] = UsbConnection(usbManager, device)
23 | }
24 | }
25 | return usbDevices
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/escposprinter/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Franck ALARY
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 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/bluetooth/BluetoothConnections.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.bluetooth
2 |
3 | import android.bluetooth.BluetoothAdapter
4 |
5 | open class BluetoothConnections {
6 | private var bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
7 |
8 | /**
9 | * Get a list of bluetooth devices available.
10 | *
11 | * @return Return an array of BluetoothConnection instance
12 | */
13 | open fun getList(): Array? {
14 | if (bluetoothAdapter == null) {
15 | return null
16 | }
17 | if (!bluetoothAdapter!!.isEnabled) {
18 | return null
19 | }
20 | val bluetoothDevicesList = bluetoothAdapter!!.bondedDevices
21 | val bluetoothDevices = arrayOfNulls(bluetoothDevicesList.size)
22 | if (bluetoothDevicesList.size > 0) {
23 | var i = 0
24 | for (device in bluetoothDevicesList) {
25 | bluetoothDevices[i++] = BluetoothConnection(device)
26 | }
27 | }
28 | return bluetoothDevices
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/BarcodeUPCE.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterSize
5 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
6 |
7 | class BarcodeUPCE(
8 | printerSize: EscPosPrinterSize,
9 | code: String,
10 | widthMM: Float,
11 | heightMM: Float,
12 | textPosition: Int
13 | ) : Barcode(
14 | printerSize,
15 | EscPosPrinterCommands.BARCODE_TYPE_UPCE,
16 | code,
17 | widthMM,
18 | heightMM,
19 | textPosition
20 | ) {
21 | override fun getCodeLength(): Int = 6
22 |
23 | override fun getColsCount(): Int = this.getCodeLength() * 7 + 16
24 |
25 | @Throws(EscPosBarcodeException::class)
26 | private fun checkCode() {
27 | val codeLength = this.getCodeLength()
28 | if (code.length < codeLength) {
29 | throw EscPosBarcodeException("Code is too short for the barcode type.")
30 | }
31 | try {
32 | code = code.substring(0, codeLength)
33 | for (i in 0 until codeLength) {
34 | code.substring(i, i + 1).toInt(10)
35 | }
36 | } catch (e: NumberFormatException) {
37 | e.printStackTrace()
38 | throw EscPosBarcodeException("Invalid barcode number")
39 | }
40 | }
41 |
42 | init {
43 | checkCode()
44 | }
45 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/coroutines/CoroutinesEscPosPrint.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.coroutines
2 |
3 | import android.content.Context
4 | import com.khairo.escposprinter.EscPosCharsetEncoding
5 | import com.khairo.escposprinter.connection.tcp.TcpDeviceConnection
6 | import com.khairo.exeption.PrintingException.FINISH_NO_PRINTER
7 | import com.khairo.exeption.onException
8 | import java.lang.ref.WeakReference
9 |
10 | class CoroutinesEscPosPrint(
11 | private val context: Context
12 | ) {
13 | private var weakContext: WeakReference = WeakReference(context)
14 |
15 | suspend fun execute(vararg printersData: CoroutinesEscPosPrinter) {
16 | if (printersData.isEmpty())
17 | return onException(context, FINISH_NO_PRINTER)
18 |
19 | val printerData = printersData[0]
20 |
21 | var deviceConnection: TcpDeviceConnection? = printerData.printerConnection
22 | // if (deviceConnection == null)
23 | // deviceConnection = BluetoothPrintersConnections.selectFirstPaired()
24 |
25 | if (deviceConnection == null) return onException(context, FINISH_NO_PRINTER)
26 |
27 | val context = weakContext.get() ?: return
28 | val printer = com.khairo.escposprinter.CoroutinesEscPosPrinter(
29 | deviceConnection,
30 | printerData.printerDpi,
31 | printerData.printerWidthMM,
32 | printerData.printerNbrCharactersPerLine,
33 | EscPosCharsetEncoding("Arabic", 22)
34 | )
35 |
36 | printer.printFormattedTextAndCut(context, printerData.textToPrint)
37 | .apply { disconnectPrinter() }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/Barcode.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterSize
4 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
5 | import kotlin.math.roundToInt
6 |
7 | abstract class Barcode internal constructor(
8 | printerSize: EscPosPrinterSize,
9 | barcodeType: Int,
10 | code: String,
11 | widthMM: Float,
12 | heightMM: Float,
13 | textPosition: Int
14 | ) {
15 | var barcodeType: Int
16 | protected set
17 | var code: String
18 | protected set
19 | var colWidth: Int
20 | protected set
21 | var height: Int
22 | protected set
23 | var textPosition: Int
24 | protected set
25 | abstract fun getCodeLength(): Int
26 | abstract fun getColsCount(): Int
27 |
28 | init {
29 | var widthMM = widthMM
30 | this.barcodeType = barcodeType
31 | this.code = code
32 | height = printerSize.mmToPx(heightMM)
33 | this.textPosition = textPosition
34 | if (widthMM == 0f) {
35 | widthMM = printerSize.printerWidthMM * 0.7f
36 | }
37 | val wantedPxWidth =
38 | if (widthMM > printerSize.printerWidthMM) printerSize.printerWidthPx else printerSize.mmToPx(
39 | widthMM
40 | )
41 | var colWidth = (wantedPxWidth.toDouble() / getColsCount().toDouble()).roundToInt()
42 | if (colWidth * getColsCount() > printerSize.printerWidthPx) {
43 | --colWidth
44 | }
45 | if (colWidth == 0) {
46 | throw EscPosBarcodeException("Barcode is too long for the paper size.")
47 | }
48 | this.colWidth = colWidth
49 | }
50 | }
--------------------------------------------------------------------------------
/escposprinter/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 30
6 |
7 | defaultConfig {
8 | minSdkVersion 16
9 | targetSdkVersion 30
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles 'consumer-rules.pro'
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(dir: 'libs', include: ['*.jar'])
28 | implementation 'androidx.appcompat:appcompat:1.2.0'
29 | testImplementation 'junit:junit:4.13.1'
30 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
32 | implementation 'com.google.zxing:core:3.4.0'
33 | implementation "androidx.core:core-ktx:1.3.2"
34 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
35 |
36 | //coroutines
37 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
38 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines"
39 |
40 | //lifecycle
41 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
42 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
43 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
44 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
45 | }
46 | repositories {
47 | mavenCentral()
48 | }
49 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/usb/UsbDeviceHelper.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.usb
2 |
3 | import android.hardware.usb.UsbConstants
4 | import android.hardware.usb.UsbDevice
5 | import android.hardware.usb.UsbEndpoint
6 | import android.hardware.usb.UsbInterface
7 |
8 | object UsbDeviceHelper {
9 | /**
10 | * Find the correct USB interface for printing
11 | *
12 | * @param usbDevice USB device
13 | * @return correct USB interface for printing, null if not found
14 | */
15 | fun findPrinterInterface(usbDevice: UsbDevice?): UsbInterface? {
16 | if (usbDevice == null) {
17 | return null
18 | }
19 | val interfacesCount = usbDevice.interfaceCount
20 | for (i in 0 until interfacesCount) {
21 | val usbInterface = usbDevice.getInterface(i)
22 | if (usbInterface.interfaceClass == UsbConstants.USB_CLASS_PRINTER) {
23 | return usbInterface
24 | }
25 | }
26 | return usbDevice.getInterface(0)
27 | }
28 |
29 | /**
30 | * Find the USB endpoint for device input
31 | *
32 | * @param usbInterface USB interface
33 | * @return Input endpoint or null if not found
34 | */
35 | fun findEndpointIn(usbInterface: UsbInterface?): UsbEndpoint? {
36 | if (usbInterface != null) {
37 | val endpointsCount = usbInterface.endpointCount
38 | for (i in 0 until endpointsCount) {
39 | val endpoint = usbInterface.getEndpoint(i)
40 | if (endpoint.type == UsbConstants.USB_ENDPOINT_XFER_BULK && endpoint.direction == UsbConstants.USB_DIR_OUT) {
41 | return endpoint
42 | }
43 | }
44 | }
45 | return null
46 | }
47 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/barcode/BarcodeNumber.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.barcode
2 |
3 | import com.khairo.escposprinter.EscPosPrinterSize
4 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
5 |
6 | abstract class BarcodeNumber(
7 | printerSize: EscPosPrinterSize,
8 | barcodeType: Int,
9 | code: String,
10 | widthMM: Float,
11 | heightMM: Float,
12 | textPosition: Int
13 | ) : Barcode(printerSize, barcodeType, code, widthMM, heightMM, textPosition) {
14 | override fun getColsCount(): Int {
15 | return this.getCodeLength() * 7 + 11
16 | }
17 |
18 | @Throws(EscPosBarcodeException::class)
19 | private fun checkCode() {
20 | val codeLength = this.getCodeLength() - 1
21 | if (code.length < codeLength) {
22 | throw EscPosBarcodeException("Code is too short for the barcode type.")
23 | }
24 | try {
25 | val code = code.substring(0, codeLength)
26 | var totalBarcodeKey = 0
27 | for (i in 0 until codeLength) {
28 | val pos = codeLength - 1 - i
29 | var intCode = code.substring(pos, pos + 1).toInt(10)
30 | if (i % 2 == 0) {
31 | intCode = 3 * intCode
32 | }
33 | totalBarcodeKey += intCode
34 | }
35 | var barcodeKey = (10 - totalBarcodeKey % 10).toString()
36 | if (barcodeKey.length == 2) {
37 | barcodeKey = "0"
38 | }
39 | this.code = code + barcodeKey
40 | } catch (e: NumberFormatException) {
41 | e.printStackTrace()
42 | throw EscPosBarcodeException("Invalid barcode number")
43 | }
44 | }
45 |
46 | init {
47 | checkCode()
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/usb/UsbPrintersConnections.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.usb
2 |
3 | import android.content.Context
4 | import android.hardware.usb.UsbConstants
5 |
6 | class UsbPrintersConnections
7 | /**
8 | * Create a new instance of UsbPrintersConnections
9 | *
10 | * @param context Application context
11 | */
12 | (context: Context) : UsbConnections(context) {
13 |
14 | override fun getList(): Array {
15 | val usbConnections = super.getList()
16 | var i = 0
17 | val printersTmp = arrayOfNulls(usbConnections!!.size)
18 | for (usbConnection in usbConnections) {
19 | val device = usbConnection!!.device
20 | var usbClass = device.deviceClass
21 | if (usbClass == UsbConstants.USB_CLASS_PER_INTERFACE && UsbDeviceHelper.findPrinterInterface(
22 | device
23 | ) != null
24 | ) {
25 | usbClass = UsbConstants.USB_CLASS_PRINTER
26 | }
27 | if (usbClass == UsbConstants.USB_CLASS_PRINTER) {
28 | printersTmp[i++] = UsbConnection(usbManager, device)
29 | }
30 | }
31 | val usbPrinters = arrayOfNulls(i)
32 | System.arraycopy(printersTmp, 0, usbPrinters, 0, i)
33 | return usbPrinters
34 | }
35 |
36 | companion object {
37 | /**
38 | * Easy way to get the first USB printer paired / connected.
39 | *
40 | * @return a UsbConnection instance
41 | */
42 | fun selectFirstConnected(context: Context): UsbConnection? {
43 | val printers = UsbPrintersConnections(context)
44 | val bluetoothPrinters = printers.getList()
45 | return if (bluetoothPrinters.isEmpty()) {
46 | null
47 | } else bluetoothPrinters[0]
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserQRCode.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 |
4 | import com.khairo.escposprinter.EscPosPrinterCommands
5 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
6 | import com.khairo.escposprinter.exceptions.EscPosParserException
7 | import java.util.*
8 |
9 | class PrinterTextParserQRCode(
10 | printerTextParserColumn: PrinterTextParserColumn, textAlign: String?,
11 | qrCodeAttributes: Hashtable, data: String
12 | ) : PrinterTextParserImg(
13 | printerTextParserColumn,
14 | textAlign,
15 | initConstructor(printerTextParserColumn, qrCodeAttributes, data)
16 | ) {
17 | companion object {
18 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
19 | private fun initConstructor(
20 | printerTextParserColumn: PrinterTextParserColumn,
21 | qrCodeAttributes: Hashtable,
22 | oldData: String
23 | ): ByteArray {
24 | var data = oldData
25 | val printer = printerTextParserColumn.line.textParser.printer
26 | data = data.trim { it <= ' ' }
27 | var size = printer.mmToPx(20f)
28 | if (qrCodeAttributes.containsKey(PrinterTextParser.ATTR_QRCODE_SIZE)) {
29 | val qrCodeAttribute = qrCodeAttributes[PrinterTextParser.ATTR_QRCODE_SIZE]
30 | ?: throw EscPosParserException("Invalid QR code attribute : " + PrinterTextParser.ATTR_QRCODE_SIZE)
31 | size = try {
32 | printer.mmToPx(qrCodeAttribute.toFloat())
33 | } catch (nfe: NumberFormatException) {
34 | throw EscPosParserException("Invalid QR code " + PrinterTextParser.ATTR_QRCODE_SIZE + " value")
35 | }
36 | }
37 | return EscPosPrinterCommands.QRCodeDataToBytes(data, size)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParserQRCode.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
5 | import com.khairo.escposprinter.exceptions.EscPosParserException
6 | import java.util.*
7 |
8 | class CoroutinesPrinterTextParserQRCode(
9 | printerTextParserColumn: CoroutinesPrinterTextParserColumn, textAlign: String?,
10 | qrCodeAttributes: Hashtable, data: String
11 | ) : CoroutinesPrinterTextParserImg(
12 | printerTextParserColumn,
13 | textAlign,
14 | initConstructor(printerTextParserColumn, qrCodeAttributes, data)
15 | ) {
16 | companion object {
17 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
18 | private fun initConstructor(
19 | printerTextParserColumn: CoroutinesPrinterTextParserColumn,
20 | qrCodeAttributes: Hashtable,
21 | oldData: String
22 | ): ByteArray {
23 | var data = oldData
24 | val printer = printerTextParserColumn.line.textParser.printer
25 | data = data.trim { it <= ' ' }
26 | var size = printer.mmToPx(20f)
27 | if (qrCodeAttributes.containsKey(PrinterTextParser.ATTR_QRCODE_SIZE)) {
28 | val qrCodeAttribute = qrCodeAttributes[PrinterTextParser.ATTR_QRCODE_SIZE]
29 | ?: throw EscPosParserException("Invalid QR code attribute : " + PrinterTextParser.ATTR_QRCODE_SIZE)
30 | size = try {
31 | printer.mmToPx(qrCodeAttribute.toFloat())
32 | } catch (nfe: NumberFormatException) {
33 | throw EscPosParserException("Invalid QR code " + PrinterTextParser.ATTR_QRCODE_SIZE + " value")
34 | }
35 | }
36 | return EscPosPrinterCommands.QRCodeDataToBytes(data, size)
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserTag.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import java.util.*
4 |
5 | class PrinterTextParserTag(oldTag: String) {
6 | var tagName = ""
7 | val attributes = Hashtable()
8 | var length = 0
9 | var isCloseTag = false
10 | fun getAttribute(key: String): String? = attributes[key]
11 |
12 | fun hasAttribute(key: String): Boolean = attributes.containsKey(key)
13 |
14 | init {
15 | var tag = oldTag
16 | tag = tag.trim { it <= ' ' }
17 | // if (!tag.startsWith("<") || !tag.endsWith(">")) {
18 | // return
19 | // }
20 | length = tag.length
21 | val openTagIndex = tag.indexOf("<")
22 | val closeTagIndex = tag.indexOf(">")
23 | val nextSpaceIndex = tag.indexOf(" ")
24 | if (nextSpaceIndex != -1 && nextSpaceIndex < closeTagIndex) {
25 | tagName = tag.substring(openTagIndex + 1, nextSpaceIndex).toLowerCase(Locale.ROOT)
26 | var attributesString = tag.substring(nextSpaceIndex, closeTagIndex).trim { it <= ' ' }
27 | while (attributesString.contains("='")) {
28 | val egalPos = attributesString.indexOf("='")
29 | val endPos = attributesString.indexOf("'", egalPos + 2)
30 | val attributeName = attributesString.substring(0, egalPos)
31 | val attributeValue = attributesString.substring(egalPos + 2, endPos)
32 | if (attributeName != "") {
33 | attributes[attributeName] = attributeValue
34 | }
35 | attributesString = attributesString.substring(endPos + 1).trim { it <= ' ' }
36 | }
37 |
38 | } else tagName = tag.substring(openTagIndex + 1, closeTagIndex).toLowerCase(Locale.ROOT)
39 |
40 | if (tagName.startsWith("/")) {
41 | tagName = tagName.substring(1)
42 | isCloseTag = true
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserLine.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import java.util.*
4 | import java.util.regex.Pattern
5 | import kotlin.math.floor
6 |
7 | class PrinterTextParserLine(val textParser: PrinterTextParser, textLine: String) {
8 | val nbrColumns: Int
9 | var nbrCharColumn: Int
10 | private set
11 | var nbrCharForgetted: Int
12 | private set
13 | var nbrCharColumnExceeded: Int
14 | private set
15 | val columns: Array
16 | fun setNbrCharColumn(newValue: Int): PrinterTextParserLine {
17 | nbrCharColumn = newValue
18 | return this
19 | }
20 |
21 | fun setNbrCharForgetted(newValue: Int): PrinterTextParserLine {
22 | nbrCharForgetted = newValue
23 | return this
24 | }
25 |
26 | fun setNbrCharColumnExceeded(newValue: Int): PrinterTextParserLine {
27 | nbrCharColumnExceeded = newValue
28 | return this
29 | }
30 |
31 | init {
32 | val nbrCharactersPerLine = textParser.printer.printerNbrCharactersPerLine
33 | val pattern = Pattern.compile(PrinterTextParser.regexAlignTags)
34 | val matcher = pattern.matcher(textLine)
35 | val columnsList = ArrayList()
36 | var lastPosition = 0
37 | while (matcher.find()) {
38 | val startPosition = matcher.start()
39 | if (startPosition > 0) {
40 | columnsList.add(textLine.substring(lastPosition, startPosition))
41 | }
42 | lastPosition = startPosition
43 | }
44 | columnsList.add(textLine.substring(lastPosition))
45 | nbrColumns = columnsList.size
46 | nbrCharColumn =
47 | floor((nbrCharactersPerLine.toFloat() / nbrColumns.toFloat()).toDouble())
48 | .toInt()
49 | nbrCharForgetted = nbrCharactersPerLine - nbrCharColumn * nbrColumns
50 | nbrCharColumnExceeded = 0
51 | columns = arrayOfNulls(nbrColumns)
52 | var i = 0
53 | for (column in columnsList) {
54 | columns[i++] = PrinterTextParserColumn(this, column)
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserString.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinter
4 | import com.khairo.escposprinter.EscPosPrinterCommands
5 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
6 | import java.io.UnsupportedEncodingException
7 | import java.util.*
8 |
9 | class PrinterTextParserString(
10 | printerTextParserColumn: PrinterTextParserColumn,
11 | var text: String,
12 | var textSize: ByteArray,
13 | var textColor: ByteArray,
14 | private var textReverseColor: ByteArray,
15 | private var textBold: ByteArray,
16 | private var textUnderline: ByteArray,
17 | private var textDoubleStrike: ByteArray
18 | ) : IPrinterTextParserElement {
19 | private val printer: EscPosPrinter = printerTextParserColumn.line.textParser.printer
20 |
21 | @Throws(EscPosEncodingException::class)
22 | override fun length(): Int {
23 | val charsetEncoding = printer.encoding
24 | val coef = if (Arrays.equals(
25 | textSize,
26 | EscPosPrinterCommands.TEXT_SIZE_DOUBLE_WIDTH
27 | ) || Arrays.equals(
28 | textSize, EscPosPrinterCommands.TEXT_SIZE_BIG
29 | )
30 | ) 2 else 1
31 | return if (charsetEncoding != null) {
32 | try {
33 | text.toByteArray(charset(charsetEncoding.name)).size * coef
34 | } catch (e: UnsupportedEncodingException) {
35 | throw EscPosEncodingException(e.message)
36 | }
37 | } else text.length * coef
38 | }
39 |
40 | /**
41 | * Print text
42 | *
43 | * @param printerSocket Instance of EscPosPrinterCommands
44 | * @return this Fluent method
45 | */
46 | @Throws(EscPosEncodingException::class)
47 | override fun print(printerSocket: EscPosPrinterCommands?): PrinterTextParserString {
48 | printerSocket!!.printText(
49 | text,
50 | textSize,
51 | textColor,
52 | textReverseColor,
53 | textBold,
54 | textUnderline,
55 | textDoubleStrike
56 | )
57 | return this
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParserLine.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import java.util.*
4 | import java.util.regex.Pattern
5 | import kotlin.math.floor
6 |
7 | class CoroutinesPrinterTextParserLine(val textParser: CoroutinesPrinterTextParser, textLine: String) {
8 | val nbrColumns: Int
9 | var nbrCharColumn: Int
10 | private set
11 | var nbrCharForgetted: Int
12 | private set
13 | var nbrCharColumnExceeded: Int
14 | private set
15 | val columns: Array
16 | fun setNbrCharColumn(newValue: Int): CoroutinesPrinterTextParserLine {
17 | nbrCharColumn = newValue
18 | return this
19 | }
20 |
21 | fun setNbrCharForgetted(newValue: Int): CoroutinesPrinterTextParserLine {
22 | nbrCharForgetted = newValue
23 | return this
24 | }
25 |
26 | fun setNbrCharColumnExceeded(newValue: Int): CoroutinesPrinterTextParserLine {
27 | nbrCharColumnExceeded = newValue
28 | return this
29 | }
30 |
31 | init {
32 | val nbrCharactersPerLine = textParser.printer.printerNbrCharactersPerLine
33 | val pattern = Pattern.compile(PrinterTextParser.regexAlignTags)
34 | val matcher = pattern.matcher(textLine)
35 | val columnsList = ArrayList()
36 | var lastPosition = 0
37 | while (matcher.find()) {
38 | val startPosition = matcher.start()
39 | if (startPosition > 0) {
40 | columnsList.add(textLine.substring(lastPosition, startPosition))
41 | }
42 | lastPosition = startPosition
43 | }
44 | columnsList.add(textLine.substring(lastPosition))
45 | nbrColumns = columnsList.size
46 | nbrCharColumn =
47 | floor((nbrCharactersPerLine.toFloat() / nbrColumns.toFloat()).toDouble())
48 | .toInt()
49 | nbrCharForgetted = nbrCharactersPerLine - nbrCharColumn * nbrColumns
50 | nbrCharColumnExceeded = 0
51 | columns = arrayOfNulls(nbrColumns)
52 | var i = 0
53 | for (column in columnsList) {
54 | columns[i++] = CoroutinesPrinterTextParserColumn(this, column)
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/bluetooth/BluetoothPrintersConnections.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.bluetooth
2 |
3 | import android.annotation.SuppressLint
4 | import android.bluetooth.BluetoothClass
5 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
6 |
7 | class BluetoothPrintersConnections : BluetoothConnections() {
8 | /**
9 | * Get a list of bluetooth printers.
10 | *
11 | * @return an array of EscPosPrinterCommands
12 | */
13 | @SuppressLint("MissingPermission")
14 | override fun getList(): Array {
15 | val bluetoothDevicesList = super.getList()
16 | var i = 0
17 | val printersTmp = arrayOfNulls(bluetoothDevicesList!!.size)
18 | for (bluetoothConnection in bluetoothDevicesList) {
19 | val device = bluetoothConnection!!.device
20 | val majDeviceCl = device!!.bluetoothClass.majorDeviceClass
21 | val deviceCl = device.bluetoothClass.deviceClass
22 | if (majDeviceCl == BluetoothClass.Device.Major.IMAGING && (deviceCl == 1664 || deviceCl == BluetoothClass.Device.Major.IMAGING)) {
23 | printersTmp[i++] = BluetoothConnection(device)
24 | }
25 | }
26 | val bluetoothPrinters = arrayOfNulls(i)
27 | System.arraycopy(printersTmp, 0, bluetoothPrinters, 0, i)
28 | return bluetoothPrinters
29 | }
30 |
31 | companion object {
32 | /**
33 | * Easy way to get the first bluetooth printer paired / connected.
34 | *
35 | * @return a EscPosPrinterCommands instance
36 | */
37 | fun selectFirstPaired(): BluetoothConnection? {
38 | val printers = BluetoothPrintersConnections()
39 | val bluetoothPrinters = printers.getList()
40 | if (bluetoothPrinters.isNotEmpty()) {
41 | for (printer in bluetoothPrinters) {
42 | try {
43 | return printer!!.connect()
44 | } catch (e: EscPosConnectionException) {
45 | e.printStackTrace()
46 | }
47 | }
48 | }
49 | return null
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | android {
8 | compileSdkVersion 30
9 | buildToolsVersion "30.0.1"
10 |
11 | defaultConfig {
12 | applicationId "com.khairo.printer"
13 | minSdkVersion 21
14 | targetSdkVersion 30
15 | versionCode 1
16 | versionName "1.0"
17 |
18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19 | }
20 |
21 | buildTypes {
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
25 | }
26 | }
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 | kotlinOptions {
32 | jvmTarget = '1.8'
33 | }
34 |
35 | buildFeatures {
36 | dataBinding = true
37 | viewBinding true
38 | }
39 | }
40 |
41 | dependencies {
42 |
43 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
44 | implementation 'androidx.core:core-ktx:1.3.2'
45 | implementation 'androidx.appcompat:appcompat:1.2.0'
46 |
47 | //material
48 | implementation 'com.google.android.material:material:1.2.1'
49 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
50 |
51 | //testing unit
52 | testImplementation 'junit:junit:4.13.1'
53 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
54 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
55 |
56 | //databinding
57 | kapt "com.android.databinding:compiler:3.2.1"
58 |
59 | //coroutines
60 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
61 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines"
62 |
63 | //lifecycle
64 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
65 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
66 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
67 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
68 |
69 | //Thermal Printer
70 | implementation project(path: ':escposprinter')
71 | }
72 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/DeviceConnection.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection
2 |
3 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
4 | import java.io.IOException
5 | import java.io.OutputStream
6 | import kotlin.math.floor
7 |
8 | abstract class DeviceConnection {
9 | @JvmField
10 | protected var stream: OutputStream? = null
11 |
12 | @JvmField
13 | protected var data: ByteArray
14 |
15 | @Throws(EscPosConnectionException::class)
16 | abstract fun connect(): DeviceConnection?
17 | abstract fun disconnect(): DeviceConnection?
18 |
19 | /**
20 | * Check if OutputStream is open.
21 | *
22 | * @return true if is connected
23 | */
24 | // open val isConnected: Boolean
25 | // get() = stream != null
26 | open fun isConnected(): Boolean = this.stream != null
27 |
28 | /**
29 | * Add data to send.
30 | */
31 | fun write(bytes: ByteArray) {
32 | val data = ByteArray(bytes.size + data.size)
33 | System.arraycopy(this.data, 0, data, 0, this.data.size)
34 | System.arraycopy(bytes, 0, data, this.data.size, bytes.size)
35 | this.data = data
36 | }
37 |
38 | /**
39 | * Send data to the device.
40 | */
41 | @Throws(EscPosConnectionException::class)
42 | open fun send() {
43 | this.send(0)
44 | }
45 |
46 | /**
47 | * Send data to the device.
48 | */
49 | @Throws(EscPosConnectionException::class)
50 | open fun send(addWaitingTime: Int) {
51 | if (!isConnected()) {
52 | throw EscPosConnectionException("Unable to send data to device.")
53 | }
54 | try {
55 | stream!!.write(data)
56 | stream!!.flush()
57 | data = ByteArray(0)
58 | val waitingTime = addWaitingTime + floor((data.size / 16f).toDouble())
59 | .toInt()
60 | if (waitingTime > 0) {
61 | Thread.sleep(waitingTime.toLong())
62 | }
63 | } catch (e: IOException) {
64 | e.printStackTrace()
65 | throw EscPosConnectionException(e.message)
66 | } catch (e: InterruptedException) {
67 | e.printStackTrace()
68 | throw EscPosConnectionException(e.message)
69 | }
70 | }
71 |
72 | init {
73 | data = ByteArray(0)
74 | }
75 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParserString.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.CoroutinesEscPosPrinter
4 | import com.khairo.escposprinter.CoroutinesEscPosPrinterCommands
5 | import com.khairo.escposprinter.EscPosPrinter
6 | import com.khairo.escposprinter.EscPosPrinterCommands
7 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
8 | import java.io.UnsupportedEncodingException
9 | import java.util.*
10 |
11 | class CoroutinesPrinterTextParserString(
12 | printerTextParserColumn: CoroutinesPrinterTextParserColumn,
13 | var text: String,
14 | var textSize: ByteArray,
15 | var textColor: ByteArray,
16 | private var textReverseColor: ByteArray,
17 | private var textBold: ByteArray,
18 | private var textUnderline: ByteArray,
19 | private var textDoubleStrike: ByteArray
20 | ) : CoroutinesIPrinterTextParserElement {
21 | private val printer: CoroutinesEscPosPrinter = printerTextParserColumn.line.textParser.printer
22 |
23 | @Throws(EscPosEncodingException::class)
24 | override fun length(): Int {
25 | val charsetEncoding = printer.encoding
26 | val coef = if (Arrays.equals(
27 | textSize,
28 | EscPosPrinterCommands.TEXT_SIZE_DOUBLE_WIDTH
29 | ) || Arrays.equals(
30 | textSize, EscPosPrinterCommands.TEXT_SIZE_BIG
31 | )
32 | ) 2 else 1
33 | return if (charsetEncoding != null) {
34 | try {
35 | text.toByteArray(charset(charsetEncoding.name)).size * coef
36 | } catch (e: UnsupportedEncodingException) {
37 | throw EscPosEncodingException(e.message)
38 | }
39 | } else text.length * coef
40 | }
41 |
42 | /**
43 | * Print text
44 | *
45 | * @param printerSocket Instance of EscPosPrinterCommands
46 | * @return this Fluent method
47 | */
48 | @Throws(EscPosEncodingException::class)
49 | override suspend fun print(printerSocket: CoroutinesEscPosPrinterCommands?): CoroutinesPrinterTextParserString {
50 | printerSocket!!.printText(
51 | text,
52 | textSize,
53 | textColor,
54 | textReverseColor,
55 | textBold,
56 | textUnderline,
57 | textDoubleStrike
58 | )
59 | return this
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/tcp/TcpConnection.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.tcp
2 |
3 | import android.content.Context
4 | import com.khairo.exeption.PrintingException.FINISH_PRINTER_DISCONNECTED
5 | import com.khairo.exeption.onException
6 | import java.io.IOException
7 | import java.net.InetAddress
8 | import java.net.InetSocketAddress
9 | import java.net.Socket
10 |
11 | /**
12 | * Create un instance of TcpConnection.
13 | *
14 | * @param address IP address of the device
15 | * @param port Port of the device
16 | */
17 | class TcpConnection(private val address: String, private val port: Int) : TcpDeviceConnection() {
18 | private var socket: Socket? = null
19 |
20 | /**
21 | * Check if the TCP device is connected by socket.
22 | *
23 | * @return true if is connected
24 | */
25 |
26 | override fun isConnected(): Boolean =
27 | socket != null && socket!!.isConnected && super.isConnected()
28 |
29 | /**
30 | * Start socket connection with the TCP device.
31 | */
32 | override suspend fun connect(context: Context): TcpConnection {
33 | if (this.isConnected()) return this
34 |
35 | try {
36 | socket = Socket()
37 | socket!!.connect(InetSocketAddress(InetAddress.getByName(address), port))
38 | stream = socket!!.getOutputStream()
39 | data = ByteArray(0)
40 |
41 | } catch (e: IOException) {
42 | e.printStackTrace()
43 | socket = null
44 | stream = null
45 | onException(context, FINISH_PRINTER_DISCONNECTED)
46 | // throw EscPosConnectionException("Unable to connect to TCP device.")
47 | }
48 | return this
49 | }
50 |
51 | /**
52 | * Close the socket connection with the TCP device.
53 | */
54 | override suspend fun disconnect(): TcpConnection {
55 | data = ByteArray(0)
56 | if (stream != null) {
57 | try {
58 | stream!!.close()
59 | stream = null
60 | } catch (e: IOException) {
61 | e.printStackTrace()
62 | }
63 | }
64 | if (socket != null) {
65 | try {
66 | socket!!.close()
67 | socket = null
68 | } catch (e: IOException) {
69 | e.printStackTrace()
70 | }
71 | }
72 | return this
73 | }
74 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/tcp/TcpDeviceConnection.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.tcp
2 |
3 | import android.content.Context
4 | import com.khairo.exeption.PrintingException.FINISH_PRINTER_DISCONNECTED
5 | import com.khairo.exeption.onException
6 | import java.io.IOException
7 | import java.io.OutputStream
8 | import kotlin.math.floor
9 |
10 | abstract class TcpDeviceConnection {
11 | @JvmField
12 | protected var stream: OutputStream? = null
13 |
14 | @JvmField
15 | protected var data: ByteArray
16 |
17 | abstract suspend fun connect(context: Context): TcpDeviceConnection?
18 | abstract suspend fun disconnect(): TcpDeviceConnection?
19 |
20 | /**
21 | * Check if OutputStream is open.
22 | *
23 | * @return true if is connected
24 | */
25 | // open val isConnected: Boolean
26 | // get() = stream != null
27 | open fun isConnected(): Boolean = this.stream != null
28 |
29 | /**
30 | * Add data to send.
31 | */
32 | suspend fun write(bytes: ByteArray) {
33 | val data = ByteArray(bytes.size + data.size)
34 | System.arraycopy(this.data, 0, data, 0, this.data.size)
35 | System.arraycopy(bytes, 0, data, this.data.size, bytes.size)
36 | this.data = data
37 | }
38 |
39 | /**
40 | * Send data to the device.
41 | */
42 | open suspend fun send(context: Context) {
43 | this.send(context, 0)
44 | }
45 |
46 | /**
47 | * Send data to the device.
48 | */
49 | open fun send(context: Context, addWaitingTime: Int) {
50 | if (!isConnected()) {
51 | onException(context, FINISH_PRINTER_DISCONNECTED)
52 | return
53 | }
54 | try {
55 | stream!!.write(data)
56 | stream!!.flush()
57 | data = ByteArray(0)
58 | val waitingTime = addWaitingTime + floor((data.size / 16f).toDouble())
59 | .toInt()
60 | if (waitingTime > 0) {
61 | Thread.sleep(waitingTime.toLong())
62 | }
63 | } catch (e: IOException) {
64 | e.printStackTrace()
65 | onException(context, FINISH_PRINTER_DISCONNECTED)
66 | } catch (e: InterruptedException) {
67 | e.printStackTrace()
68 | onException(context, FINISH_PRINTER_DISCONNECTED)
69 | }
70 | }
71 |
72 | init {
73 | data = ByteArray(0)
74 | }
75 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/usb/UsbConnection.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.usb
2 |
3 | import android.hardware.usb.UsbDevice
4 | import android.hardware.usb.UsbManager
5 | import com.khairo.escposprinter.connection.DeviceConnection
6 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
7 | import java.io.IOException
8 |
9 | class UsbConnection
10 | /**
11 | * Create un instance of UsbConnection.
12 | *
13 | * @param usbManager an instance of UsbManager
14 | * @param device an instance of UsbDevice
15 | */(
16 | private val usbManager: UsbManager,
17 | /**
18 | * Get the instance UsbDevice connected.
19 | *
20 | * @return an instance of UsbDevice
21 | */
22 | val device: UsbDevice
23 | ) : DeviceConnection() {
24 |
25 | /**
26 | * Start socket connection with the usbDevice.
27 | */
28 | @Throws(EscPosConnectionException::class)
29 | override fun connect(): UsbConnection {
30 | if (isConnected()) {
31 | return this
32 | }
33 | try {
34 | stream = UsbOutputStream(usbManager, device)
35 | data = ByteArray(0)
36 | } catch (e: IOException) {
37 | e.printStackTrace()
38 | stream = null
39 | throw EscPosConnectionException("Unable to connect to USB device.")
40 | }
41 | return this
42 | }
43 |
44 | /**
45 | * Close the socket connection with the usbDevice.
46 | */
47 | override fun disconnect(): UsbConnection {
48 | data = ByteArray(0)
49 | if (isConnected()) {
50 | try {
51 | stream!!.close()
52 | } catch (e: IOException) {
53 | e.printStackTrace()
54 | }
55 | stream = null
56 | }
57 | return this
58 | }
59 |
60 | /**
61 | * Send data to the device.
62 | */
63 | @Throws(EscPosConnectionException::class)
64 | override fun send() {
65 | this.send(0)
66 | }
67 |
68 | /**
69 | * Send data to the device.
70 | */
71 | @Throws(EscPosConnectionException::class)
72 | override fun send(addWaitingTime: Int) {
73 | try {
74 | stream!!.write(data)
75 | data = ByteArray(0)
76 | } catch (e: IOException) {
77 | e.printStackTrace()
78 | throw EscPosConnectionException(e.message)
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/usb/UsbOutputStream.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.usb
2 |
3 | import android.hardware.usb.*
4 | import java.io.IOException
5 | import java.io.OutputStream
6 | import java.nio.ByteBuffer
7 |
8 | class UsbOutputStream(usbManager: UsbManager, usbDevice: UsbDevice?) : OutputStream() {
9 | private var usbConnection: UsbDeviceConnection?
10 | private var usbInterface: UsbInterface?
11 | private var usbEndpoint: UsbEndpoint?
12 |
13 | @Throws(IOException::class)
14 | override fun write(i: Int) {
15 | this.write(byteArrayOf(i.toByte()))
16 | }
17 |
18 | @Throws(IOException::class)
19 | override fun write(bytes: ByteArray) {
20 | this.write(bytes, 0, bytes.size)
21 | }
22 |
23 | @Throws(IOException::class)
24 | override fun write(bytes: ByteArray, offset: Int, length: Int) {
25 | if (usbInterface == null || usbEndpoint == null || usbConnection == null) {
26 | throw IOException("Unable to connect to USB device.")
27 | }
28 | if (!usbConnection!!.claimInterface(usbInterface, true)) {
29 | throw IOException("Error during claim USB interface.")
30 | }
31 | val buffer = ByteBuffer.wrap(bytes)
32 | val usbRequest = UsbRequest()
33 | try {
34 | usbRequest.initialize(usbConnection, usbEndpoint)
35 | if (!usbRequest.queue(buffer, bytes.size)) {
36 | throw IOException("Error queueing USB request.")
37 | }
38 | usbConnection!!.requestWait()
39 | } finally {
40 | usbRequest.close()
41 | }
42 | }
43 |
44 | @Throws(IOException::class)
45 | override fun flush() {
46 | }
47 |
48 | @Throws(IOException::class)
49 | override fun close() {
50 | if (usbConnection != null) {
51 | usbConnection!!.close()
52 | usbInterface = null
53 | usbEndpoint = null
54 | usbConnection = null
55 | }
56 | }
57 |
58 | init {
59 | usbInterface = UsbDeviceHelper.findPrinterInterface(usbDevice)
60 | if (usbInterface == null) {
61 | throw IOException("Unable to find USB interface.")
62 | }
63 | usbEndpoint = UsbDeviceHelper.findEndpointIn(usbInterface)
64 | if (usbEndpoint == null) {
65 | throw IOException("Unable to find USB endpoint.")
66 | }
67 | usbConnection = usbManager.openDevice(usbDevice)
68 | if (usbConnection == null) {
69 | throw IOException("Unable to open USB connection.")
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/EscPosPrinterSize.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter
2 |
3 | import android.graphics.Bitmap
4 | import kotlin.math.roundToInt
5 |
6 | open class EscPosPrinterSize constructor(
7 | /**
8 | * Get the printer DPI
9 | *
10 | * @return int
11 | */
12 | var printerDpi: Int,
13 | /**
14 | * Get the printing width in millimeters
15 | *
16 | * @return float
17 | */
18 | var printerWidthMM: Float,
19 | /**
20 | * Get the maximum number of characters that can be printed on a line.
21 | *
22 | * @return int
23 | */
24 | var printerNbrCharactersPerLine: Int
25 | ) {
26 |
27 | /**
28 | * Get the printing width in dot
29 | *
30 | * @return int
31 | */
32 | var printerWidthPx: Int
33 | protected set
34 |
35 | /**
36 | * Get the number of dot that a printed character contain
37 | *
38 | * @return int
39 | */
40 | var printerCharSizeWidthPx: Int
41 | protected set
42 |
43 | /**
44 | * Convert from millimeters to dot the mmSize variable.
45 | *
46 | * @param mmSize Distance in millimeters to be converted
47 | * @return int
48 | */
49 | fun mmToPx(mmSize: Float): Int = (mmSize * printerDpi.toFloat() / INCH_TO_MM).roundToInt()
50 |
51 | /**
52 | * Convert Bitmap object to ESC/POS image.
53 | *
54 | * @param oldBitmap Instance of Bitmap
55 | * @return Bytes contain the image in ESC/POS command
56 | */
57 | fun bitmapToBytes(oldBitmap: Bitmap): ByteArray {
58 | var bitmap = oldBitmap
59 | var isSizeEdit = false
60 | var bitmapWidth = bitmap.width
61 | var bitmapHeight = bitmap.height
62 | val maxWidth = printerWidthPx
63 | val maxHeight = 256
64 | if (bitmapWidth > maxWidth) {
65 | bitmapHeight =
66 | (bitmapHeight.toFloat() * maxWidth.toFloat() / bitmapWidth.toFloat()).roundToInt()
67 | bitmapWidth = maxWidth
68 | isSizeEdit = true
69 | }
70 | if (bitmapHeight > maxHeight) {
71 | bitmapWidth =
72 | (bitmapWidth.toFloat() * maxHeight.toFloat() / bitmapHeight.toFloat()).roundToInt()
73 | bitmapHeight = maxHeight
74 | isSizeEdit = true
75 | }
76 | if (isSizeEdit)
77 | bitmap = Bitmap.createScaledBitmap(bitmap, bitmapWidth, bitmapHeight, false)
78 |
79 | return EscPosPrinterCommands.bitmapToBytes(bitmap)
80 | }
81 |
82 | companion object {
83 | const val INCH_TO_MM = 25.4f
84 | }
85 |
86 | init {
87 | val printingWidthPx = mmToPx(printerWidthMM)
88 | printerWidthPx = printingWidthPx + printingWidthPx % 8
89 | printerCharSizeWidthPx = printingWidthPx / printerNbrCharactersPerLine
90 | }
91 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/connection/bluetooth/BluetoothConnection.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.connection.bluetooth
2 |
3 | import android.annotation.SuppressLint
4 | import android.bluetooth.BluetoothDevice
5 | import android.bluetooth.BluetoothSocket
6 | import com.khairo.escposprinter.connection.DeviceConnection
7 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
8 | import java.io.IOException
9 | import java.util.*
10 |
11 | class BluetoothConnection
12 | /**
13 | * Create un instance of BluetoothConnection.
14 | *
15 | * @param device an instance of BluetoothDevice
16 | */(
17 | /**
18 | * Get the instance BluetoothDevice connected.
19 | *
20 | * @return an instance of BluetoothDevice
21 | */
22 | val device: BluetoothDevice?
23 | ) : DeviceConnection() {
24 | private var socket: BluetoothSocket? = null
25 |
26 | /**
27 | * Check if OutputStream is open.
28 | *
29 | * @return true if is connected
30 | */
31 | override fun isConnected(): Boolean {
32 | return socket != null && socket!!.isConnected && super.isConnected()
33 | }
34 |
35 | /**
36 | * Start socket connection with the bluetooth device.
37 | */
38 | @SuppressLint("MissingPermission")
39 | @Throws(EscPosConnectionException::class)
40 | override fun connect(): BluetoothConnection {
41 | if (isConnected()) {
42 | return this
43 | }
44 | if (device == null) {
45 | throw EscPosConnectionException("Bluetooth device is not connected.")
46 | }
47 | val uuids = device.uuids
48 | val uuid = if (uuids != null && uuids.isNotEmpty()) uuids[0].uuid else UUID.randomUUID()
49 | try {
50 | socket = device.createRfcommSocketToServiceRecord(uuid)
51 | socket!!.connect()
52 | stream = socket!!.outputStream
53 | data = ByteArray(0)
54 | } catch (e: IOException) {
55 | e.printStackTrace()
56 | socket = null
57 | stream = null
58 | throw EscPosConnectionException("Unable to connect to bluetooth device.")
59 | }
60 | return this
61 | }
62 |
63 | /**
64 | * Close the socket connection with the bluetooth device.
65 | */
66 | override fun disconnect(): BluetoothConnection {
67 | data = ByteArray(0)
68 | if (stream != null) {
69 | try {
70 | stream!!.close()
71 | } catch (e: IOException) {
72 | e.printStackTrace()
73 | }
74 | stream = null
75 | }
76 | if (socket != null) {
77 | try {
78 | socket!!.close()
79 | } catch (e: IOException) {
80 | e.printStackTrace()
81 | }
82 | socket = null
83 | }
84 | return this
85 | }
86 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/khairo/printer/utils/Extensions.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.printer.utils
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import com.khairo.coroutines.CoroutinesEscPosPrinter
6 | import com.khairo.escposprinter.textparser.PrinterTextParserImg
7 | import com.khairo.printer.R
8 | import java.text.SimpleDateFormat
9 | import java.util.*
10 |
11 | fun String.replaceNonstandardDigits(): String {
12 | if (this.isEmpty()) {
13 | return this
14 | }
15 | val builder = StringBuilder()
16 | for (element in this) {
17 | if (element.isNonstandardDigit()) {
18 | val numericValue = Character.getNumericValue(element)
19 | if (numericValue >= 0) {
20 | builder.append(numericValue)
21 | }
22 | } else {
23 | builder.append(element)
24 | }
25 | }
26 | return builder.toString()
27 | }
28 |
29 | fun Char.isNonstandardDigit(): Boolean {
30 | return Character.isDigit(this) && this !in '0'..'9'
31 | }
32 |
33 | @SuppressLint("SimpleDateFormat")
34 | fun String.getDateTime(): String = SimpleDateFormat(this).format(Date()).replaceNonstandardDigits()
35 |
36 |
37 | @SuppressLint("UseCompatLoadingForDrawables")
38 | fun Context.printViaWifi(
39 | printer: CoroutinesEscPosPrinter,
40 | orderId: Int,
41 | body: String,
42 | totalBill: Float,
43 | tax: Int,
44 | customer: String = "",
45 | barcode: String
46 | ): CoroutinesEscPosPrinter {
47 |
48 | var test =
49 | "[C]
" + PrinterTextParserImg.bitmapToHexadecimalString(
50 | printer,
51 | getDrawable(R.drawable.logo)
52 | ) + "\n" +
53 | "[L]\n" +
54 | "[C]ORDER N°$orderId\n" +
55 | "[L]\n" +
56 | "[C]${"'on' yyyy-MM-dd 'at' HH:mm:ss".getDateTime()}\n" +
57 | "[C]================================\n" +
58 | "[L]\n" +
59 | "[L] Items[R][R]Qty[R][R]Price\n" +
60 | "[L][R]\n" +
61 | "$body\n" +
62 | "[L][R]\n" +
63 | "[C]--------------------------------\n" +
64 | "[R] TOTAL :[R]${totalBill} $\n"
65 |
66 | test += if (tax != 0) "[R] TAX :[R]${tax} %\n" + "[R] GRAND TOTAL :[R]${totalBill * (tax / 100f) + totalBill} $\n" else ""
67 |
68 | test += "[L][R]\n" +
69 | "$customer\n" +
70 | "[C]$barcode\n" +
71 | "[L]\n" +
72 | "[C]VISIT HIS SITE\n" +
73 | "[L]\n" +
74 | "[L]\n" +
75 | "[C]http://www.developpeur-web.khairo.com/\n" +
76 | "[L]\n" +
77 | "[L]\n" +
78 | "[L]\n" +
79 | "[L]\n" +
80 | "[L]\n"
81 |
82 | return printer.setTextToPrint(test)
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
15 |
16 |
21 |
22 |
28 |
29 |
35 |
36 |
41 |
42 |
47 |
48 |
55 |
56 |
62 |
63 |
69 |
70 |
71 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/exeption/PrintingException.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.exeption
2 |
3 | import android.app.AlertDialog
4 | import android.content.Context
5 | import com.khairo.exeption.PrintingException.FINISH_BARCODE_ERROR
6 | import com.khairo.exeption.PrintingException.FINISH_ENCODING_ERROR
7 | import com.khairo.exeption.PrintingException.FINISH_NO_PRINTER
8 | import com.khairo.exeption.PrintingException.FINISH_PARSER_ERROR
9 | import com.khairo.exeption.PrintingException.FINISH_PRINTER_DISCONNECTED
10 | import com.khairo.exeption.PrintingException.FINISH_SUCCESS
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.runBlocking
13 | import java.lang.ref.WeakReference
14 |
15 | //try {
16 | // var deviceConnection: TcpDeviceConnection? = printerData.printerConnection
17 | //// if (deviceConnection == null)
18 | //// deviceConnection = BluetoothPrintersConnections.selectFirstPaired()
19 | //
20 | // if (deviceConnection == null) return onPostExecute(CoroutinesEscPosPrint.FINISH_NO_PRINTER)
21 | //
22 | // val context = weakContext.get() ?: return
23 | // val printer = com.khairo.escposprinter.CoroutinesEscPosPrinter(
24 | // context,
25 | // deviceConnection,
26 | // printerData.printerDpi,
27 | // printerData.printerWidthMM,
28 | // printerData.printerNbrCharactersPerLine,
29 | // EscPosCharsetEncoding("Arabic", 22)
30 | // )
31 | //
32 | // printer.printFormattedTextAndCut(printerData.textToPrint).apply { disconnectPrinter() }
33 | //
34 | //} catch (e: EscPosConnectionException) {
35 | // e.printStackTrace()
36 | // return onPostExecute(CoroutinesEscPosPrint.FINISH_PRINTER_DISCONNECTED)
37 | //} catch (e: EscPosParserException) {
38 | // e.printStackTrace()
39 | // return onPostExecute(CoroutinesEscPosPrint.FINISH_PARSER_ERROR)
40 | //} catch (e: EscPosEncodingException) {
41 | // e.printStackTrace()
42 | // return onPostExecute(CoroutinesEscPosPrint.FINISH_ENCODING_ERROR)
43 | //} catch (e: EscPosBarcodeException) {
44 | // e.printStackTrace()
45 | // return onPostExecute(CoroutinesEscPosPrint.FINISH_BARCODE_ERROR)
46 | //}
47 | //return onPostExecute(FINISH_SUCCESS)
48 |
49 | fun onException(context: Context, result: Int) {
50 | val weakContext: WeakReference = WeakReference(context)
51 |
52 | val newContext = weakContext.get() ?: return
53 | runBlocking(Dispatchers.Main) {
54 | when (result) {
55 | FINISH_SUCCESS -> AlertDialog.Builder(newContext)
56 | .setTitle("Success")
57 | .setMessage("Congratulation ! The text is printed !")
58 | .show()
59 | FINISH_NO_PRINTER -> AlertDialog.Builder(newContext)
60 | .setTitle("No printer")
61 | .setMessage("The application can't find any printer connected.")
62 | .show()
63 | FINISH_PRINTER_DISCONNECTED -> AlertDialog.Builder(newContext)
64 | .setTitle("Broken connection")
65 | .setMessage("Unable to connect the printer.")
66 | .show()
67 | FINISH_PARSER_ERROR -> AlertDialog.Builder(newContext)
68 | .setTitle("Invalid formatted text")
69 | .setMessage("It seems to be an invalid syntax problem.")
70 | .show()
71 | FINISH_ENCODING_ERROR -> AlertDialog.Builder(newContext)
72 | .setTitle("Bad selected encoding")
73 | .setMessage("The selected encoding character returning an error.")
74 | .show()
75 | FINISH_BARCODE_ERROR -> AlertDialog.Builder(newContext)
76 | .setTitle("Invalid barcode")
77 | .setMessage("Data send to be converted to barcode or QR code seems to be invalid.")
78 | .show()
79 | else -> AlertDialog.Builder(newContext)
80 | .setTitle("Unknown error")
81 | .setMessage("Unknown error.")
82 | .show()
83 | }
84 | }
85 | }
86 |
87 | object PrintingException {
88 |
89 | const val FINISH_SUCCESS = 1
90 | const val FINISH_NO_PRINTER = 2
91 | const val FINISH_PRINTER_DISCONNECTED = 3
92 | const val FINISH_PARSER_ERROR = 4
93 | const val FINISH_ENCODING_ERROR = 5
94 | const val FINISH_BARCODE_ERROR = 6
95 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/async/AsyncEscPosPrint.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.async
2 |
3 | import android.app.AlertDialog
4 | import android.content.Context
5 | import android.os.AsyncTask
6 | import com.khairo.escposprinter.EscPosCharsetEncoding
7 | import com.khairo.escposprinter.EscPosPrinter
8 | import com.khairo.escposprinter.connection.DeviceConnection
9 | import com.khairo.escposprinter.connection.bluetooth.BluetoothPrintersConnections
10 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
11 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
12 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
13 | import com.khairo.escposprinter.exceptions.EscPosParserException
14 | import java.lang.ref.WeakReference
15 |
16 | abstract class AsyncEscPosPrint(context: Context?) : AsyncTask() {
17 | private var weakContext: WeakReference = WeakReference(context)
18 |
19 | override fun doInBackground(vararg printersData: AsyncEscPosPrinter): Int {
20 | if (printersData.isEmpty())
21 | return FINISH_NO_PRINTER
22 |
23 | val printerData = printersData[0]
24 | try {
25 | var deviceConnection: DeviceConnection? = printerData.printerConnection
26 | if (deviceConnection == null)
27 | deviceConnection = BluetoothPrintersConnections.selectFirstPaired()
28 |
29 | if (deviceConnection == null) return FINISH_NO_PRINTER
30 |
31 | val printer = EscPosPrinter(
32 | deviceConnection,
33 | printerData.printerDpi,
34 | printerData.printerWidthMM,
35 | printerData.printerNbrCharactersPerLine,
36 | EscPosCharsetEncoding("Arabic", 22)
37 | )
38 |
39 | printer.printFormattedTextAndCut(printerData.textToPrint).apply { disconnectPrinter() }
40 |
41 | } catch (e: EscPosConnectionException) {
42 | e.printStackTrace()
43 | return FINISH_PRINTER_DISCONNECTED
44 | } catch (e: EscPosParserException) {
45 | e.printStackTrace()
46 | return FINISH_PARSER_ERROR
47 | } catch (e: EscPosEncodingException) {
48 | e.printStackTrace()
49 | return FINISH_ENCODING_ERROR
50 | } catch (e: EscPosBarcodeException) {
51 | e.printStackTrace()
52 | return FINISH_BARCODE_ERROR
53 | }
54 | return FINISH_SUCCESS
55 | }
56 |
57 | override fun onPostExecute(result: Int) {
58 | val context = weakContext.get() ?: return
59 | when (result) {
60 | FINISH_SUCCESS ->
61 | AlertDialog.Builder(context)
62 | .setTitle("Success")
63 | .setMessage("Congratulation ! The text is printed !")
64 | .show()
65 | FINISH_NO_PRINTER -> AlertDialog.Builder(context)
66 | .setTitle("No printer")
67 | .setMessage("The application can't find any printer connected.")
68 | .show()
69 | FINISH_PRINTER_DISCONNECTED -> AlertDialog.Builder(context)
70 | .setTitle("Broken connection")
71 | .setMessage("Unable to connect the printer.")
72 | .show()
73 | FINISH_PARSER_ERROR -> AlertDialog.Builder(context)
74 | .setTitle("Invalid formatted text")
75 | .setMessage("It seems to be an invalid syntax problem.")
76 | .show()
77 | FINISH_ENCODING_ERROR -> AlertDialog.Builder(context)
78 | .setTitle("Bad selected encoding")
79 | .setMessage("The selected encoding character returning an error.")
80 | .show()
81 | FINISH_BARCODE_ERROR -> AlertDialog.Builder(context)
82 | .setTitle("Invalid barcode")
83 | .setMessage("Data send to be converted to barcode or QR code seems to be invalid.")
84 | .show()
85 | }
86 | }
87 |
88 | companion object {
89 | const val FINISH_SUCCESS = 1
90 | const val FINISH_NO_PRINTER = 2
91 | const val FINISH_PRINTER_DISCONNECTED = 3
92 | const val FINISH_PARSER_ERROR = 4
93 | const val FINISH_ENCODING_ERROR = 5
94 | const val FINISH_BARCODE_ERROR = 6
95 | }
96 |
97 | }
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | xmlns:android
34 |
35 | ^$
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | xmlns:.*
45 |
46 | ^$
47 |
48 |
49 | BY_NAME
50 |
51 |
52 |
53 |
54 |
55 |
56 | .*:id
57 |
58 | http://schemas.android.com/apk/res/android
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | .*:name
68 |
69 | http://schemas.android.com/apk/res/android
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | name
79 |
80 | ^$
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | style
90 |
91 | ^$
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | .*
101 |
102 | ^$
103 |
104 |
105 | BY_NAME
106 |
107 |
108 |
109 |
110 |
111 |
112 | .*
113 |
114 | http://schemas.android.com/apk/res/android
115 |
116 |
117 | ANDROID_ATTRIBUTE_ORDER
118 |
119 |
120 |
121 |
122 |
123 |
124 | .*
125 |
126 | .*
127 |
128 |
129 | BY_NAME
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserBarcode.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.barcode.*
5 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
6 | import com.khairo.escposprinter.exceptions.EscPosParserException
7 | import java.util.*
8 |
9 | class PrinterTextParserBarcode(
10 | printerTextParserColumn: PrinterTextParserColumn,
11 | textAlign: String?,
12 | barcodeAttributes: Hashtable,
13 | var code: String
14 | ) : IPrinterTextParserElement {
15 | private var barcode: Barcode? = null
16 | private val length: Int
17 | private var align: ByteArray
18 |
19 | /**
20 | * Get the barcode width in char length.
21 | *
22 | * @return int
23 | */
24 | @Throws(EscPosEncodingException::class)
25 | override fun length(): Int {
26 | return length
27 | }
28 |
29 | /**
30 | * Print barcode
31 | *
32 | * @param printerSocket Instance of EscPosPrinterCommands
33 | * @return this Fluent method
34 | */
35 | override fun print(printerSocket: EscPosPrinterCommands?): PrinterTextParserBarcode {
36 | printerSocket!!.setAlign(align).printBarcode(barcode!!)
37 | return this
38 | }
39 |
40 | init {
41 | val printer = printerTextParserColumn.line.textParser.printer
42 | code = code.trim { it <= ' ' }
43 | align = EscPosPrinterCommands.TEXT_ALIGN_LEFT
44 | when (textAlign) {
45 | PrinterTextParser.TAGS_ALIGN_CENTER -> align = EscPosPrinterCommands.TEXT_ALIGN_CENTER
46 | PrinterTextParser.TAGS_ALIGN_RIGHT -> align = EscPosPrinterCommands.TEXT_ALIGN_RIGHT
47 | }
48 | length = printer.printerNbrCharactersPerLine
49 | var height = 10f
50 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_HEIGHT)) {
51 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_HEIGHT]
52 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_HEIGHT)
53 | height = try {
54 | barCodeAttribute.toFloat()
55 | } catch (nfe: NumberFormatException) {
56 | throw EscPosParserException("Invalid barcode " + PrinterTextParser.ATTR_BARCODE_HEIGHT + " value")
57 | }
58 | }
59 | var width = 0f
60 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_WIDTH)) {
61 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_WIDTH]
62 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_WIDTH)
63 | width = try {
64 | barCodeAttribute.toFloat()
65 | } catch (nfe: NumberFormatException) {
66 | throw EscPosParserException("Invalid barcode " + PrinterTextParser.ATTR_BARCODE_WIDTH + " value")
67 | }
68 | }
69 | var textPosition = EscPosPrinterCommands.BARCODE_TEXT_POSITION_BELOW
70 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_TEXT_POSITION)) {
71 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_TEXT_POSITION]
72 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_TEXT_POSITION)
73 | when (barCodeAttribute) {
74 | PrinterTextParser.ATTR_BARCODE_TEXT_POSITION_NONE -> textPosition =
75 | EscPosPrinterCommands.BARCODE_TEXT_POSITION_NONE
76 | PrinterTextParser.ATTR_BARCODE_TEXT_POSITION_ABOVE -> textPosition =
77 | EscPosPrinterCommands.BARCODE_TEXT_POSITION_ABOVE
78 | }
79 | }
80 | var barcodeType: String? = PrinterTextParser.ATTR_BARCODE_TYPE_EAN13
81 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_TYPE)) {
82 | barcodeType = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_TYPE]
83 | if (barcodeType == null) {
84 | throw EscPosParserException("Invalid barcode attribute : " + PrinterTextParser.ATTR_BARCODE_TYPE)
85 | }
86 | }
87 | barcode = when (barcodeType) {
88 | PrinterTextParser.ATTR_BARCODE_TYPE_EAN8 -> BarcodeEAN8(
89 | printer,
90 | code,
91 | width,
92 | height,
93 | textPosition
94 | )
95 | PrinterTextParser.ATTR_BARCODE_TYPE_EAN13 -> BarcodeEAN13(
96 | printer,
97 | code,
98 | width,
99 | height,
100 | textPosition
101 | )
102 | PrinterTextParser.ATTR_BARCODE_TYPE_UPCA -> BarcodeUPCA(
103 | printer,
104 | code,
105 | width,
106 | height,
107 | textPosition
108 | )
109 | PrinterTextParser.ATTR_BARCODE_TYPE_UPCE -> BarcodeUPCE(
110 | printer,
111 | code,
112 | width,
113 | height,
114 | textPosition
115 | )
116 | PrinterTextParser.ATTR_BARCODE_TYPE_128 -> Barcode128(
117 | printer,
118 | code,
119 | width,
120 | height,
121 | textPosition
122 | )
123 | else -> throw EscPosParserException("Invalid barcode attribute : " + PrinterTextParser.ATTR_BARCODE_TYPE)
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParserBarcode.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.CoroutinesEscPosPrinterCommands
4 | import com.khairo.escposprinter.EscPosPrinterCommands
5 | import com.khairo.escposprinter.barcode.*
6 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
7 | import com.khairo.escposprinter.exceptions.EscPosParserException
8 | import java.util.*
9 |
10 | class CoroutinesPrinterTextParserBarcode(
11 | printerTextParserColumn: CoroutinesPrinterTextParserColumn,
12 | textAlign: String?,
13 | barcodeAttributes: Hashtable,
14 | var code: String
15 | ) : CoroutinesIPrinterTextParserElement {
16 | private var barcode: Barcode? = null
17 | private val length: Int
18 | private var align: ByteArray
19 |
20 | /**
21 | * Get the barcode width in char length.
22 | *
23 | * @return int
24 | */
25 | @Throws(EscPosEncodingException::class)
26 | override fun length(): Int {
27 | return length
28 | }
29 |
30 | /**
31 | * Print barcode
32 | *
33 | * @param printerSocket Instance of EscPosPrinterCommands
34 | * @return this Fluent method
35 | */
36 | override suspend fun print(printerSocket: CoroutinesEscPosPrinterCommands?): CoroutinesPrinterTextParserBarcode {
37 | printerSocket!!.setAlign(align).printBarcode(barcode!!)
38 | return this
39 | }
40 |
41 | init {
42 | val printer = printerTextParserColumn.line.textParser.printer
43 | code = code.trim { it <= ' ' }
44 | align = EscPosPrinterCommands.TEXT_ALIGN_LEFT
45 | when (textAlign) {
46 | PrinterTextParser.TAGS_ALIGN_CENTER -> align = EscPosPrinterCommands.TEXT_ALIGN_CENTER
47 | PrinterTextParser.TAGS_ALIGN_RIGHT -> align = EscPosPrinterCommands.TEXT_ALIGN_RIGHT
48 | }
49 | length = printer.printerNbrCharactersPerLine
50 | var height = 10f
51 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_HEIGHT)) {
52 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_HEIGHT]
53 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_HEIGHT)
54 | height = try {
55 | barCodeAttribute.toFloat()
56 | } catch (nfe: NumberFormatException) {
57 | throw EscPosParserException("Invalid barcode " + PrinterTextParser.ATTR_BARCODE_HEIGHT + " value")
58 | }
59 | }
60 | var width = 0f
61 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_WIDTH)) {
62 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_WIDTH]
63 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_WIDTH)
64 | width = try {
65 | barCodeAttribute.toFloat()
66 | } catch (nfe: NumberFormatException) {
67 | throw EscPosParserException("Invalid barcode " + PrinterTextParser.ATTR_BARCODE_WIDTH + " value")
68 | }
69 | }
70 | var textPosition = EscPosPrinterCommands.BARCODE_TEXT_POSITION_BELOW
71 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_TEXT_POSITION)) {
72 | val barCodeAttribute = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_TEXT_POSITION]
73 | ?: throw EscPosParserException("Invalid barcode attribute: " + PrinterTextParser.ATTR_BARCODE_TEXT_POSITION)
74 | when (barCodeAttribute) {
75 | PrinterTextParser.ATTR_BARCODE_TEXT_POSITION_NONE -> textPosition =
76 | EscPosPrinterCommands.BARCODE_TEXT_POSITION_NONE
77 | PrinterTextParser.ATTR_BARCODE_TEXT_POSITION_ABOVE -> textPosition =
78 | EscPosPrinterCommands.BARCODE_TEXT_POSITION_ABOVE
79 | }
80 | }
81 | var barcodeType: String? = PrinterTextParser.ATTR_BARCODE_TYPE_EAN13
82 | if (barcodeAttributes.containsKey(PrinterTextParser.ATTR_BARCODE_TYPE)) {
83 | barcodeType = barcodeAttributes[PrinterTextParser.ATTR_BARCODE_TYPE]
84 | if (barcodeType == null) {
85 | throw EscPosParserException("Invalid barcode attribute : " + PrinterTextParser.ATTR_BARCODE_TYPE)
86 | }
87 | }
88 | barcode = when (barcodeType) {
89 | PrinterTextParser.ATTR_BARCODE_TYPE_EAN8 -> BarcodeEAN8(
90 | printer,
91 | code,
92 | width,
93 | height,
94 | textPosition
95 | )
96 | PrinterTextParser.ATTR_BARCODE_TYPE_EAN13 -> BarcodeEAN13(
97 | printer,
98 | code,
99 | width,
100 | height,
101 | textPosition
102 | )
103 | PrinterTextParser.ATTR_BARCODE_TYPE_UPCA -> BarcodeUPCA(
104 | printer,
105 | code,
106 | width,
107 | height,
108 | textPosition
109 | )
110 | PrinterTextParser.ATTR_BARCODE_TYPE_UPCE -> BarcodeUPCE(
111 | printer,
112 | code,
113 | width,
114 | height,
115 | textPosition
116 | )
117 | PrinterTextParser.ATTR_BARCODE_TYPE_128 -> Barcode128(
118 | printer,
119 | code,
120 | width,
121 | height,
122 | textPosition
123 | )
124 | else -> throw EscPosParserException("Invalid barcode attribute : " + PrinterTextParser.ATTR_BARCODE_TYPE)
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserImg.java:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.drawable.BitmapDrawable;
5 | import android.graphics.drawable.Drawable;
6 |
7 | import com.khairo.escposprinter.EscPosPrinter;
8 | import com.khairo.escposprinter.EscPosPrinterCommands;
9 | import com.khairo.escposprinter.EscPosPrinterSize;
10 | import com.khairo.escposprinter.exceptions.EscPosEncodingException;
11 |
12 |
13 | public class PrinterTextParserImg implements IPrinterTextParserElement {
14 |
15 | /**
16 | * Convert Drawable instance to a hexadecimal string of the image data.
17 | *
18 | * @param printerSize A EscPosPrinterSize instance that will print the image.
19 | * @param drawable Drawable instance to be converted.
20 | * @return A hexadecimal string of the image data. Empty string if Drawable cannot be cast to BitmapDrawable.
21 | */
22 | public static String bitmapToHexadecimalString(EscPosPrinterSize printerSize, Drawable drawable) {
23 | if (drawable instanceof BitmapDrawable) {
24 | return PrinterTextParserImg.bitmapToHexadecimalString(printerSize, (BitmapDrawable) drawable);
25 | }
26 | return "";
27 | }
28 |
29 | /**
30 | * Convert BitmapDrawable instance to a hexadecimal string of the image data.
31 | *
32 | * @param printerSize A EscPosPrinterSize instance that will print the image.
33 | * @param bitmapDrawable BitmapDrawable instance to be converted.
34 | * @return A hexadecimal string of the image data.
35 | */
36 | public static String bitmapToHexadecimalString(EscPosPrinterSize printerSize, BitmapDrawable bitmapDrawable) {
37 | return PrinterTextParserImg.bitmapToHexadecimalString(printerSize, bitmapDrawable.getBitmap());
38 | }
39 |
40 | /**
41 | * Convert Bitmap instance to a hexadecimal string of the image data.
42 | *
43 | * @param printerSize A EscPosPrinterSize instance that will print the image.
44 | * @param bitmap Bitmap instance to be converted.
45 | * @return A hexadecimal string of the image data.
46 | */
47 | public static String bitmapToHexadecimalString(EscPosPrinterSize printerSize, Bitmap bitmap) {
48 | return PrinterTextParserImg.bytesToHexadecimalString(printerSize.bitmapToBytes(bitmap));
49 | }
50 |
51 | /**
52 | * Convert byte array to a hexadecimal string of the image data.
53 | *
54 | * @param bytes Bytes contain the image in ESC/POS command.
55 | * @return A hexadecimal string of the image data.
56 | */
57 | public static String bytesToHexadecimalString(byte[] bytes) {
58 | StringBuilder imageHexString = new StringBuilder();
59 | for (byte aByte : bytes) {
60 | String hexString = Integer.toHexString(aByte & 0xFF);
61 | if (hexString.length() == 1) {
62 | hexString = "0" + hexString;
63 | }
64 | imageHexString.append(hexString);
65 | }
66 | return imageHexString.toString();
67 | }
68 |
69 | /**
70 | * Convert hexadecimal string of the image data to bytes ESC/POS command.
71 | *
72 | * @param hexString Hexadecimal string of the image data.
73 | * @return Bytes contain the image in ESC/POS command.
74 | */
75 | public static byte[] hexadecimalStringToBytes(String hexString) throws NumberFormatException {
76 | byte[] bytes = new byte[hexString.length() / 2];
77 | for (int i = 0; i < bytes.length; i++) {
78 | int pos = i * 2;
79 | bytes[i] = (byte) Integer.parseInt(hexString.substring(pos, pos + 2), 16);
80 | }
81 |
82 | return bytes;
83 | }
84 |
85 |
86 | private int length;
87 | private byte[] image;
88 |
89 | /**
90 | * Create new instance of PrinterTextParserImg.
91 | *
92 | * @param printerTextParserColumn Parent PrinterTextParserColumn instance.
93 | * @param textAlign Set the image alignment. Use PrinterTextParser.TAGS_ALIGN_... constants.
94 | * @param hexadecimalString Hexadecimal string of the image data.
95 | */
96 | public PrinterTextParserImg(PrinterTextParserColumn printerTextParserColumn, String textAlign, String hexadecimalString) {
97 | this(printerTextParserColumn, textAlign, PrinterTextParserImg.hexadecimalStringToBytes(hexadecimalString));
98 | }
99 |
100 | /**
101 | * Create new instance of PrinterTextParserImg.
102 | *
103 | * @param printerTextParserColumn Parent PrinterTextParserColumn instance.
104 | * @param textAlign Set the image alignment. Use PrinterTextParser.TAGS_ALIGN_... constants.
105 | * @param image Bytes contain the image in ESC/POS command.
106 | */
107 | public PrinterTextParserImg(PrinterTextParserColumn printerTextParserColumn, String textAlign, byte[] image) {
108 | EscPosPrinter printer = printerTextParserColumn.getLine().getTextParser().getPrinter();
109 |
110 | int
111 | byteWidth = ((int) image[4] & 0xFF) + ((int) image[5] & 0xFF) * 256,
112 | width = byteWidth * 8,
113 | height = ((int) image[6] & 0xFF) + ((int) image[7] & 0xFF) * 256,
114 | nbrByteDiff = (int) Math.floor(((float) (printer.getPrinterWidthPx() - width)) / 8f),
115 | nbrWhiteByteToInsert = 0;
116 |
117 | switch (textAlign) {
118 | case PrinterTextParser.TAGS_ALIGN_CENTER:
119 | nbrWhiteByteToInsert = Math.round(((float) nbrByteDiff) / 2f);
120 | break;
121 | case PrinterTextParser.TAGS_ALIGN_RIGHT:
122 | nbrWhiteByteToInsert = nbrByteDiff;
123 | break;
124 | }
125 |
126 | if (nbrWhiteByteToInsert > 0) {
127 | int newByteWidth = byteWidth + nbrWhiteByteToInsert;
128 | byte[] newImage = EscPosPrinterCommands.initImageCommand(newByteWidth, height);
129 | for (int i = 0; i < height; i++) {
130 | System.arraycopy(image, (byteWidth * i + 8), newImage, (newByteWidth * i + nbrWhiteByteToInsert + 8), byteWidth);
131 | }
132 | image = newImage;
133 | }
134 |
135 | this.length = (int) Math.ceil(((float) byteWidth * 8) / ((float) printer.getPrinterCharSizeWidthPx()));
136 | this.image = image;
137 | }
138 |
139 | /**
140 | * Get the image width in char length.
141 | *
142 | * @return int
143 | */
144 | @Override
145 | public int length() throws EscPosEncodingException {
146 | return this.length;
147 | }
148 |
149 | /**
150 | * Print image
151 | *
152 | * @param printerSocket Instance of EscPosPrinterCommands
153 | * @return this Fluent method
154 | */
155 | @Override
156 | public PrinterTextParserImg print(EscPosPrinterCommands printerSocket) {
157 | printerSocket.printImage(this.image);
158 | return this;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParserImg.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.drawable.BitmapDrawable
5 | import android.graphics.drawable.Drawable
6 | import com.khairo.escposprinter.CoroutinesEscPosPrinterCommands
7 | import com.khairo.escposprinter.EscPosPrinterCommands
8 | import com.khairo.escposprinter.EscPosPrinterSize
9 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
10 | import kotlin.experimental.and
11 |
12 | open class CoroutinesPrinterTextParserImg(
13 | printerTextParserColumn: CoroutinesPrinterTextParserColumn,
14 | textAlign: String?,
15 | image: ByteArray
16 | ) : CoroutinesIPrinterTextParserElement {
17 | private val length: Int
18 | private val image: ByteArray
19 |
20 | /**
21 | * Create new instance of PrinterTextParserImg.
22 | *
23 | * @param printerTextParserColumn Parent PrinterTextParserColumn instance.
24 | * @param textAlign Set the image alignment. Use PrinterTextParser.TAGS_ALIGN_... constants.
25 | * @param hexadecimalString Hexadecimal string of the image data.
26 | */
27 | constructor(
28 | printerTextParserColumn: CoroutinesPrinterTextParserColumn,
29 | textAlign: String?,
30 | hexadecimalString: String
31 | ) : this(printerTextParserColumn, textAlign, hexadecimalStringToBytes(hexadecimalString)) {
32 | }
33 |
34 | /**
35 | * Get the image width in char length.
36 | *
37 | * @return int
38 | */
39 | @Throws(EscPosEncodingException::class)
40 | override fun length(): Int {
41 | return length
42 | }
43 |
44 |
45 | /**
46 | * Print image
47 | *
48 | * @param printerSocket Instance of EscPosPrinterCommands
49 | * @return this Fluent method
50 | */
51 | override suspend fun print(printerSocket: CoroutinesEscPosPrinterCommands?): CoroutinesIPrinterTextParserElement? {
52 | printerSocket!!.printImage(image)
53 | return this
54 | }
55 |
56 | companion object {
57 | /**
58 | * Convert Drawable instance to a hexadecimal string of the image data.
59 | *
60 | * @param printerSize A EscPosPrinterSize instance that will print the image.
61 | * @param drawable Drawable instance to be converted.
62 | * @return A hexadecimal string of the image data. Empty string if Drawable cannot be cast to BitmapDrawable.
63 | */
64 | fun bitmapToHexadecimalString(printerSize: EscPosPrinterSize, drawable: Drawable?): String {
65 | return if (drawable is BitmapDrawable) {
66 | bitmapToHexadecimalString(
67 | printerSize,
68 | drawable
69 | )
70 | } else ""
71 | }
72 |
73 | /**
74 | * Convert BitmapDrawable instance to a hexadecimal string of the image data.
75 | *
76 | * @param printerSize A EscPosPrinterSize instance that will print the image.
77 | * @param bitmapDrawable BitmapDrawable instance to be converted.
78 | * @return A hexadecimal string of the image data.
79 | */
80 | fun bitmapToHexadecimalString(
81 | printerSize: EscPosPrinterSize,
82 | bitmapDrawable: BitmapDrawable
83 | ): String {
84 | return bitmapToHexadecimalString(printerSize, bitmapDrawable.bitmap)
85 | }
86 |
87 | /**
88 | * Convert Bitmap instance to a hexadecimal string of the image data.
89 | *
90 | * @param printerSize A EscPosPrinterSize instance that will print the image.
91 | * @param bitmap Bitmap instance to be converted.
92 | * @return A hexadecimal string of the image data.
93 | */
94 | fun bitmapToHexadecimalString(printerSize: EscPosPrinterSize, bitmap: Bitmap?): String {
95 | return bytesToHexadecimalString(
96 | printerSize.bitmapToBytes(
97 | bitmap!!
98 | )
99 | )
100 | }
101 |
102 | /**
103 | * Convert byte array to a hexadecimal string of the image data.
104 | *
105 | * @param bytes Bytes contain the image in ESC/POS command.
106 | * @return A hexadecimal string of the image data.
107 | */
108 | fun bytesToHexadecimalString(bytes: ByteArray): String {
109 | val imageHexString = StringBuilder()
110 | for (aByte in bytes) {
111 | var hexString = Integer.toHexString((aByte and 0xFF.toByte()).toInt())
112 | if (hexString.length == 1) {
113 | hexString = "0$hexString"
114 | }
115 | imageHexString.append(hexString)
116 | }
117 | return imageHexString.toString()
118 | }
119 |
120 | /**
121 | * Convert hexadecimal string of the image data to bytes ESC/POS command.
122 | *
123 | * @param hexString Hexadecimal string of the image data.
124 | * @return Bytes contain the image in ESC/POS command.
125 | */
126 | @Throws(NumberFormatException::class)
127 | fun hexadecimalStringToBytes(hexString: String): ByteArray {
128 | val bytes = ByteArray(hexString.length / 2)
129 | for (i in bytes.indices) {
130 | val pos = i * 2
131 | bytes[i] = hexString.substring(pos, pos + 2).toInt(16).toByte()
132 | }
133 | return bytes
134 | }
135 | }
136 |
137 | /**
138 | * Create new instance of PrinterTextParserImg.
139 | *
140 | * @param printerTextParserColumn Parent PrinterTextParserColumn instance.
141 | * @param textAlign Set the image alignment. Use PrinterTextParser.TAGS_ALIGN_... constants.
142 | * @param image Bytes contain the image in ESC/POS command.
143 | */
144 | init {
145 | var image = image
146 | val printer = printerTextParserColumn.line.textParser.printer
147 | val byteWidth = (image[4].toInt() and 0xFF) + (image[5].toInt() and 0xFF) * 256
148 | val width = byteWidth * 8
149 | val height = (image[6].toInt() and 0xFF) + (image[7].toInt() and 0xFF) * 256
150 | val nbrByteDiff = Math.floor(((printer.printerWidthPx - width).toFloat() / 8f).toDouble())
151 | .toInt()
152 | var nbrWhiteByteToInsert = 0
153 | when (textAlign) {
154 | PrinterTextParser.TAGS_ALIGN_CENTER -> nbrWhiteByteToInsert = Math.round(
155 | nbrByteDiff.toFloat() / 2f
156 | )
157 | PrinterTextParser.TAGS_ALIGN_RIGHT -> nbrWhiteByteToInsert = nbrByteDiff
158 | }
159 | if (nbrWhiteByteToInsert > 0) {
160 | val newByteWidth = byteWidth + nbrWhiteByteToInsert
161 | val newImage = EscPosPrinterCommands.initImageCommand(newByteWidth, height)
162 | for (i in 0 until height) {
163 | System.arraycopy(
164 | image,
165 | byteWidth * i + 8,
166 | newImage,
167 | newByteWidth * i + nbrWhiteByteToInsert + 8,
168 | byteWidth
169 | )
170 | }
171 | image = newImage
172 | }
173 | length =
174 | Math.ceil((byteWidth.toFloat() * 8 / printer.printerCharSizeWidthPx.toFloat()).toDouble())
175 | .toInt()
176 | this.image = image
177 | }
178 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/CoroutinesEscPosPrinter.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter
2 |
3 | import android.content.Context
4 | import com.khairo.escposprinter.connection.tcp.TcpDeviceConnection
5 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
6 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
7 | import com.khairo.escposprinter.exceptions.EscPosParserException
8 | import com.khairo.escposprinter.textparser.*
9 | import com.khairo.exeption.PrintingException.FINISH_NO_PRINTER
10 | import com.khairo.exeption.onException
11 |
12 | class CoroutinesEscPosPrinter(
13 | var printer: CoroutinesEscPosPrinterCommands?,
14 | printerDpi: Int,
15 | printerWidthMM: Float,
16 | printerNbrCharactersPerLine: Int
17 | ) : EscPosPrinterSize(printerDpi, printerWidthMM, printerNbrCharactersPerLine) {
18 |
19 | /**
20 | * Create new instance of EscPosPrinter.
21 | *
22 | * @param printerConnection Instance of class which implement DeviceConnection
23 | * @param printerDpi DPI of the connected printer
24 | * @param printerWidthMM Printing width in millimeters
25 | * @param printerNbrCharactersPerLine The maximum number of characters that can be printed on a line.
26 | */
27 | constructor(
28 | printerConnection: TcpDeviceConnection?,
29 | printerDpi: Int,
30 | printerWidthMM: Float,
31 | printerNbrCharactersPerLine: Int
32 | ) : this(
33 | printerConnection?.let { CoroutinesEscPosPrinterCommands(it) },
34 | printerDpi,
35 | printerWidthMM,
36 | printerNbrCharactersPerLine
37 | )
38 |
39 | /**
40 | * Create new instance of EscPosPrinter.
41 | *
42 | * @param printerConnection Instance of class which implement DeviceConnection
43 | * @param printerDpi DPI of the connected printer
44 | * @param printerWidthMM Printing width in millimeters
45 | * @param printerNbrCharactersPerLine The maximum number of characters that can be printed on a line.
46 | * @param charsetEncoding Set the charset encoding.
47 | */
48 | constructor(
49 | printerConnection: TcpDeviceConnection?,
50 | printerDpi: Int,
51 | printerWidthMM: Float,
52 | printerNbrCharactersPerLine: Int,
53 | charsetEncoding: EscPosCharsetEncoding?
54 | ) : this(
55 | printerConnection?.let { CoroutinesEscPosPrinterCommands(it, charsetEncoding) },
56 | printerDpi,
57 | printerWidthMM,
58 | printerNbrCharactersPerLine
59 | )
60 |
61 | /**
62 | * Close the connection with the printer.
63 | *
64 | * @return Fluent interface
65 | */
66 | suspend fun disconnectPrinter(): CoroutinesEscPosPrinter {
67 | if (printer != null) {
68 | printer!!.disconnect()
69 | printer = null
70 | }
71 | return this
72 | }
73 | /**
74 | * Print a formatted text. Read the README.md for more information about text formatting options.
75 | *
76 | * @param text Formatted text to be printed.
77 | * @param mmFeedPaper millimeter distance feed paper at the end.
78 | * @return Fluent interface
79 | */
80 | /**
81 | * Print a formatted text. Read the README.md for more information about text formatting options.
82 | *
83 | * @param text Formatted text to be printed.
84 | * @return Fluent interface
85 | */
86 | @JvmOverloads
87 | @Throws(
88 | EscPosParserException::class,
89 | EscPosEncodingException::class,
90 | EscPosBarcodeException::class
91 | )
92 | suspend fun printFormattedText(
93 | context: Context,
94 | text: String?,
95 | mmFeedPaper: Float = 20f
96 | ): CoroutinesEscPosPrinter {
97 | return this.printFormattedText(context, text, mmToPx(mmFeedPaper))
98 | }
99 |
100 | /**
101 | * Print a formatted text. Read the README.md for more information about text formatting options.
102 | *
103 | * @param text Formatted text to be printed.
104 | * @param dotsFeedPaper distance feed paper at the end.
105 | * @return Fluent interface
106 | */
107 | @Throws(
108 | EscPosParserException::class,
109 | EscPosEncodingException::class,
110 | EscPosBarcodeException::class
111 | )
112 | suspend fun printFormattedText(
113 | context: Context,
114 | text: String?,
115 | dotsFeedPaper: Int
116 | ): CoroutinesEscPosPrinter {
117 | if (printer == null || printerNbrCharactersPerLine == 0) {
118 | return this
119 | }
120 |
121 | val textParser = CoroutinesPrinterTextParser(this)
122 | val linesParsed = textParser
123 | .setFormattedText(text!!)
124 | .parse()
125 | printer!!.reset()
126 | for (line in linesParsed) {
127 | val columns = line!!.columns
128 | var lastElement: CoroutinesIPrinterTextParserElement? = null
129 | for (column in columns) {
130 | val elements = column!!.elements
131 | for (element in elements) {
132 | element!!.print(printer)
133 | lastElement = element
134 | }
135 | }
136 | if (lastElement is CoroutinesPrinterTextParserString) {
137 | printer!!.newLine(context)
138 | }
139 | }
140 | printer!!.feedPaper(context, dotsFeedPaper)
141 | return this
142 | }
143 | /**
144 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
145 | *
146 | * @param text Formatted text to be printed.
147 | * @param mmFeedPaper millimeter distance feed paper at the end.
148 | * @return Fluent interface
149 | */
150 | /**
151 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
152 | *
153 | * @param text Formatted text to be printed.
154 | * @return Fluent interface
155 | */
156 | @JvmOverloads
157 | @Throws(
158 | EscPosParserException::class,
159 | EscPosEncodingException::class,
160 | EscPosBarcodeException::class
161 | )
162 | suspend fun printFormattedTextAndCut(
163 | context: Context,
164 | text: String?,
165 | mmFeedPaper: Float = 20f
166 | ): CoroutinesEscPosPrinter {
167 | return this.printFormattedTextAndCut(context, text, mmToPx(mmFeedPaper))
168 | }
169 |
170 | /**
171 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
172 | *
173 | * @param text Formatted text to be printed.
174 | * @param dotsFeedPaper distance feed paper at the end.
175 | * @return Fluent interface
176 | */
177 | @Throws(
178 | EscPosParserException::class,
179 | EscPosEncodingException::class,
180 | EscPosBarcodeException::class
181 | )
182 | suspend fun printFormattedTextAndCut(
183 | context: Context,
184 | text: String?,
185 | dotsFeedPaper: Int
186 | ): CoroutinesEscPosPrinter {
187 | if (printer == null || printerNbrCharactersPerLine == 0) {
188 | onException(context, FINISH_NO_PRINTER)
189 | return this
190 | }
191 |
192 | this.printFormattedText(context, text, dotsFeedPaper)
193 | printer!!.cutPaper(context)
194 | return this
195 | }
196 |
197 | /**
198 | * @return Charset encoding
199 | */
200 | val encoding: EscPosCharsetEncoding
201 | get() = printer!!.getCharsetEncoding()!!
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/EscPosPrinter.java:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter;
2 |
3 | import com.khairo.escposprinter.connection.DeviceConnection;
4 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException;
5 | import com.khairo.escposprinter.exceptions.EscPosConnectionException;
6 | import com.khairo.escposprinter.exceptions.EscPosEncodingException;
7 | import com.khairo.escposprinter.exceptions.EscPosParserException;
8 | import com.khairo.escposprinter.textparser.IPrinterTextParserElement;
9 | import com.khairo.escposprinter.textparser.PrinterTextParser;
10 | import com.khairo.escposprinter.textparser.PrinterTextParserColumn;
11 | import com.khairo.escposprinter.textparser.PrinterTextParserLine;
12 | import com.khairo.escposprinter.textparser.PrinterTextParserString;
13 | import com.khairo.escposprinter.connection.DeviceConnection;
14 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException;
15 | import com.khairo.escposprinter.exceptions.EscPosConnectionException;
16 | import com.khairo.escposprinter.exceptions.EscPosEncodingException;
17 | import com.khairo.escposprinter.exceptions.EscPosParserException;
18 | import com.khairo.escposprinter.textparser.IPrinterTextParserElement;
19 | import com.khairo.escposprinter.textparser.PrinterTextParser;
20 | import com.khairo.escposprinter.textparser.PrinterTextParserColumn;
21 | import com.khairo.escposprinter.textparser.PrinterTextParserLine;
22 | import com.khairo.escposprinter.textparser.PrinterTextParserString;
23 |
24 | public class EscPosPrinter extends EscPosPrinterSize {
25 |
26 | private EscPosPrinterCommands printer = null;
27 |
28 | /**
29 | * Create new instance of EscPosPrinter.
30 | *
31 | * @param printerConnection Instance of class which implement DeviceConnection
32 | * @param printerDpi DPI of the connected printer
33 | * @param printerWidthMM Printing width in millimeters
34 | * @param printerNbrCharactersPerLine The maximum number of characters that can be printed on a line.
35 | */
36 | public EscPosPrinter(DeviceConnection printerConnection, int printerDpi, float printerWidthMM, int printerNbrCharactersPerLine) throws EscPosConnectionException {
37 | this(printerConnection != null ? new EscPosPrinterCommands(printerConnection) : null, printerDpi, printerWidthMM, printerNbrCharactersPerLine);
38 | }
39 |
40 | /**
41 | * Create new instance of EscPosPrinter.
42 | *
43 | * @param printerConnection Instance of class which implement DeviceConnection
44 | * @param printerDpi DPI of the connected printer
45 | * @param printerWidthMM Printing width in millimeters
46 | * @param printerNbrCharactersPerLine The maximum number of characters that can be printed on a line.
47 | * @param charsetEncoding Set the charset encoding.
48 | */
49 | public EscPosPrinter(DeviceConnection printerConnection, int printerDpi, float printerWidthMM, int printerNbrCharactersPerLine, EscPosCharsetEncoding charsetEncoding) throws EscPosConnectionException {
50 | this(printerConnection != null ? new EscPosPrinterCommands(printerConnection, charsetEncoding) : null, printerDpi, printerWidthMM, printerNbrCharactersPerLine);
51 | }
52 |
53 | /**
54 | * Create new instance of EscPosPrinter.
55 | *
56 | * @param printer Instance of EscPosPrinterCommands
57 | * @param printerDpi DPI of the connected printer
58 | * @param printerWidthMM Printing width in millimeters
59 | * @param printerNbrCharactersPerLine The maximum number of characters that can be printed on a line.
60 | */
61 | public EscPosPrinter(EscPosPrinterCommands printer, int printerDpi, float printerWidthMM, int printerNbrCharactersPerLine) throws EscPosConnectionException {
62 | super(printerDpi, printerWidthMM, printerNbrCharactersPerLine);
63 | if (printer != null) {
64 | this.printer = printer.connect();
65 | }
66 | }
67 |
68 | /**
69 | * Close the connection with the printer.
70 | *
71 | * @return Fluent interface
72 | */
73 | public EscPosPrinter disconnectPrinter() {
74 | if (this.printer != null) {
75 | this.printer.disconnect();
76 | this.printer = null;
77 | }
78 | return this;
79 | }
80 |
81 | /**
82 | * Print a formatted text. Read the README.md for more information about text formatting options.
83 | *
84 | * @param text Formatted text to be printed.
85 | * @return Fluent interface
86 | */
87 | public EscPosPrinter printFormattedText(String text) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
88 | return this.printFormattedText(text, 20f);
89 | }
90 |
91 | /**
92 | * Print a formatted text. Read the README.md for more information about text formatting options.
93 | *
94 | * @param text Formatted text to be printed.
95 | * @param mmFeedPaper millimeter distance feed paper at the end.
96 | * @return Fluent interface
97 | */
98 | public EscPosPrinter printFormattedText(String text, float mmFeedPaper) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
99 | return this.printFormattedText(text, this.mmToPx(mmFeedPaper));
100 | }
101 |
102 | /**
103 | * Print a formatted text. Read the README.md for more information about text formatting options.
104 | *
105 | * @param text Formatted text to be printed.
106 | * @param dotsFeedPaper distance feed paper at the end.
107 | * @return Fluent interface
108 | */
109 | public EscPosPrinter printFormattedText(String text, int dotsFeedPaper) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
110 | if (this.printer == null || this.getPrinterNbrCharactersPerLine() == 0) {
111 | return this;
112 | }
113 |
114 | PrinterTextParser textParser = new PrinterTextParser(this);
115 | PrinterTextParserLine[] linesParsed = textParser
116 | .setFormattedText(text)
117 | .parse();
118 |
119 | this.printer.reset();
120 |
121 | for (PrinterTextParserLine line : linesParsed) {
122 | PrinterTextParserColumn[] columns = line.getColumns();
123 |
124 | IPrinterTextParserElement lastElement = null;
125 | for (PrinterTextParserColumn column : columns) {
126 | IPrinterTextParserElement[] elements = column.getElements();
127 | for (IPrinterTextParserElement element : elements) {
128 | element.print(this.printer);
129 | lastElement = element;
130 | }
131 | }
132 |
133 | if (lastElement instanceof PrinterTextParserString) {
134 | this.printer.newLine();
135 | }
136 | }
137 |
138 | this.printer.feedPaper(dotsFeedPaper);
139 | return this;
140 | }
141 |
142 | /**
143 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
144 | *
145 | * @param text Formatted text to be printed.
146 | * @return Fluent interface
147 | */
148 | public EscPosPrinter printFormattedTextAndCut(String text) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
149 | return this.printFormattedTextAndCut(text, 20f);
150 | }
151 |
152 | /**
153 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
154 | *
155 | * @param text Formatted text to be printed.
156 | * @param mmFeedPaper millimeter distance feed paper at the end.
157 | * @return Fluent interface
158 | */
159 | public EscPosPrinter printFormattedTextAndCut(String text, float mmFeedPaper) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
160 | return this.printFormattedTextAndCut(text, this.mmToPx(mmFeedPaper));
161 | }
162 |
163 | /**
164 | * Print a formatted text and cut the paper. Read the README.md for more information about text formatting options.
165 | *
166 | * @param text Formatted text to be printed.
167 | * @param dotsFeedPaper distance feed paper at the end.
168 | * @return Fluent interface
169 | */
170 | public EscPosPrinter printFormattedTextAndCut(String text, int dotsFeedPaper) throws EscPosConnectionException, EscPosParserException, EscPosEncodingException, EscPosBarcodeException {
171 | if (this.printer == null || this.getPrinterNbrCharactersPerLine() == 0) {
172 | return this;
173 | }
174 |
175 | this.printFormattedText(text, dotsFeedPaper);
176 | this.printer.cutPaper();
177 |
178 | return this;
179 | }
180 |
181 | /**
182 | * @return Charset encoding
183 | */
184 | public EscPosCharsetEncoding getEncoding() {
185 | return this.printer.getCharsetEncoding();
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParser.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinter
4 | import com.khairo.escposprinter.EscPosPrinterCommands
5 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
6 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
7 | import com.khairo.escposprinter.exceptions.EscPosParserException
8 |
9 | class PrinterTextParser(val printer: EscPosPrinter) {
10 | private var textSize = arrayOf(EscPosPrinterCommands.TEXT_SIZE_NORMAL)
11 | private var textColor = arrayOf(EscPosPrinterCommands.TEXT_COLOR_BLACK)
12 | private var textReverseColor = arrayOf(EscPosPrinterCommands.TEXT_COLOR_REVERSE_OFF)
13 | private var textBold = arrayOf(EscPosPrinterCommands.TEXT_WEIGHT_NORMAL)
14 | private var textUnderline = arrayOf(EscPosPrinterCommands.TEXT_UNDERLINE_OFF)
15 | private var textDoubleStrike = arrayOf(EscPosPrinterCommands.TEXT_DOUBLE_STRIKE_OFF)
16 | private var text = ""
17 | fun setFormattedText(text: String): PrinterTextParser {
18 | this.text = text
19 | return this
20 | }
21 |
22 | val lastTextSize: ByteArray
23 | get() = textSize[textSize.size - 1]
24 |
25 | fun addTextSize(newTextSize: ByteArray): PrinterTextParser {
26 | textSize = arrayBytePush(textSize, newTextSize).toTypedArray()
27 | return this
28 | }
29 |
30 | fun dropLastTextSize(): PrinterTextParser {
31 | if (textSize.size > 1) {
32 | textSize = arrayByteDropLast(textSize).toTypedArray()
33 | }
34 | return this
35 | }
36 |
37 | val lastTextColor: ByteArray
38 | get() = textColor[textColor.size - 1]
39 |
40 | fun addTextColor(newTextColor: ByteArray): PrinterTextParser {
41 | textColor = arrayBytePush(textColor, newTextColor).toTypedArray()
42 | return this
43 | }
44 |
45 | fun dropLastTextColor(): PrinterTextParser {
46 | if (textColor.size > 1) {
47 | textColor = arrayByteDropLast(textColor).toTypedArray()
48 | }
49 | return this
50 | }
51 |
52 | val lastTextReverseColor: ByteArray
53 | get() = textReverseColor[textReverseColor.size - 1]
54 |
55 | fun addTextReverseColor(newTextReverseColor: ByteArray): PrinterTextParser {
56 | textReverseColor = arrayBytePush(textReverseColor, newTextReverseColor).toTypedArray()
57 | return this
58 | }
59 |
60 | fun dropLastTextReverseColor(): PrinterTextParser {
61 | if (textReverseColor.size > 1) {
62 | textReverseColor = arrayByteDropLast(textReverseColor).toTypedArray()
63 | }
64 | return this
65 | }
66 |
67 | val lastTextBold: ByteArray
68 | get() = textBold[textBold.size - 1]
69 |
70 | fun addTextBold(newTextBold: ByteArray): PrinterTextParser {
71 | textBold = arrayBytePush(textBold, newTextBold).toTypedArray()
72 | return this
73 | }
74 |
75 | fun dropTextBold(): PrinterTextParser {
76 | if (textBold.size > 1) {
77 | textBold = arrayByteDropLast(textBold).toTypedArray()
78 | }
79 | return this
80 | }
81 |
82 | val lastTextUnderline: ByteArray
83 | get() = textUnderline[textUnderline.size - 1]
84 |
85 | fun addTextUnderline(newTextUnderline: ByteArray): PrinterTextParser {
86 | textUnderline = arrayBytePush(textUnderline, newTextUnderline).toTypedArray()
87 | return this
88 | }
89 |
90 | fun dropLastTextUnderline(): PrinterTextParser {
91 | if (textUnderline.size > 1) {
92 | textUnderline = arrayByteDropLast(textUnderline).toTypedArray()
93 | }
94 | return this
95 | }
96 |
97 | val lastTextDoubleStrike: ByteArray
98 | get() = textDoubleStrike[textDoubleStrike.size - 1]
99 |
100 | fun addTextDoubleStrike(newTextDoubleStrike: ByteArray): PrinterTextParser {
101 | textDoubleStrike = arrayBytePush(textDoubleStrike, newTextDoubleStrike).toTypedArray()
102 | return this
103 | }
104 |
105 | fun dropLastTextDoubleStrike(): PrinterTextParser {
106 | if (textDoubleStrike.size > 1) {
107 | textDoubleStrike = arrayByteDropLast(textDoubleStrike).toTypedArray()
108 | }
109 | return this
110 | }
111 |
112 | @Throws(
113 | EscPosParserException::class,
114 | EscPosBarcodeException::class,
115 | EscPosEncodingException::class
116 | )
117 | fun parse(): Array {
118 | val stringLines = text.split("\n|\r\n".toRegex()).toTypedArray()
119 | val lines = arrayOfNulls(stringLines.size)
120 | var i = 0
121 | for (line in stringLines) {
122 | lines[i++] = PrinterTextParserLine(this, line)
123 | }
124 | return lines
125 | }
126 |
127 | companion object {
128 | const val TAGS_ALIGN_LEFT = "L"
129 | const val TAGS_ALIGN_CENTER = "C"
130 | const val TAGS_ALIGN_RIGHT = "R"
131 | val TAGS_ALIGN = arrayOf(TAGS_ALIGN_LEFT, TAGS_ALIGN_CENTER, TAGS_ALIGN_RIGHT)
132 | const val TAGS_IMAGE = "img"
133 | const val TAGS_BARCODE = "barcode"
134 | const val TAGS_QRCODE = "qrcode"
135 | const val ATTR_BARCODE_WIDTH = "width"
136 | const val ATTR_BARCODE_HEIGHT = "height"
137 | const val ATTR_BARCODE_TYPE = "type"
138 | const val ATTR_BARCODE_TYPE_EAN8 = "ean8"
139 | const val ATTR_BARCODE_TYPE_EAN13 = "ean13"
140 | const val ATTR_BARCODE_TYPE_UPCA = "upca"
141 | const val ATTR_BARCODE_TYPE_UPCE = "upce"
142 | const val ATTR_BARCODE_TYPE_128 = "128"
143 | const val ATTR_BARCODE_TEXT_POSITION = "text"
144 | const val ATTR_BARCODE_TEXT_POSITION_NONE = "none"
145 | const val ATTR_BARCODE_TEXT_POSITION_ABOVE = "above"
146 | const val ATTR_BARCODE_TEXT_POSITION_BELOW = "below"
147 | const val TAGS_FORMAT_TEXT_FONT = "font"
148 | const val TAGS_FORMAT_TEXT_BOLD = "b"
149 | const val TAGS_FORMAT_TEXT_UNDERLINE = "u"
150 | val TAGS_FORMAT_TEXT =
151 | arrayOf(TAGS_FORMAT_TEXT_FONT, TAGS_FORMAT_TEXT_BOLD, TAGS_FORMAT_TEXT_UNDERLINE)
152 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE = "type"
153 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE_NORMAL = "normal"
154 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE_DOUBLE = "double"
155 | const val ATTR_FORMAT_TEXT_FONT_SIZE = "size"
156 | const val ATTR_FORMAT_TEXT_FONT_SIZE_BIG = "big"
157 | const val ATTR_FORMAT_TEXT_FONT_SIZE_TALL = "tall"
158 | const val ATTR_FORMAT_TEXT_FONT_SIZE_WIDE = "wide"
159 | const val ATTR_FORMAT_TEXT_FONT_SIZE_NORMAL = "normal"
160 | const val ATTR_FORMAT_TEXT_FONT_COLOR = "color"
161 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BLACK = "black"
162 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BG_BLACK = "bg-black"
163 | const val ATTR_FORMAT_TEXT_FONT_COLOR_RED = "red"
164 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BG_RED = "bg-red"
165 | const val ATTR_QRCODE_SIZE = "size"
166 | var regexAlignTags: String? = null
167 | get() {
168 | if (field == null) {
169 | val regexAlignTags = StringBuilder()
170 | for (i in TAGS_ALIGN.indices) {
171 | regexAlignTags.append("|\\[").append(TAGS_ALIGN[i]).append("\\]")
172 | }
173 | field = regexAlignTags.toString().substring(1)
174 | }
175 | return field
176 | }
177 | private set
178 |
179 | @JvmStatic
180 | fun isTagTextFormat(oldTagName: String): Boolean {
181 | var tagName = oldTagName
182 | if (tagName.startsWith("/")) tagName = tagName.substring(1)
183 |
184 | for (tag in TAGS_FORMAT_TEXT) {
185 | if (tag == tagName) return true
186 | }
187 | return false
188 | }
189 |
190 | // fun arrayByteDropLast(arr: Array): Array {
191 | // if (arr.isEmpty()) return arr
192 | // System.arraycopy(arr, 0, arr, 0, arr.size)
193 | // return arr
194 | // }
195 |
196 | // fun arrayBytePush(arr: Array, add: ByteArray): Array {
197 | // var newArr = ArrayList()
198 | //
199 | // for (i in arr.indices) {
200 | // newArr[i] = arr[i]
201 | // }
202 | // System.arraycopy(arr, 0, arr, 0, arr.size)
203 | // Log.d("asdadada", "size: ${arr.size}")
204 | // arr[arr.size] = add
205 | // return newArr
206 | // }
207 |
208 | fun arrayByteDropLast(arr: Array): List {
209 | if (arr.isEmpty()) {
210 | return arr.toList()
211 | }
212 | val newArr = arrayOfNulls(arr.size - 1)
213 | System.arraycopy(arr, 0, newArr, 0, newArr.size)
214 | return newArr.filterNotNull()
215 | }
216 |
217 | //
218 | fun arrayBytePush(arr: Array, add: ByteArray): List {
219 | val newArr = arrayOfNulls(arr.size + 1)
220 | System.arraycopy(arr, 0, newArr, 0, arr.size)
221 | newArr[arr.size] = add
222 | return newArr.filterNotNull()
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/CoroutinesPrinterTextParser.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.CoroutinesEscPosPrinter
4 | import com.khairo.escposprinter.CoroutinesEscPosPrinterCommands
5 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
6 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
7 | import com.khairo.escposprinter.exceptions.EscPosParserException
8 |
9 | class CoroutinesPrinterTextParser(val printer: CoroutinesEscPosPrinter) {
10 | private var textSize = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_SIZE_NORMAL)
11 | private var textColor = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_COLOR_BLACK)
12 | private var textReverseColor = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_COLOR_REVERSE_OFF)
13 | private var textBold = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_WEIGHT_NORMAL)
14 | private var textUnderline = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_UNDERLINE_OFF)
15 | private var textDoubleStrike = arrayOf(CoroutinesEscPosPrinterCommands.TEXT_DOUBLE_STRIKE_OFF)
16 | private var text = ""
17 | fun setFormattedText(text: String): CoroutinesPrinterTextParser {
18 | this.text = text
19 | return this
20 | }
21 |
22 | val lastTextSize: ByteArray
23 | get() = textSize[textSize.size - 1]
24 |
25 | fun addTextSize(newTextSize: ByteArray): CoroutinesPrinterTextParser {
26 | textSize = arrayBytePush(textSize, newTextSize).toTypedArray()
27 | return this
28 | }
29 |
30 | fun dropLastTextSize(): CoroutinesPrinterTextParser {
31 | if (textSize.size > 1) {
32 | textSize = arrayByteDropLast(textSize).toTypedArray()
33 | }
34 | return this
35 | }
36 |
37 | val lastTextColor: ByteArray
38 | get() = textColor[textColor.size - 1]
39 |
40 | fun addTextColor(newTextColor: ByteArray): CoroutinesPrinterTextParser {
41 | textColor = arrayBytePush(textColor, newTextColor).toTypedArray()
42 | return this
43 | }
44 |
45 | fun dropLastTextColor(): CoroutinesPrinterTextParser {
46 | if (textColor.size > 1) {
47 | textColor = arrayByteDropLast(textColor).toTypedArray()
48 | }
49 | return this
50 | }
51 |
52 | val lastTextReverseColor: ByteArray
53 | get() = textReverseColor[textReverseColor.size - 1]
54 |
55 | fun addTextReverseColor(newTextReverseColor: ByteArray): CoroutinesPrinterTextParser {
56 | textReverseColor = arrayBytePush(textReverseColor, newTextReverseColor).toTypedArray()
57 | return this
58 | }
59 |
60 | fun dropLastTextReverseColor(): CoroutinesPrinterTextParser {
61 | if (textReverseColor.size > 1) {
62 | textReverseColor = arrayByteDropLast(textReverseColor).toTypedArray()
63 | }
64 | return this
65 | }
66 |
67 | val lastTextBold: ByteArray
68 | get() = textBold[textBold.size - 1]
69 |
70 | fun addTextBold(newTextBold: ByteArray): CoroutinesPrinterTextParser {
71 | textBold = arrayBytePush(textBold, newTextBold).toTypedArray()
72 | return this
73 | }
74 |
75 | fun dropTextBold(): CoroutinesPrinterTextParser {
76 | if (textBold.size > 1) {
77 | textBold = arrayByteDropLast(textBold).toTypedArray()
78 | }
79 | return this
80 | }
81 |
82 | val lastTextUnderline: ByteArray
83 | get() = textUnderline[textUnderline.size - 1]
84 |
85 | fun addTextUnderline(newTextUnderline: ByteArray): CoroutinesPrinterTextParser {
86 | textUnderline = arrayBytePush(textUnderline, newTextUnderline).toTypedArray()
87 | return this
88 | }
89 |
90 | fun dropLastTextUnderline(): CoroutinesPrinterTextParser {
91 | if (textUnderline.size > 1) {
92 | textUnderline = arrayByteDropLast(textUnderline).toTypedArray()
93 | }
94 | return this
95 | }
96 |
97 | val lastTextDoubleStrike: ByteArray
98 | get() = textDoubleStrike[textDoubleStrike.size - 1]
99 |
100 | fun addTextDoubleStrike(newTextDoubleStrike: ByteArray): CoroutinesPrinterTextParser {
101 | textDoubleStrike = arrayBytePush(textDoubleStrike, newTextDoubleStrike).toTypedArray()
102 | return this
103 | }
104 |
105 | fun dropLastTextDoubleStrike(): CoroutinesPrinterTextParser {
106 | if (textDoubleStrike.size > 1) {
107 | textDoubleStrike = arrayByteDropLast(textDoubleStrike).toTypedArray()
108 | }
109 | return this
110 | }
111 |
112 | @Throws(
113 | EscPosParserException::class,
114 | EscPosBarcodeException::class,
115 | EscPosEncodingException::class
116 | )
117 | fun parse(): Array {
118 | val stringLines = text.split("\n|\r\n".toRegex()).toTypedArray()
119 | val lines = arrayOfNulls(stringLines.size)
120 | var i = 0
121 | for (line in stringLines) {
122 | lines[i++] = CoroutinesPrinterTextParserLine(this, line)
123 | }
124 | return lines
125 | }
126 |
127 | companion object {
128 | const val TAGS_ALIGN_LEFT = "L"
129 | const val TAGS_ALIGN_CENTER = "C"
130 | const val TAGS_ALIGN_RIGHT = "R"
131 | val TAGS_ALIGN = arrayOf(TAGS_ALIGN_LEFT, TAGS_ALIGN_CENTER, TAGS_ALIGN_RIGHT)
132 | const val TAGS_IMAGE = "img"
133 | const val TAGS_BARCODE = "barcode"
134 | const val TAGS_QRCODE = "qrcode"
135 | const val ATTR_BARCODE_WIDTH = "width"
136 | const val ATTR_BARCODE_HEIGHT = "height"
137 | const val ATTR_BARCODE_TYPE = "type"
138 | const val ATTR_BARCODE_TYPE_EAN8 = "ean8"
139 | const val ATTR_BARCODE_TYPE_EAN13 = "ean13"
140 | const val ATTR_BARCODE_TYPE_UPCA = "upca"
141 | const val ATTR_BARCODE_TYPE_UPCE = "upce"
142 | const val ATTR_BARCODE_TYPE_128 = "128"
143 | const val ATTR_BARCODE_TEXT_POSITION = "text"
144 | const val ATTR_BARCODE_TEXT_POSITION_NONE = "none"
145 | const val ATTR_BARCODE_TEXT_POSITION_ABOVE = "above"
146 | const val ATTR_BARCODE_TEXT_POSITION_BELOW = "below"
147 | const val TAGS_FORMAT_TEXT_FONT = "font"
148 | const val TAGS_FORMAT_TEXT_BOLD = "b"
149 | const val TAGS_FORMAT_TEXT_UNDERLINE = "u"
150 | val TAGS_FORMAT_TEXT =
151 | arrayOf(TAGS_FORMAT_TEXT_FONT, TAGS_FORMAT_TEXT_BOLD, TAGS_FORMAT_TEXT_UNDERLINE)
152 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE = "type"
153 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE_NORMAL = "normal"
154 | const val ATTR_FORMAT_TEXT_UNDERLINE_TYPE_DOUBLE = "double"
155 | const val ATTR_FORMAT_TEXT_FONT_SIZE = "size"
156 | const val ATTR_FORMAT_TEXT_FONT_SIZE_BIG = "big"
157 | const val ATTR_FORMAT_TEXT_FONT_SIZE_TALL = "tall"
158 | const val ATTR_FORMAT_TEXT_FONT_SIZE_WIDE = "wide"
159 | const val ATTR_FORMAT_TEXT_FONT_SIZE_NORMAL = "normal"
160 | const val ATTR_FORMAT_TEXT_FONT_COLOR = "color"
161 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BLACK = "black"
162 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BG_BLACK = "bg-black"
163 | const val ATTR_FORMAT_TEXT_FONT_COLOR_RED = "red"
164 | const val ATTR_FORMAT_TEXT_FONT_COLOR_BG_RED = "bg-red"
165 | const val ATTR_QRCODE_SIZE = "size"
166 | var regexAlignTags: String? = null
167 | get() {
168 | if (field == null) {
169 | val regexAlignTags = StringBuilder()
170 | for (i in TAGS_ALIGN.indices) {
171 | regexAlignTags.append("|\\[").append(TAGS_ALIGN[i]).append("\\]")
172 | }
173 | field = regexAlignTags.toString().substring(1)
174 | }
175 | return field
176 | }
177 | private set
178 |
179 | @JvmStatic
180 | fun isTagTextFormat(oldTagName: String): Boolean {
181 | var tagName = oldTagName
182 | if (tagName.startsWith("/")) tagName = tagName.substring(1)
183 |
184 | for (tag in TAGS_FORMAT_TEXT) {
185 | if (tag == tagName) return true
186 | }
187 | return false
188 | }
189 |
190 | // fun arrayByteDropLast(arr: Array): Array {
191 | // if (arr.isEmpty()) return arr
192 | // System.arraycopy(arr, 0, arr, 0, arr.size)
193 | // return arr
194 | // }
195 |
196 | // fun arrayBytePush(arr: Array, add: ByteArray): Array {
197 | // var newArr = ArrayList()
198 | //
199 | // for (i in arr.indices) {
200 | // newArr[i] = arr[i]
201 | // }
202 | // System.arraycopy(arr, 0, arr, 0, arr.size)
203 | // Log.d("asdadada", "size: ${arr.size}")
204 | // arr[arr.size] = add
205 | // return newArr
206 | // }
207 |
208 | fun arrayByteDropLast(arr: Array): List {
209 | if (arr.isEmpty()) {
210 | return arr.toList()
211 | }
212 | val newArr = arrayOfNulls(arr.size - 1)
213 | System.arraycopy(arr, 0, newArr, 0, newArr.size)
214 | return newArr.filterNotNull()
215 | }
216 |
217 | //
218 | fun arrayBytePush(arr: Array, add: ByteArray): List {
219 | val newArr = arrayOfNulls(arr.size + 1)
220 | System.arraycopy(arr, 0, newArr, 0, arr.size)
221 | newArr[arr.size] = add
222 | return newArr.filterNotNull()
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/khairo/printer/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.printer.ui
2 |
3 | import android.Manifest
4 | import android.annotation.SuppressLint
5 | import android.app.AlertDialog
6 | import android.app.PendingIntent
7 | import android.content.BroadcastReceiver
8 | import android.content.Context
9 | import android.content.Intent
10 | import android.content.IntentFilter
11 | import android.content.pm.PackageManager
12 | import android.hardware.usb.UsbDevice
13 | import android.hardware.usb.UsbManager
14 | import android.os.AsyncTask
15 | import android.os.Bundle
16 | import android.os.Parcelable
17 | import android.util.DisplayMetrics
18 | import androidx.appcompat.app.AppCompatActivity
19 | import androidx.core.app.ActivityCompat
20 | import androidx.core.content.ContextCompat
21 | import androidx.databinding.DataBindingUtil
22 | import androidx.lifecycle.lifecycleScope
23 | import com.khairo.async.*
24 | import com.khairo.coroutines.CoroutinesEscPosPrint
25 | import com.khairo.coroutines.CoroutinesEscPosPrinter
26 | import com.khairo.escposprinter.EscPosPrinter
27 | import com.khairo.escposprinter.connection.DeviceConnection
28 | import com.khairo.escposprinter.connection.tcp.TcpConnection
29 | import com.khairo.escposprinter.connection.usb.UsbConnection
30 | import com.khairo.escposprinter.connection.usb.UsbPrintersConnections
31 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
32 | import com.khairo.escposprinter.exceptions.EscPosConnectionException
33 | import com.khairo.escposprinter.exceptions.EscPosEncodingException
34 | import com.khairo.escposprinter.exceptions.EscPosParserException
35 | import com.khairo.escposprinter.textparser.PrinterTextParserImg
36 | import com.khairo.printer.R
37 | import com.khairo.printer.databinding.ActivityMainBinding
38 | import com.khairo.printer.utils.printViaWifi
39 | import kotlinx.coroutines.Dispatchers
40 | import kotlinx.coroutines.launch
41 | import java.text.SimpleDateFormat
42 | import java.util.*
43 |
44 | class MainActivity : AppCompatActivity() {
45 |
46 | private lateinit var binding: ActivityMainBinding
47 |
48 | private var printer: CoroutinesEscPosPrinter? = null
49 |
50 | override fun onCreate(savedInstanceState: Bundle?) {
51 | super.onCreate(savedInstanceState)
52 | binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
53 |
54 | binding.apply {
55 | buttonTcp.setOnClickListener {
56 | lifecycleScope.launch(Dispatchers.IO) {
57 | printTcp()
58 | }
59 | }
60 |
61 | buttonBluetooth.setOnClickListener {
62 | printBluetooth()
63 | }
64 |
65 | buttonUsb.setOnClickListener {
66 | printUsb()
67 | }
68 | }
69 | }
70 |
71 | /*==============================================================================================
72 | ======================================BLUETOOTH PART============================================
73 | ==============================================================================================*/
74 | private val PERMISSION_BLUETOOTH = 1
75 |
76 | private fun printBluetooth() {
77 | if (ContextCompat.checkSelfPermission(
78 | this,
79 | Manifest.permission.BLUETOOTH
80 | ) != PackageManager.PERMISSION_GRANTED
81 | ) {
82 | ActivityCompat.requestPermissions(
83 | this,
84 | arrayOf(Manifest.permission.BLUETOOTH),
85 | PERMISSION_BLUETOOTH
86 | )
87 | } else {
88 | // this.printIt(BluetoothPrintersConnections.selectFirstPaired());
89 | AsyncBluetoothEscPosPrint(this).execute(this.getAsyncEscPosPrinter(null))
90 | }
91 | }
92 |
93 | override fun onRequestPermissionsResult(
94 | requestCode: Int,
95 | permissions: Array,
96 | grantResults: IntArray
97 | ) {
98 | if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
99 | when (requestCode) {
100 | PERMISSION_BLUETOOTH -> printBluetooth()
101 | }
102 | }
103 | }
104 |
105 | /*==============================================================================================
106 | ===========================================USB PART=============================================
107 | ==============================================================================================*/
108 | private val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
109 | private val usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
110 | override fun onReceive(context: Context, intent: Intent) {
111 | val action = intent.action
112 | if (ACTION_USB_PERMISSION == action) {
113 | synchronized(this) {
114 | val usbManager = getSystemService(USB_SERVICE) as UsbManager
115 | val usbDevice =
116 | intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) as UsbDevice?
117 | if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
118 | if (usbDevice != null) {
119 | // printIt(new UsbConnection(usbManager, usbDevice));
120 | AsyncUsbEscPosPrint(context)
121 | .execute(
122 | getAsyncEscPosPrinter(
123 | UsbConnection(
124 | usbManager,
125 | usbDevice
126 | )
127 | )
128 | )
129 | }
130 | }
131 | }
132 | }
133 | }
134 | }
135 |
136 | fun printUsb() {
137 | val usbConnection = UsbPrintersConnections.selectFirstConnected(this)
138 | val usbManager = this.getSystemService(USB_SERVICE) as UsbManager
139 | if (usbConnection == null) {
140 | AlertDialog.Builder(this)
141 | .setTitle("USB Connection")
142 | .setMessage("No USB printer found.")
143 | .show()
144 | return
145 | }
146 | val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)
147 | val filter = IntentFilter(ACTION_USB_PERMISSION)
148 | registerReceiver(usbReceiver, filter)
149 | usbManager.requestPermission(usbConnection.device, permissionIntent)
150 | }
151 |
152 | /*==============================================================================================
153 | ===================================ESC/POS PRINTER PART=========================================
154 | ==============================================================================================*/
155 | /**
156 | * Synchronous printing
157 | */
158 | @SuppressLint("SimpleDateFormat")
159 | fun printIt(printerConnection: DeviceConnection?) {
160 | AsyncTask.execute {
161 | try {
162 | val format = SimpleDateFormat("'on' yyyy-MM-dd 'at' HH:mm:ss")
163 | val printer = EscPosPrinter(
164 | printerConnection,
165 | 203,
166 | 48f,
167 | 32
168 | )
169 | printer
170 | .printFormattedText(
171 | "[C]
" + PrinterTextParserImg.bitmapToHexadecimalString(
172 | printer,
173 | applicationContext.resources.getDrawableForDensity(
174 | R.drawable.logo,
175 | DisplayMetrics.DENSITY_MEDIUM
176 | )
177 | ) + "\n" +
178 | "[L]\n" +
179 | "[C]ORDER N°045\n" +
180 | "[C]" + format.format(Date()) + "\n" +
181 | "[L]\n" +
182 | "[C]==================عربي تيست هههههههه==============\n" +
183 | "[L]\n" +
184 | "[L]BEAUTIFUL SHIRT[R]9.99e\n" +
185 | "[L] + Size : S\n" +
186 | "[L]\n" +
187 | "[L]AWESOME HAT[R]24.99e\n" +
188 | "[L] + Size : 57/58\n" +
189 | "[L]\n" +
190 | "[C]--------------------------------\n" +
191 | "[R]TOTAL PRICE :[R]34.98e\n" +
192 | "[R]TAX :[R]4.23e\n" +
193 | "[L]\n" +
194 | "[C]================================\n" +
195 | "[L]\n" +
196 | "[L]Customer :\n" +
197 | "[L]Raymond DUPONT\n" +
198 | "[L]5 rue des girafes\n" +
199 | "[L]31547 PERPETES\n" +
200 | "[L]Tel : +33801201456\n" +
201 | "[L]\n" +
202 | "[C]83125478455134567890\n" +
203 | "[C]http://www.developpeur-web.khairo.com/" +
204 | "[L]\n" +
205 | "[L]\n" +
206 | "[L]\n" +
207 | "[L]\n" +
208 | "[L]\n" +
209 | "[L]\n"
210 | )
211 | } catch (e: EscPosConnectionException) {
212 | e.printStackTrace()
213 | AlertDialog.Builder(this@MainActivity)
214 | .setTitle("Broken connection")
215 | .setMessage(e.message)
216 | .show()
217 | } catch (e: EscPosParserException) {
218 | e.printStackTrace()
219 | AlertDialog.Builder(this@MainActivity)
220 | .setTitle("Invalid formatted text")
221 | .setMessage(e.message)
222 | .show()
223 | } catch (e: EscPosEncodingException) {
224 | e.printStackTrace()
225 | AlertDialog.Builder(this@MainActivity)
226 | .setTitle("Bad selected encoding")
227 | .setMessage(e.message)
228 | .show()
229 | } catch (e: EscPosBarcodeException) {
230 | e.printStackTrace()
231 | AlertDialog.Builder(this@MainActivity)
232 | .setTitle("Invalid barcode")
233 | .setMessage(e.message)
234 | .show()
235 | }
236 | }
237 | }
238 |
239 | /**
240 | * Asynchronous printing
241 | */
242 | @SuppressLint("SimpleDateFormat")
243 | fun getAsyncEscPosPrinter(printerConnection: DeviceConnection?): AsyncEscPosPrinter {
244 | val format = SimpleDateFormat("'on' yyyy-MM-dd 'at' HH:mm:ss")
245 | val printer = AsyncEscPosPrinter(printerConnection!!, 203, 48f, 32)
246 | return printer.setTextToPrint(
247 | "[C]
" + PrinterTextParserImg.bitmapToHexadecimalString(
248 | printer,
249 | this.applicationContext.resources.getDrawableForDensity(
250 | R.drawable.logo,
251 | DisplayMetrics.DENSITY_MEDIUM
252 | )
253 | ) + "\n" +
254 | "[L]\n" +
255 | "[C]ORDER N°045\n" +
256 | "[L]\n" +
257 | "[C]" + format.format(Date()) + "\n" +
258 | "[C]\n" +
259 | "[C]================================\n" +
260 | "[L]\n" +
261 | "[L]BEAUTIFUL SHIRT[R]9.99e\n" +
262 | "[L] + Size : S\n" +
263 | "[L]\n" +
264 | "[L]AWESOME HAT[R]24.99e\n" +
265 | "[L] + Size : 57/58\n" +
266 | "[L]\n" +
267 | "[C]--------------------------------\n" +
268 | "[R]TOTAL PRICE :[R]34.98e\n" +
269 | "[R]TAX :[R]4.23e\n" +
270 | "[L]\n" +
271 | "[C]================================\n" +
272 | "[L]\n" +
273 | "[L]Customer :\n" +
274 | "[L]Raymond DUPONT\n" +
275 | "[L]5 rue des girafes\n" +
276 | "[L]31547 PERPETES\n" +
277 | "[L]Tel : +33801201456\n" +
278 | "\n" +
279 | "[C]83125478455134567890\n" +
280 | "[L]\n" +
281 | "[C]http://www.developpeur-web.khairo.com/\n" +
282 | "[L]\n" +
283 | "[L]\n" +
284 | "[L]\n" +
285 | "[L]\n" +
286 | "[L]\n" +
287 | "[L]\n"
288 | )
289 | }
290 |
291 | /*==============================================================================================
292 | =========================================TCP PART===============================================
293 | ==============================================================================================*/
294 | private suspend fun printTcp() {
295 | try {
296 | printer =
297 | CoroutinesEscPosPrinter(
298 | TcpConnection(
299 | binding.tcpIp.text.toString(),
300 | binding.tcpPort.text.toString().toInt()
301 | ).apply { connect(this@MainActivity) }, 203, 48f, 32
302 | )
303 |
304 | // this.printIt(new TcpConnection(ipAddress.getText().toString(), Integer.parseInt(portAddress.getText().toString())));
305 | // AsyncTcpEscPosPrint(this).execute(printer.setTextToPrint(test))
306 |
307 | CoroutinesEscPosPrint(this).execute(
308 | printViaWifi(
309 | printer!!,
310 | 45,
311 | body,
312 | 34.98f,
313 | 4,
314 | customer,
315 | "83125478455134567890"
316 | )
317 | ).apply { printer = null }
318 |
319 | } catch (e: NumberFormatException) {
320 | AlertDialog.Builder(this)
321 | .setTitle("Invalid TCP port address")
322 | .setMessage("Port field must be a number.")
323 | .show()
324 | e.printStackTrace()
325 | }
326 | }
327 |
328 | private val body: String
329 | get() = "[L]\n" +
330 | "[L] Pizza[R][R]3[R][R]55 $\n" +
331 | "[L] + Olive[R][R]1 $\n" +
332 | "[L] + Cheese[R][R]5 $\n" +
333 | "[L] + Mushroom[R][R]7 $\n" +
334 | "[L]\n" +
335 | "[L] Burger[R][R]7[R][R]43.54 $\n" +
336 | "[L] + Cheese[R][R]3 $\n" +
337 | "[L]\n" +
338 | "[L] Shawarma[R][R]2[R][R]4 $\n" +
339 | "[L] + Garlic[R][R]0.5 $\n" +
340 | "[L]\n" +
341 | "[L] Steak[R][R]3[R][R]75 $\n" +
342 | "[L]\n" +
343 | "[R] PAYMENT METHOD :[R]Visa\n"
344 |
345 | private val customer: String
346 | get() =
347 | "[C]================================\n" +
348 | "[L]\n" +
349 | "[L]Delivery[R]5 $\n" +
350 | "[L]\n" +
351 | "[L]Customer :\n" +
352 | "[L]Name : Mohammad khair\n" +
353 | "[L]Phone : 00962787144627\n" +
354 | "[L]Area : Khalda\n" +
355 | "[L]street : testing street\n" +
356 | "[L]building : 9\n" +
357 | "[L]Floor : 2\n" +
358 | "[L]Apartment : 1\n" +
359 | "[L]Note : This order is just for testing\n"
360 | }
361 |
--------------------------------------------------------------------------------
/escposprinter/src/main/java/com/khairo/escposprinter/textparser/PrinterTextParserColumn.kt:
--------------------------------------------------------------------------------
1 | package com.khairo.escposprinter.textparser
2 |
3 | import com.khairo.escposprinter.EscPosPrinterCommands
4 | import com.khairo.escposprinter.exceptions.EscPosBarcodeException
5 | import com.khairo.escposprinter.exceptions.EscPosParserException
6 | import com.khairo.escposprinter.textparser.PrinterTextParser.Companion.isTagTextFormat
7 | import java.util.*
8 | import kotlin.math.floor
9 |
10 | /**
11 | * Create a new instance of PrinterTextParserColumn.
12 | *
13 | * @param textParserLine Parent PrinterTextParserLine instance
14 | * @param oldTextColumn Text that the column contain
15 | */
16 | class PrinterTextParserColumn(textParserLine: PrinterTextParserLine, oldTextColumn: String) {
17 | val line: PrinterTextParserLine
18 | var elements = arrayOfNulls(0)
19 | private set
20 |
21 | private fun prependString(text: String): PrinterTextParserColumn {
22 | val textParser = line.textParser
23 | return this.prependString(
24 | text,
25 | textParser.lastTextSize,
26 | textParser.lastTextColor,
27 | textParser.lastTextReverseColor,
28 | textParser.lastTextBold,
29 | textParser.lastTextUnderline,
30 | textParser.lastTextDoubleStrike
31 | )
32 | }
33 |
34 | private fun prependString(
35 | text: String,
36 | textSize: ByteArray?,
37 | textColor: ByteArray?,
38 | textReverseColor: ByteArray?,
39 | textBold: ByteArray?,
40 | textUnderline: ByteArray?,
41 | textDoubleStrike: ByteArray?
42 | ): PrinterTextParserColumn {
43 | return prependElement(
44 | PrinterTextParserString(
45 | this,
46 | text,
47 | textSize!!,
48 | textColor!!,
49 | textReverseColor!!,
50 | textBold!!,
51 | textUnderline!!,
52 | textDoubleStrike!!
53 | )
54 | )
55 | }
56 |
57 | private fun appendString(text: String): PrinterTextParserColumn {
58 | val textParser = line.textParser
59 | return this.appendString(
60 | text,
61 | textParser.lastTextSize,
62 | textParser.lastTextColor,
63 | textParser.lastTextReverseColor,
64 | textParser.lastTextBold,
65 | textParser.lastTextUnderline,
66 | textParser.lastTextDoubleStrike
67 | )
68 | }
69 |
70 | private fun appendString(
71 | text: String,
72 | textSize: ByteArray?,
73 | textColor: ByteArray?,
74 | textReverseColor: ByteArray?,
75 | textBold: ByteArray?,
76 | textUnderline: ByteArray?,
77 | textDoubleStrike: ByteArray?
78 | ): PrinterTextParserColumn {
79 | val printer = line.textParser.printer
80 | return this.appendElement(
81 | PrinterTextParserString(
82 | this,
83 | text,
84 | textSize!!,
85 | textColor!!,
86 | textReverseColor!!,
87 | textBold!!,
88 | textUnderline!!,
89 | textDoubleStrike!!
90 | )
91 | )
92 | }
93 |
94 | private fun prependImage(textAlign: String, hexString: String): PrinterTextParserColumn {
95 | return prependElement(
96 | PrinterTextParserImg(
97 | this,
98 | textAlign,
99 | hexString
100 | )
101 | )
102 | }
103 |
104 | private fun appendImage(textAlign: String, hexString: String): PrinterTextParserColumn {
105 | return this.appendElement(
106 | PrinterTextParserImg(
107 | this,
108 | textAlign,
109 | hexString
110 | )
111 | )
112 | }
113 |
114 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
115 | private fun prependBarcode(
116 | textAlign: String,
117 | barcodeAttributes: Hashtable,
118 | code: String
119 | ): PrinterTextParserColumn {
120 | return prependElement(PrinterTextParserBarcode(this, textAlign, barcodeAttributes, code))
121 | }
122 |
123 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
124 | private fun appendBarcode(
125 | textAlign: String,
126 | barcodeAttributes: Hashtable,
127 | code: String
128 | ): PrinterTextParserColumn {
129 | return this.appendElement(
130 | PrinterTextParserBarcode(
131 | this,
132 | textAlign,
133 | barcodeAttributes,
134 | code
135 | )
136 | )
137 | }
138 |
139 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
140 | private fun prependQRCode(
141 | textAlign: String,
142 | qrCodeAttributes: Hashtable,
143 | data: String
144 | ): PrinterTextParserColumn {
145 | return prependElement(PrinterTextParserBarcode(this, textAlign, qrCodeAttributes, data))
146 | }
147 |
148 | @Throws(EscPosParserException::class, EscPosBarcodeException::class)
149 | private fun appendQRCode(
150 | textAlign: String,
151 | qrCodeAttributes: Hashtable,
152 | data: String
153 | ): PrinterTextParserColumn {
154 | return this.appendElement(PrinterTextParserQRCode(this, textAlign, qrCodeAttributes, data))
155 | }
156 |
157 | private fun prependElement(element: IPrinterTextParserElement): PrinterTextParserColumn {
158 | val elementsTmp = arrayOfNulls(elements.size + 1)
159 | elementsTmp[0] = element
160 | System.arraycopy(elements, 0, elementsTmp, 1, elements.size)
161 | elements = elementsTmp
162 | return this
163 | }
164 |
165 | private fun appendElement(element: IPrinterTextParserElement): PrinterTextParserColumn {
166 | val elementsTmp = arrayOfNulls(elements.size + 1)
167 | System.arraycopy(elements, 0, elementsTmp, 0, elements.size)
168 | elementsTmp[elements.size] = element
169 | elements = elementsTmp
170 | return this
171 | }
172 |
173 | companion object {
174 | private fun generateSpace(nbrSpace: Int): String {
175 | val str = StringBuilder()
176 | for (i in 0 until nbrSpace) {
177 | str.append(" ")
178 | }
179 | return str.toString()
180 | }
181 | }
182 |
183 | init {
184 | var textColumn = oldTextColumn
185 | line = textParserLine
186 | val textParser = line.textParser
187 | var textAlign = PrinterTextParser.TAGS_ALIGN_LEFT
188 | val textUnderlineStartColumn = textParser.lastTextUnderline
189 | val textDoubleStrikeStartColumn = textParser.lastTextDoubleStrike
190 | val textColorStartColumn = textParser.lastTextColor
191 | val textReverseColorStartColumn = textParser.lastTextReverseColor
192 |
193 |
194 | // =================================================================
195 | // Check the column alignment
196 | if (textColumn.length > 2) {
197 | when (textColumn.substring(0, 3).toUpperCase(Locale.ROOT)) {
198 | "[" + PrinterTextParser.TAGS_ALIGN_LEFT + "]", "[" + PrinterTextParser.TAGS_ALIGN_CENTER + "]", "[" + PrinterTextParser.TAGS_ALIGN_RIGHT + "]" -> {
199 | textAlign = textColumn.substring(1, 2).toUpperCase(Locale.ROOT)
200 | textColumn = textColumn.substring(3)
201 | }
202 | }
203 | }
204 | val trimmedTextColumn = textColumn.trim { it <= ' ' }
205 | var isImgOrBarcodeLine = false
206 | if (line.nbrColumns == 1 && trimmedTextColumn.indexOf("<") == 0) {
207 | // =================================================================
208 | // Image or Barcode Lines
209 | val openTagIndex = trimmedTextColumn.indexOf("<")
210 | val openTagEndIndex = trimmedTextColumn.indexOf(">", openTagIndex + 1) + 1
211 | if (openTagIndex < openTagEndIndex) {
212 | val textParserTag =
213 | PrinterTextParserTag(trimmedTextColumn.substring(openTagIndex, openTagEndIndex))
214 | when (textParserTag.tagName) {
215 | PrinterTextParser.TAGS_IMAGE, PrinterTextParser.TAGS_BARCODE, PrinterTextParser.TAGS_QRCODE -> {
216 | val closeTag = "" + textParserTag.tagName + ">"
217 | val closeTagPosition = trimmedTextColumn.length - closeTag.length
218 | if (trimmedTextColumn.substring(closeTagPosition) == closeTag) {
219 | when (textParserTag.tagName) {
220 | PrinterTextParser.TAGS_IMAGE -> appendImage(
221 | textAlign,
222 | trimmedTextColumn.substring(openTagEndIndex, closeTagPosition)
223 | )
224 | PrinterTextParser.TAGS_BARCODE -> appendBarcode(
225 | textAlign,
226 | textParserTag.attributes,
227 | trimmedTextColumn.substring(openTagEndIndex, closeTagPosition)
228 | )
229 | PrinterTextParser.TAGS_QRCODE -> appendQRCode(
230 | textAlign,
231 | textParserTag.attributes,
232 | trimmedTextColumn.substring(openTagEndIndex, closeTagPosition)
233 | )
234 | }
235 | isImgOrBarcodeLine = true
236 | }
237 | }
238 | }
239 | }
240 | }
241 | if (!isImgOrBarcodeLine) {
242 | // =================================================================
243 | // If the tag is for format text
244 | var offset = 0
245 | while (true) {
246 | var openTagIndex = textColumn.indexOf("<", offset)
247 | var closeTagIndex = -1
248 | if (openTagIndex != -1) {
249 | closeTagIndex = textColumn.indexOf(">", openTagIndex)
250 | } else {
251 | openTagIndex = textColumn.length
252 | }
253 | this.appendString(textColumn.substring(offset, openTagIndex))
254 | if (closeTagIndex == -1) {
255 | break
256 | }
257 | closeTagIndex++
258 | val textParserTag =
259 | PrinterTextParserTag(textColumn.substring(openTagIndex, closeTagIndex))
260 | offset = if (isTagTextFormat(textParserTag.tagName)) {
261 | if (textParserTag.isCloseTag) {
262 | when (textParserTag.tagName) {
263 | PrinterTextParser.TAGS_FORMAT_TEXT_BOLD -> textParser.dropTextBold()
264 | PrinterTextParser.TAGS_FORMAT_TEXT_UNDERLINE -> {
265 | textParser.dropLastTextUnderline()
266 | textParser.dropLastTextDoubleStrike()
267 | }
268 | PrinterTextParser.TAGS_FORMAT_TEXT_FONT -> {
269 | textParser.dropLastTextSize()
270 | textParser.dropLastTextColor()
271 | textParser.dropLastTextReverseColor()
272 | }
273 | }
274 | } else {
275 | when (textParserTag.tagName) {
276 | PrinterTextParser.TAGS_FORMAT_TEXT_BOLD -> textParser.addTextBold(
277 | EscPosPrinterCommands.TEXT_WEIGHT_BOLD
278 | )
279 | PrinterTextParser.TAGS_FORMAT_TEXT_UNDERLINE -> if (textParserTag.hasAttribute(
280 | PrinterTextParser.ATTR_FORMAT_TEXT_UNDERLINE_TYPE
281 | )
282 | ) {
283 | when (textParserTag.getAttribute(PrinterTextParser.ATTR_FORMAT_TEXT_UNDERLINE_TYPE)) {
284 | PrinterTextParser.ATTR_FORMAT_TEXT_UNDERLINE_TYPE_NORMAL -> {
285 | textParser.addTextUnderline(EscPosPrinterCommands.TEXT_UNDERLINE_LARGE)
286 | textParser.addTextDoubleStrike(textParser.lastTextDoubleStrike)
287 | }
288 | PrinterTextParser.ATTR_FORMAT_TEXT_UNDERLINE_TYPE_DOUBLE -> {
289 | textParser.addTextUnderline(textParser.lastTextUnderline)
290 | textParser.addTextDoubleStrike(EscPosPrinterCommands.TEXT_DOUBLE_STRIKE_ON)
291 | }
292 | }
293 | } else {
294 | textParser.addTextUnderline(EscPosPrinterCommands.TEXT_UNDERLINE_LARGE)
295 | textParser.addTextDoubleStrike(textParser.lastTextDoubleStrike)
296 | }
297 | PrinterTextParser.TAGS_FORMAT_TEXT_FONT -> {
298 | if (textParserTag.hasAttribute(PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE)) {
299 | when (textParserTag.getAttribute(PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE)) {
300 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE_NORMAL -> textParser.addTextSize(
301 | EscPosPrinterCommands.TEXT_SIZE_NORMAL
302 | )
303 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE_TALL -> textParser.addTextSize(
304 | EscPosPrinterCommands.TEXT_SIZE_DOUBLE_HEIGHT
305 | )
306 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE_WIDE -> textParser.addTextSize(
307 | EscPosPrinterCommands.TEXT_SIZE_DOUBLE_WIDTH
308 | )
309 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_SIZE_BIG -> textParser.addTextSize(
310 | EscPosPrinterCommands.TEXT_SIZE_BIG
311 | )
312 | else -> textParser.addTextSize(EscPosPrinterCommands.TEXT_SIZE_NORMAL)
313 | }
314 | } else {
315 | textParser.addTextSize(textParser.lastTextSize)
316 | }
317 | if (textParserTag.hasAttribute(PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR)) {
318 | when (textParserTag.getAttribute(PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR)) {
319 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR_BLACK -> {
320 | textParser.addTextColor(EscPosPrinterCommands.TEXT_COLOR_BLACK)
321 | textParser.addTextReverseColor(EscPosPrinterCommands.TEXT_COLOR_REVERSE_OFF)
322 | }
323 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR_BG_BLACK -> {
324 | textParser.addTextColor(EscPosPrinterCommands.TEXT_COLOR_BLACK)
325 | textParser.addTextReverseColor(EscPosPrinterCommands.TEXT_COLOR_REVERSE_ON)
326 | }
327 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR_RED -> {
328 | textParser.addTextColor(EscPosPrinterCommands.TEXT_COLOR_RED)
329 | textParser.addTextReverseColor(EscPosPrinterCommands.TEXT_COLOR_REVERSE_OFF)
330 | }
331 | PrinterTextParser.ATTR_FORMAT_TEXT_FONT_COLOR_BG_RED -> {
332 | textParser.addTextColor(EscPosPrinterCommands.TEXT_COLOR_RED)
333 | textParser.addTextReverseColor(EscPosPrinterCommands.TEXT_COLOR_REVERSE_ON)
334 | }
335 | else -> {
336 | textParser.addTextColor(EscPosPrinterCommands.TEXT_COLOR_BLACK)
337 | textParser.addTextReverseColor(EscPosPrinterCommands.TEXT_COLOR_REVERSE_OFF)
338 | }
339 | }
340 | } else {
341 | textParser.addTextColor(textParser.lastTextColor)
342 | textParser.addTextReverseColor(textParser.lastTextReverseColor)
343 | }
344 | }
345 | }
346 | }
347 | closeTagIndex
348 | } else {
349 | this.appendString("<")
350 | openTagIndex + 1
351 | }
352 | }
353 |
354 | // =================================================================
355 | // Define the number of spaces required for the different alignments
356 | val nbrCharColumn = line.nbrCharColumn
357 | var nbrCharForgetted = line.nbrCharForgetted
358 | var nbrCharColumnExceeded = line.nbrCharColumnExceeded
359 | var nbrCharTextWithoutTag = 0
360 | var leftSpace = 0
361 | var rightSpace = 0
362 | for (textParserElement in elements) {
363 | nbrCharTextWithoutTag += textParserElement!!.length()
364 | }
365 | when (textAlign) {
366 | PrinterTextParser.TAGS_ALIGN_LEFT -> rightSpace =
367 | nbrCharColumn - nbrCharTextWithoutTag
368 | PrinterTextParser.TAGS_ALIGN_CENTER -> {
369 | leftSpace =
370 | floor(((nbrCharColumn.toFloat() - nbrCharTextWithoutTag.toFloat()) / 2f).toDouble())
371 | .toInt()
372 | rightSpace = nbrCharColumn - nbrCharTextWithoutTag - leftSpace
373 | }
374 | PrinterTextParser.TAGS_ALIGN_RIGHT -> leftSpace =
375 | nbrCharColumn - nbrCharTextWithoutTag
376 | }
377 | if (nbrCharForgetted > 0) {
378 | nbrCharForgetted -= 1
379 | rightSpace++
380 | }
381 | if (nbrCharColumnExceeded < 0) {
382 | leftSpace += nbrCharColumnExceeded
383 | nbrCharColumnExceeded = 0
384 | if (leftSpace < 1) {
385 | rightSpace += leftSpace - 1
386 | leftSpace = 1
387 | }
388 | }
389 | if (leftSpace < 0) {
390 | nbrCharColumnExceeded += leftSpace
391 | leftSpace = 0
392 | }
393 | if (rightSpace < 0) {
394 | nbrCharColumnExceeded += rightSpace
395 | rightSpace = 0
396 | }
397 | if (leftSpace > 0) {
398 | this.prependString(
399 | generateSpace(leftSpace),
400 | EscPosPrinterCommands.TEXT_SIZE_NORMAL,
401 | textColorStartColumn,
402 | textReverseColorStartColumn,
403 | EscPosPrinterCommands.TEXT_WEIGHT_NORMAL,
404 | textUnderlineStartColumn,
405 | textDoubleStrikeStartColumn
406 | )
407 | }
408 | if (rightSpace > 0) {
409 | this.appendString(
410 | generateSpace(rightSpace),
411 | EscPosPrinterCommands.TEXT_SIZE_NORMAL,
412 | textParser.lastTextColor,
413 | textParser.lastTextReverseColor,
414 | EscPosPrinterCommands.TEXT_WEIGHT_NORMAL,
415 | textParser.lastTextUnderline,
416 | textParser.lastTextDoubleStrike
417 | )
418 | }
419 |
420 | // =================================================================================================
421 | // nbrCharForgetted and nbrCharColumnExceeded is use to define number of spaces for the next columns
422 | line
423 | .setNbrCharForgetted(nbrCharForgetted)
424 | .setNbrCharColumnExceeded(nbrCharColumnExceeded)
425 | }
426 | }
427 | }
--------------------------------------------------------------------------------