Reputation: 1380
I want to press button in my app and send pdf document to printer for printing directly (without showing system android preview from printing-framework Android 4.4). How can I do it? I tried to connect to printer via Socket. It was Ok, without exceptions, but my printer didn`t respond and nothing printed.
Maybe need I setup driver on my phone for concrete printer? But how to do it and where can i get so driver?
EDITED
Upvotes: 4
Views: 3998
Reputation: 389
I have written a class to help printing a PDF file directly to a network printer, providing its IP. It is supposed to work on most printers, as long as they support PJL commands.
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();
}
}
Upvotes: 5
Reputation: 3713
Additionally to Gokula's answer:
It's also possible to do this without having a file saved on device. In my case I used byte array or base 64 to print an image.
Code in kotlin =)
Printer Controller Call
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)
}
}
Printer Extension
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}")
}
}
Printer Job Constants
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
Upvotes: 0
Reputation: 187
@Cristian answer with AsyncTask implementation. With this implementation you can perform UI operation with respect to the PrintServiceListener callbacks.
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();
}
}
Upvotes: 0