不需要打印服务预览的打印方法

4
我希望在我的应用程序中按下按钮,直接将PDF文档发送到打印机进行打印(无需在打印框架Android 4.4中显示系统android预览)。我该怎么做? 我尝试通过Socket连接打印机。一切正常,没有异常,但我的打印机没有响应,也没有任何东西打印出来。
也许我需要为具体的打印机在手机上安装驱动程序?但是如何操作并在哪里获取这个驱动程序呢? 编辑过的内容

enter image description here

3个回答

5
我已经编写了一个类,可帮助直接将PDF文件打印到网络打印机并提供其IP地址。只要打印机支持PJL命令,它就应该能在大多数打印机上工作。
public class PrintService {

    private static PrintListener printListener;

    public enum PaperSize {
        A4,
        A5
    }

    public static void printPDFFile(final String printerIP, final int printerPort,
                                    final File file, final String filename, final PaperSize paperSize, final int copies) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                Socket socket = null;
                DataOutputStream out = null;
                FileInputStream inputStream = null;
                try {
                    socket = new Socket(printerIP, printerPort);
                    out = new DataOutputStream(socket.getOutputStream());
                    DataInputStream input = new DataInputStream(socket.getInputStream());
                    inputStream = new FileInputStream(file);
                    byte[] buffer = new byte[3000];

                    final char ESC = 0x1b;
                    final String UEL = ESC + "%-12345X";
                    final String ESC_SEQ = ESC + "%-12345\r\n";

                    out.writeBytes(UEL);
                    out.writeBytes("@PJL \r\n");
                    out.writeBytes("@PJL JOB NAME = '" + filename + "' \r\n");
                    out.writeBytes("@PJL SET PAPER=" + paperSize.name());
                    out.writeBytes("@PJL SET COPIES=" + copies);
                    out.writeBytes("@PJL ENTER LANGUAGE = PDF\r\n");
                    while (inputStream.read(buffer) != -1)
                        out.write(buffer);
                    out.writeBytes(ESC_SEQ);
                    out.writeBytes("@PJL \r\n");
                    out.writeBytes("@PJL RESET \r\n");
                    out.writeBytes("@PJL EOJ NAME = '" + filename + "'");
                    out.writeBytes(UEL);

                    out.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                    if (printListener != null)
                        printListener.networkError();
                } finally {
                    try {
                        if (inputStream != null)
                            inputStream.close();
                        if (out != null)
                            out.close();
                        if (socket != null)
                            socket.close();
                        if (printListener != null)
                            printListener.printCompleted();
                    } catch (IOException e) {
                        e.printStackTrace();
                        if (printListener != null)
                            printListener.networkError();
                    }
                }
            }
        });
        t.start();
    }

    public static void setPrintListener(PrintListener list) {
        printListener = list;
    }

    public interface PrintListener {
        void printCompleted();

        void networkError();
    }
}

假设它接受PJL并知道如何在打印机中本地打印PDF。自从我上次参与打印机固件开发已经过去十多年了,但那时第二个假设是非常大胆的。 - Gabe Sechan
谢谢,这个解决方案看起来非常不错。但是我遇到了一个错误: java.net.SocketException: sendto failed: ECONNRESET (Connection reset by peer) 我更新了我的问题,添加了错误图片 - punchman
你要发送到哪个端口?如果我没记错的话,PJL通常在9100上工作。 - Cristian
@Cristian我尝试了631端口。我以为所有的打印机都连接到631端口。好的,我会尝试9100端口。 - punchman
@Cristian 是的,使用9100端口可以避免错误,但打印机没有打印。我的打印机是:HP LaserJet Professional M1217nfw MFP。也许需要其他编码方式? - punchman
1
谢谢@Cristian,你的解决方案可行,但是对于其他打印机。我的第一台打印机不支持PDF和PostScript。 - punchman

0

除了Gokula的答案之外:

  1. 也可以在不将文件保存在设备上的情况下完成此操作。在我的情况下,我使用字节数组或base64来打印图像。

  2. Kotlin代码=)

打印机控制器调用

override fun write(content: String, address: String?) {
    address?.let {
        val policy: StrictMode.ThreadPolicy = StrictMode.ThreadPolicy.Builder().permitAll().build()
        StrictMode.setThreadPolicy(policy)
        Base64.decode("Base64 image content goes here", Base64.DEFAULT).printByDeviceIp(address)
    }
}

打印机扩展

fun ByteArray.printByDeviceIp(address: String) {
    try {
        val socket = Socket(address, PRINTER_DEFAULT_PORT)
        val output = DataOutputStream(socket.getOutputStream())
        val buffer = ByteArray(PRINTER_BUFFER_SIZE)
        val inputStream = ByteArrayInputStream(this)

        output.writeBytes(UEL)
        output.writeBytes(PRINT_META_JOB_START)
        output.writeBytes(PRINT_META_JOB_NAME)
        output.writeBytes(PRINT_META_JOB_PAPER_TYPE)
        output.writeBytes(PRINT_META_JOB_COPIES)
        output.writeBytes(PRINT_META_JOB_LANGUAGE)

        while (inputStream.read(buffer) != -1)
            output.write(buffer)

        output.writeBytes(ESC_SEQ)
        output.writeBytes(UEL)

        output.flush()

        inputStream.close()
        output.close()
        socket.close()
    } catch (e: Exception) {
        when(e) {
        is SocketException -> Log.e(this.javaClass.name, "Network failure: ${e.message}")
        is SocketTimeoutException -> Log.e(this.javaClass.name, "Timeout: ${e.message}")
        is IOException -> Log.e(this.javaClass.name, "Buffer failure: ${e.message}")
        else -> Log.e(this.javaClass.name, "General failure: ${e.message}")
    }
}

打印机作业常量

private const val PRINT_META_JOB_LABEL = "@PJL"
private const val PRINT_META_BREAK = "\r\n"

private const val ESCAPE_KEY = 0x1b.toChar()
const val UEL = "$ESCAPE_KEY%-12345X"
const val ESC_SEQ = "$ESCAPE_KEY%-12345 $PRINT_META_BREAK"

const val PRINT_META_JOB_START = "$PRINT_META_JOB_LABEL $PRINT_META_BREAK"
const val PRINT_META_JOB_NAME = "$PRINT_META_JOB_LABEL JOB NAME = 'INBOUND_FINISH' $PRINT_META_BREAK"
const val PRINT_META_JOB_PAPER_TYPE = "$PRINT_META_JOB_LABEL SET PAPER = A4"
const val PRINT_META_JOB_COPIES = "$PRINT_META_JOB_LABEL SET COPIES = 1"
const val PRINT_META_JOB_LANGUAGE = "$PRINT_META_JOB_LABEL ENTER LANGUAGE = PDF $PRINT_META_BREAK"

const val PRINTER_DEFAULT_PORT: Int = 9100
const val PRINTER_BUFFER_SIZE: Int = 3000

0

@Cristian使用AsyncTask实现回答。通过这种实现,您可以根据PrintServiceListener回调执行UI操作。

public class CustomPrinterService extends AsyncTask<Void, Void, Boolean> {

public enum PaperSize {
    A4,
    A5
}

private static final String TAG = "CustomPrinterService";

private PrintServiceListener mPrintServiceListener;

private String mPrinterIP;
private String mFilename;

private int mPrinterPort;
private int mNumberOfCopies;

private File mFile;
private PaperSize mPaperSize;

public CustomPrinterService(final String printerIP, final int printerPort, final File file,
                            final String filename, final PaperSize paperSize, final int copies) {
    mPrinterIP = printerIP;
    mPrinterPort = printerPort;
    mFile = file;
    mFilename = filename;
    mPaperSize = paperSize;
    mNumberOfCopies = copies;
}

@Override
protected Boolean doInBackground(Void... voids) {
    Boolean result = null;
    Socket socket = null;
    DataOutputStream out = null;
    FileInputStream inputStream = null;
    try {
        socket = new Socket(mPrinterIP, mPrinterPort);
        out = new DataOutputStream(socket.getOutputStream());
        DataInputStream input = new DataInputStream(socket.getInputStream());
        inputStream = new FileInputStream(mFile);
        byte[] buffer = new byte[3000];

        final char ESC = 0x1b;
        final String UEL = ESC + "%-12345X";
        final String ESC_SEQ = ESC + "%-12345\r\n";

        out.writeBytes(UEL);
        out.writeBytes("@PJL \r\n");
        out.writeBytes("@PJL JOB NAME = '" + mFilename + "' \r\n");
        out.writeBytes("@PJL SET PAPER=" + mPaperSize.name());
        out.writeBytes("@PJL SET COPIES=" + mNumberOfCopies);
        out.writeBytes("@PJL ENTER LANGUAGE = PDF\r\n");
        while (inputStream.read(buffer) != -1)
            out.write(buffer);
        out.writeBytes(ESC_SEQ);
        out.writeBytes("@PJL \r\n");
        out.writeBytes("@PJL RESET \r\n");
        out.writeBytes("@PJL EOJ NAME = '" + mFilename + "'");
        out.writeBytes(UEL);

        out.flush();
    } catch (Exception exception) {
        Log.d(TAG, exception.toString());
        result = false;
    } finally {
        try {
            if (inputStream != null) {
                inputStream.close();
            }
            if (out != null) {
                out.close();
            }
            if (socket != null) {
                socket.close();
            }
            if (result == null) {
                result = true;
            }
        } catch (Exception exception) {
            Log.d(TAG, exception.toString());
            result = false;
        }
    }
    return result;
}

@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);
    if (result) {
        if (mPrintServiceListener != null) {
            mPrintServiceListener.onPrintCompleted();
        }
    } else {
        if (mPrintServiceListener != null) {
            mPrintServiceListener.onNetworkError();
        }
    }
}

public void setPrintServiceListener(PrintServiceListener listener) {
    mPrintServiceListener = listener;
}

public interface PrintServiceListener {

    void onPrintCompleted();

    void onNetworkError();
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接