kotlin 如何通过Wifi/Bleutooth打印机打印PDF?

cetgtptt  于 2023-03-03  发布在  Kotlin
关注(0)|答案(1)|浏览(320)

我想通过Wifi/Bleutooth打印机打印PDF文件,但在此之前,我想连接到打印机
我已经尝试了一种方法来做到这一点,但问题是我的打印机尺寸小于pdf页面大小(A4)
如何使文件与所有大小的打印机兼容?
下面是一些代码:

private fun savePdf(
            invoiceType: String,
            invoiceModel: SalesDatabase,
            date: String,
            personType: String,
            personName: String,
            paymentMethod: String
        ) {

            val am: AssetManager = context.assets
            var font: PdfFont?
            try {
                am.open("text.ttf").use { inStream ->
                    val buffer = ByteArrayOutputStream()
                    var nRead: Int
                    val data = ByteArray(16384)
                    while (inStream.read(data, 0, data.size).also { nRead = it } != -1) {
                        buffer.write(data, 0, nRead)
                    }
                    font = PdfFontFactory.createFont(buffer.toByteArray(), PdfEncodings.UTF8)
                }
            } catch (e: Exception) {
                Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
                return
            }

            val mFileName = SimpleDateFormat(
                "yyyyMMdd_HHmmss",
                Locale.getDefault()
            ).format(System.currentTimeMillis())
            val mFilePath =
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
                    .toString() + "/" + "$invoiceType Invoice" + mFileName + ".pdf"
            val file = File(mFilePath)
            file.createNewFile()
            val outputStream: OutputStream = FileOutputStream(file)
            val pdfWriter = PdfWriter(outputStream)
            val pdfDocument = PdfDocument(pdfWriter)
            val mDoc = Document(pdfDocument)
            try {
                if (file.exists()) {

                    //Setting
                    mDoc.pdfDocument.defaultPageSize = PageSize.A4

                    val typeInvoice = "Invoice $invoiceType"
                    val text =
                        Paragraph(typeInvoice).setBold().setFontColor(ColorConstants.BLACK)
                            .setFont(font).setTextAlignment(TextAlignment.CENTER).setFontSize(22f)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)

                    val textWidth = PageSize.A4.width
                    val table1 = Table(FloatArray(1) { textWidth })
                    table1.addCell(
                        Cell().add(text)
                            .setBorder(Border.NO_BORDER)
                            .setHorizontalAlignment(HorizontalAlignment.CENTER)
                            .setTextAlignment(TextAlignment.CENTER)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    )

                    mDoc.add(table1)

                    addLineSpace(mDoc)

                    val width = PageSize.A4.width / 3
                    val columns = FloatArray(3)
                    columns[0] = width
                    columns[1] = width
                    columns[2] = width
                    val infoTable = Table(columns)
                    val theDate =
                        Paragraph("Date : $date").setBold().setFont(font)
                            .setFontColor(ColorConstants.BLACK)
                            .setTextAlignment(TextAlignment.CENTER).setFontSize(12f)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    val theTypeName =
                        Paragraph("$personType Name: $personName").setBold().setFont(font)
                            .setFontColor(ColorConstants.BLACK)
                            .setTextAlignment(TextAlignment.CENTER).setFontSize(12f)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    val thePaymentType =
                        Paragraph("Payment method : $paymentMethod").setBold().setFont(font)
                            .setFontColor(ColorConstants.BLACK)
                            .setTextAlignment(TextAlignment.CENTER).setFontSize(12f)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)

                    infoTable.addCell(
                        Cell().add(theDate)
                            .setBorder(Border.NO_BORDER)
                            .setHorizontalAlignment(HorizontalAlignment.CENTER)
                            .setTextAlignment(TextAlignment.CENTER)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    )
                    infoTable.addCell(
                        Cell().add(theTypeName)
                            .setBorder(Border.NO_BORDER)
                            .setHorizontalAlignment(HorizontalAlignment.CENTER)
                            .setTextAlignment(TextAlignment.CENTER)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    )
                    infoTable.addCell(
                        Cell().add(thePaymentType)
                            .setBorder(Border.NO_BORDER)
                            .setHorizontalAlignment(HorizontalAlignment.CENTER)
                            .setTextAlignment(TextAlignment.CENTER)
                            .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    )

                    mDoc.add(infoTable)

                    addLineSpace(mDoc)
                    addLineSeparator(mDoc)
                    addLineSpace(mDoc)

                    addTable(mDoc, invoiceModel, font)
                }

                mDoc.close()

                showPleaseWaitDialog(false, "")
                Toast.makeText(context, "تم إنشاء الملف", Toast.LENGTH_LONG).show()
                Toast.makeText(context, "تم حفظ الملف في $mFilePath", Toast.LENGTH_LONG).show()

                Handler().postDelayed({
//                    val intent = Intent(context, ShowPdf::class.java)
//                    intent.putExtra("pdfUrl", mFilePath)
//                    context.startActivity(intent)

                    printPDF(file)
                }, 1000)
            } catch (e: Exception) {
                Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
            }
        }
private fun printPDF(file: File) {
            if (OptionDatabase.isWifiMode(context)) {
                val printManager: PrintManager? =
                    getSystemService(context, PrintManager::class.java)
                try {
                    val printDocumentAdapter: PrintDocumentAdapter =
                        PdfDocumentAdapter(context, file.path)
                    printManager!!.print(
                        "Document",
                        printDocumentAdapter,
                        PrintAttributes.Builder().build()
                    )
                } catch (ex: java.lang.Exception) {
                    Toast.makeText(context, "Can't read pdf file", Toast.LENGTH_SHORT).show()
                }
                return
            }
            if (OptionDatabase.isBluetoothMode(context)) {
                Printooth.printer().printingCallback = this
                Printooth.printer().print(pdfToBitmap(file))
                return
            }
        }
private fun pdfToBitmap(pdfFile: File): ArrayList<Printable> {
            val bitmaps = ArrayList<Printable>()
            try {
                val renderer = PdfRenderer(
                    ParcelFileDescriptor.open(
                        pdfFile,
                        ParcelFileDescriptor.MODE_READ_ONLY
                    )
                )
                var bitmap: Bitmap
                val pageCount = renderer.pageCount
                for (i in 0 until pageCount) {
                    val page = renderer.openPage(i)
                    val width: Int =
                        resources.displayMetrics.densityDpi / 72 * page.width
                    val height: Int =
                        resources.displayMetrics.densityDpi / 72 * page.height
                    bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
                    page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
                    bitmaps.add(ImagePrintable.Builder(bitmap).build())

                    // close the page
                    page.close()
                }

                // close the renderer
                renderer.close()
            } catch (ex: java.lang.Exception) {
                context.showToast(ex.message.toString(), 0)
            }
            return bitmaps
        }
private fun addTable(document: Document, invoiceModel: PurchaseDatabase, font: PdfFont?) {

            val columns = FloatArray(5)
            columns[0] = 30f
            columns[1] = (PageSize.A4.width - 30f) / 4
            columns[2] = (PageSize.A4.width - 30f) / 4
            columns[3] = (PageSize.A4.width - 30f) / 4
            columns[4] = (PageSize.A4.width - 30f) / 4

            val table = Table(columns).setMarginBottom(20f)

            addCell(table, "", font!!, true)
            addCell(table, "Product Name", font, true)
            addCell(table, "Price", font, true)
            addCell(table, "Quantity", font, true)
            addCell(table, "Total", font, true)

            val myType = object : TypeToken<ArrayList<ProductBuyModel>>() {}.type
            val products =
                Gson().fromJson<ArrayList<ProductBuyModel>>(invoiceModel.products, myType)

            for (s in products.indices) {
                addCell(table, (s + 1).toString(), font, false)
                addCell(table, products[s].productName, font, false)
                val price =
                    (products[s].productPrixTotal - products[s].productTax) / products[s].productQuantity
                addCell(table, price.toString(), font, false)
                addCell(table, products[s].productQuantity.toString(), font, false)
                addCell(table, products[s].productPrixTotal.toString(), font, false)
            }

            addCell(table, "", font, false)
            addCell(table, "", font, false)
            addCell(table, "Payment : ${invoiceModel.paymentPrice}", font, true)
            addCell(table, "Rest : ${invoiceModel.restPrice}", font, true)
            addCell(table, "Total : ${invoiceModel.totalPrice}", font, true)

            table.setBackgroundColor(ColorConstants.WHITE)
            table.isKeepTogether = true
            document.add(table)
        }

当我尝试我的代码时,结果如下:

mzillmmw

mzillmmw1#

您使用的是哪种类型的打印机?与使用Windows打印驱动程序打印相比,使用这些连接到Android的小型移动的打印机打印可能会有点棘手。
根据型号的不同,这台打印机将有一个本地语言(Zebra有Zebra打印语言又名ZPL,是最流行的语言之一)。通常你不会打印原始PDF,而是发送嵌入在ZPL /本地打印机语言中的打印数据。虽然这听起来很复杂,但它确实使一些事情变得容易(特别是当需要条形码时)。Zebra打印语言信息供参考
大小普遍可能有点坚韧,因为大多数打印机的索引点(绝对)和利用不同的字体/大小。我想这可以做到,但我还没有看到它。
在这两种情况下,连接都非常简单。您可以简单地ping IP打印机,然后打开一个套接字并发送打印流。对于蓝牙,您可以打开一个蓝牙套接字,然后关闭它,从而找出它是否存在和在线。下面的代码假设您有一个打印机列表和它们的地址(IP或蓝牙)。注意:下面的代码应该封装在一个AsyncTask doinbackground方法中,并且假设你的原始打印数据在params 1元素中。另外,下面的代码是Java的,但是Kotlin转换应该非常简单!

//region BT
            if (is_bluetooth()){

                try{
                    status = "Printing";
                    if (bt_dev == null){
                        bta = BluetoothAdapter.getDefaultAdapter();
                        bt_dev = bta.getRemoteDevice(address);
                    }
                    bt_socket = bt_dev.createInsecureRfcommSocketToServiceRecord(MY_UUID);
                    bt_socket.connect();
                }
                catch (IOException ex){
                    errs.add("Could not create BT Socket");
                    Log.e("ERR", "doInBackground: ", ex);
                    status = "Ready";
                    return "!Could not create BT Socket";
                }

                try{
                    os = bt_socket.getOutputStream();
                }
                catch (IOException ex){
                    errs.add("Could not connect BT Socket");
                    Log.e("ERR", "doInBackground: ", ex);
                    status = "Ready";
                    return "!Could not connect BT Socket";
                }

                try{
                    Thread.sleep(200);
                }
                catch (InterruptedException  ex){
                    errs.add("OutputStream Delay Problem:" + ex.getMessage());
                }

                buff = params[1].getBytes();
                for (c = 0; c < buff.length; c++){
                    try{
                        //Thread.sleep(2);
                        os.write(buff[c]);
                    }
                    catch (IOException  ex){
                        errs.add("OutputStream Delay Problem:" + ex.getMessage());
                    }
                }


                try{
                    os.close();

                }
                catch (IOException ex){
                    errs.add("Could not close BT Socket");
                    Log.e("ERR", "doInBackground: ", ex);
                    status = "Ready";
                    return "!Could not close BT Socket";
                }
            }
            //endregion

            //region IP
            if (is_ethernet()){
                try{
                    status = "Printing";
                    prn_addr = InetAddress.getByName(address);
                    sock = new Socket(prn_addr, port);

                }
                catch (UnknownHostException ex){
                    errs.add("Unknown Host Error!");
                    Log.e("DCCERR Unknown Host", "doInBackground:IPPrint", ex);
                    return "!" + ex.getMessage();
                }
                catch (IOException ex){
                    errs.add("I/O Error!");
                    Log.e("ERR IO Error", "doInBackground:IPPrint", ex);
                    return "!" + ex.getMessage();
                }
                catch (Exception ex){
                    errs.add("Gen Error!");
                    Log.e("ERR IO Error", "doInBackground:IPPrint", ex);
                    return "!" + ex.getMessage();
                }

                try{
                    os = sock.getOutputStream();
                }
                catch (IOException ex){
                    errs.add("Could not connect IP Socket");
                    Log.e("ERR", "doInBackground:IPPrint ", ex);
                    status = "Ready";
                    return "!Could not connect IP Socket";
                }

                try{
                    buff = params[1].getBytes();
                    os.write(buff);
                    os.flush();
                }
                catch (IOException ex){
                    errs.add("Could not write to IP Socket");
                    Log.e("ERR", "doInBackground:IPPrint ", ex);
                    status = "Ready";
                    return "!Could not write to IP Socket";
                }

                try{
                    os.close();

                }
                catch (IOException ex){
                    errs.add("Could not close IP Socket");
                    Log.e("ERR", "doInBackground:IPPrint", ex);
                    status = "Ready";
                    return "!Could not close IP Socket";
                }
            }
        }

在蓝牙世界中连接有点复杂,但仍然相当简单。只需设置一个意图/广播接收器匹配,这样你就可以开始发现过程并选择一个BT设备。这也给了你选择配对设备或实际与一个新设备配对的选项!类似于下面的内容:

//region INIT_BT
public boolean init(){
    try{

        // Register for broadcasts when a device is discovered
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        con.registerReceiver(bt_interface, filter);

        // Register for broadcasts when discovery has finished
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        con.registerReceiver(bt_interface, filter);

        //REGISTER TO GET MESSAGES FOR BT DISCOVERY STARTED
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        con.registerReceiver(bt_interface, filter);

        //GET THE DEFAULT ADAPTER
        bta = BluetoothAdapter.getDefaultAdapter();

        //TURN BT ON
        if (!bta.isEnabled()){
            log("init_bt", "Turned BT On", null);
            bta.enable();
        }

        //INIT DEVS AND DEVLIST ARRAYLISTS
        devs = new ArrayList<String>();
        dev_list = new ArrayList<BluetoothDevice>();

        //GOOD IF WE MADE IT HERE
        return true;

    }
    catch (Exception ex){
        log("init_bt", "Init Failure", ex);
        return false;
    }

}

下面是一些小问题:移动终端/应用程序/打印机组合可能会导致一些时间问题,这是我们多年来看到的。您可能需要在发送时引入一个小的字符延迟,但这取决于移动设备/应用程序/打印机组合。如果您在尝试打印时没有响应,请尝试添加一个小的字符延迟(5 ms/10 ms)
上面的代码当然不是唯一的方法来做到这一点,我相信有一些优化,我们可以添加,但这已经工作了多年的多个移动终端制造商和移动打印机制造商!
有更多的东西可以解释在一个职位,但这应该希望至少给予你一个方向!

相关问题