在没有打印服务预览的情况下打印
Printing without print service preview
我想在我的应用程序中按下按钮并将 pdf 文档发送到打印机以直接打印(不显示系统 android 从打印框架 Android 4.4 预览)。我该怎么做?
我试图通过套接字连接到打印机。没问题,无一例外,但我的打印机没有响应,也没有打印任何东西。
也许我需要在 phone 上为具体打印机安装驱动程序?但是如何做到这一点,我在哪里可以得到这样的驱动程序?
已编辑
我写了一个 class 来帮助将 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();
}
}
@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();
}
}
除 Gokula 的回答外:
也可以在不在设备上保存文件的情况下执行此操作。在我的例子中,我使用字节数组或 base 64 来打印图像。
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
我想在我的应用程序中按下按钮并将 pdf 文档发送到打印机以直接打印(不显示系统 android 从打印框架 Android 4.4 预览)。我该怎么做? 我试图通过套接字连接到打印机。没问题,无一例外,但我的打印机没有响应,也没有打印任何东西。
也许我需要在 phone 上为具体打印机安装驱动程序?但是如何做到这一点,我在哪里可以得到这样的驱动程序?
已编辑
我写了一个 class 来帮助将 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();
}
}
@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();
}
}
除 Gokula 的回答外:
也可以在不在设备上保存文件的情况下执行此操作。在我的例子中,我使用字节数组或 base 64 来打印图像。
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