Как я могу распечатать изображение на принтере Bluetooth в Android?
Мне нужно распечатать некоторые данные на термопринтере Bluetooth, я делаю с этим:
String message="abcdef any message 12345";
byte[] send;
send = message.getBytes();
mService.write(send);
Это хорошо работает для текста, но не для изображений. Я думаю, мне нужно получить byte[]
данные изображения. Я попытался получить данные изображения таким образом:
Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.qrcode);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();
К сожалению, принтер печатает много странных символов (приблизительно. 50 см бумаги). Я не знаю, как распечатать изображение.
Я хотел бы попробовать получить пиксели растрового изображения, а затем преобразовать его в byte[]
и отправить, но я не знаю, как это сделать.
Спасибо
Обновить:
Спустя столько времени я делаю это: у меня есть метод с именем print_image (строковый файл), который получает путь к изображению, которое я хочу распечатать:
private void print_image(String file) {
File fl = new File(file);
if (fl.exists()) {
Bitmap bmp = BitmapFactory.decodeFile(file);
convertBitmap(bmp);
mService.write(PrinterCommands.SET_LINE_SPACING_24);
int offset = 0;
while (offset < bmp.getHeight()) {
mService.write(PrinterCommands.SELECT_BIT_IMAGE_MODE);
for (int x = 0; x < bmp.getWidth(); ++x) {
for (int k = 0; k < 3; ++k) {
byte slice = 0;
for (int b = 0; b < 8; ++b) {
int y = (((offset / 8) + k) * 8) + b;
int i = (y * bmp.getWidth()) + x;
boolean v = false;
if (i < dots.length()) {
v = dots.get(i);
}
slice |= (byte) ((v ? 1 : 0) << (7 - b));
}
mService.write(slice);
}
}
offset += 24;
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
}
mService.write(PrinterCommands.SET_LINE_SPACING_30);
} else {
Toast.makeText(this, "file doesn't exists", Toast.LENGTH_SHORT)
.show();
}
}
Я сделал это на основе этого поста
Это класс PrinterCommands:
public class PrinterCommands {
public static final byte[] INIT = {27, 64};
public static byte[] FEED_LINE = {10};
public static byte[] SELECT_FONT_A = {27, 33, 0};
public static byte[] SET_BAR_CODE_HEIGHT = {29, 104, 100};
public static byte[] PRINT_BAR_CODE_1 = {29, 107, 2};
public static byte[] SEND_NULL_BYTE = {0x00};
public static byte[] SELECT_PRINT_SHEET = {0x1B, 0x63, 0x30, 0x02};
public static byte[] FEED_PAPER_AND_CUT = {0x1D, 0x56, 66, 0x00};
public static byte[] SELECT_CYRILLIC_CHARACTER_CODE_TABLE = {0x1B, 0x74, 0x11};
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
public static byte[] SET_LINE_SPACING_24 = {0x1B, 0x33, 24};
public static byte[] SET_LINE_SPACING_30 = {0x1B, 0x33, 30};
public static byte[] TRANSMIT_DLE_PRINTER_STATUS = {0x10, 0x04, 0x01};
public static byte[] TRANSMIT_DLE_OFFLINE_PRINTER_STATUS = {0x10, 0x04, 0x02};
public static byte[] TRANSMIT_DLE_ERROR_STATUS = {0x10, 0x04, 0x03};
public static byte[] TRANSMIT_DLE_ROLL_PAPER_SENSOR_STATUS = {0x10, 0x04, 0x04};
}
Как видно из метода print_image, я вызываю метод, называемый convertBitmap , и я отправляю растровое изображение, это код:
public String convertBitmap(Bitmap inputBitmap) {
mWidth = inputBitmap.getWidth();
mHeight = inputBitmap.getHeight();
convertArgbToGrayscale(inputBitmap, mWidth, mHeight);
mStatus = "ok";
return mStatus;
}
private void convertArgbToGrayscale(Bitmap bmpOriginal, int width,
int height) {
int pixel;
int k = 0;
int B = 0, G = 0, R = 0;
dots = new BitSet();
try {
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
// get one pixel color
pixel = bmpOriginal.getPixel(y, x);
// retrieve color of all channels
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// take conversion up to one single value by calculating
// pixel intensity.
R = G = B = (int) (0.299 * R + 0.587 * G + 0.114 * B);
// set bit into bitset, by calculating the pixel's luma
if (R < 55) {
dots.set(k);//this is the bitset that i'm printing
}
k++;
}
}
} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, e.toString());
}
}
Это принтер, который я использую, разрешение: 8 точек / мм, 576 точек / строка
И это то, что мне нравится делать (я сделал это на том же принтере, но с приложением, загруженным из play Store)
Это то, что я получаю сейчас
Ближе:
Closer2:
Видна небольшая часть изображения, поэтому я думаю, что я ближе к тому, чтобы распечатать изображение...
Изображение, которое я использую, это (576x95):
И это преобразованное изображение (я конвертирую его с помощью верхнего кода):
Итак, ответ таков: что я делаю не так?, я думаю, что ошибка в этой команде:
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
Но, как я могу вычислить правильные значения для моего изображения?, спасибо
Переведено автоматически
Ответ 1
Я решаю эту проблему, преобразуя растровое изображение в массив байтов. Помните, что ваше изображение должно быть в черно-белом формате.
Полный исходный код: https://github.com/imrankst1221/Thermal-Printer-in-Android
public void printPhoto() {
try {
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.img);
if(bmp!=null){
byte[] command = Utils.decodeBitmap(bmp);
printText(command);
}else{
Log.e("Print Photo error", "the file isn't exists");
}
} catch (Exception e) {
e.printStackTrace();
Log.e("PrintTools", "the file isn't exists");
}
}
Ответ 2
Я также попробовал это, и я нашел свое собственное решение, и я думаю, что понял, как работает команда SELECT_BIT_IMAGE_MODE
.
Команда public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};
в классе PrinterCommands
является командой POS для печати изображений.
Первые два являются довольно стандартными, следующие три определяют режим и размеры изображения, которое будет напечатано. Ради этого решения давайте просто предположим, что второй элемент (33, мы индексируем ноль) всегда равен 33.
Последние два элемента этого байта[] относятся к свойству Width (в пикселях) изображения, которое вы хотите распечатать, элемент 3 иногда называют nL
, а элемент 4 иногда называют nH
. На самом деле они оба относятся к ширине, nL
это Low Byte
, а nH
это High Byte
. Это означает, что мы можем получить максимум изображение шириной 1111 1111 1111 1111b (двоичное), которое равно 65535d (десятичное), хотя я еще не пробовал. Если для nL или nH не установлены правильные значения, то вместе с изображением будут напечатаны символы мусора.
Каким-то образом в документах Android сообщается, что пределы значения для байта в массиве byte равны -128 и + 127, когда я попытался ввести 255, Eclipse попросил меня преобразовать его в Byte.
В любом случае, возвращаясь к nL и nW, в вашем случае у вас есть изображение шириной 576, если мы преобразуем 576 в двоичный файл, мы получим два байта, которые будут выглядеть следующим образом:
0000 0010 0100 0000
В этом случае младший байт равен 0100 0000
, а старший - 0000 0010
. Преобразуйте его обратно в десятичный, и мы получим nL = 64
и nH = 2
.
В моем случае я напечатал изображение шириной 330 пикселей, преобразовав 330 в двоичный файл, мы получаем:
0000 0001 0100 1010
В этом случае теперь младший байт равен 0100 1010
, а старший - 0000 0001
. Преобразуя в десятичный код, мы получаем nL = 74
и nH = 1
.
Для получения дополнительной информации ознакомьтесь с этой документацией / руководствами:
Документация по мобильному принтеру Star Asia
Руководство по программированию ECS-POS - действительно обширное
Расширенная версия приведенного выше кода с дополнительными пояснениями
Объяснение приведенного выше кода
Надеюсь, это поможет.
Ответ 3
Решено!, я выполнял неправильную инициализацию принтера... Правильный способ:
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};
Таким образом, изображение печатается полностью нормально
Ответ 4
РЕДАКТИРОВАТЬ: Обновление на основе прочтения вашего вопроса: https://javalang.ru/questions/16597789/print-bitmap-on-esc-pos-printer-java
Я предположу, что принтер, на котором вы печатаете, такой же, как указано выше, то есть термопринтер Rego. Он, как вы заметили, поддерживает язык описания страницы ESC / POS.
Принтеры интерпретируют передаваемые им данные либо как размеченный документ (аналогично тому, как браузер интерпретирует HTML). В некоторых случаях принтер буквально запускает документ как программу (например, PostScript). Ссылка: Языки описания страницы.
Распространенными языками являются:
Вам нужно прочитать спецификации вашего принтера, чтобы определить, какой язык использовать - если вам нужно поддерживать любой принтер, то вам предстоит очень большая работа : (
В ESC / POS вам нужно будет использовать GS v 0
команду (задокументирована на p33). Вы делаете это, отправляя символы 0x1D7630
по последовательной ссылке, за которыми следует набор аргументов:
ASCII: Gs v 0
Decimal: 29 118 48 m xL xH yL yH [d]k
Hexadecimal: 1D 76 30 m xL xH yL yH [d]k
Определения параметров:
- m:
- 0,48: обычный режим (масштаб 1: 1)
- 1,49: двойная ширина
- 2,50: двойная высота
- 3,51: двойная ширина + двойная высота
- xL, xH задает (xL + xH × 256) байты по горизонтали для битового изображения.
- yL, yH задает (yL + yH × 256) точки по вертикали для битового изображения.
- [d] k задает битовые данные изображения (растровый формат).
- k указывает количество битовых данных изображения. k является параметром пояснения; следовательно, его не нужно передавать.
Примечания:
- Когда data [d] k равно 1, указывается бит, печатаемый равным 1, а не равный 0.
- Если растровое битовое изображение превышает одну строку области печати, лишние данные не печатаются.
- Эта команда выполняет подачу бумаги в количестве, необходимом для печати битового изображения, независимо от настроек ESC 2 или ESC 3.
- После печати битового изображения эта команда устанавливает позицию печати в начало строки и очищает буфер.
- При выполнении этой команды данные передаются и печатаются синхронно. Таким образом, никакая другая команда печати не требуется.
Есть несколько более подробных описаний:
- http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/
- На SO в C #. Хотя это и не Java, но достаточно близко, чтобы быть шаблоном.
К сожалению, в Android нет API для принтера. Если вы решительно настроены по этому поводу, ознакомьтесь с этими вопросами: