Подтвердить что ты не робот

Как распечатать изображение на 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[] и отправить его, но я не знаю, как это сделать.

Спасибо

UPDATE:

После такого количества времени я делаю это: у меня есть метод print_image (String file), который получает путь к изображению, которое я хочу напечатать:

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();
    }
}

Я сделал это на основе этого post

Это класс 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, и im, отправляющий растровое изображение, это код:

   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 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 точек/строка

И это то, что мне нравится делать (я сделал это с одним и тем же принтером, но с приложением, загруженным из магазина воспроизведения) Image that I want to print

Это то, что я сейчас получаю My printing trying

доводчик: A closer part

Closer2: enter image description here

Небольшая часть изображения может быть видна, поэтому я думаю, что я ближе, чтобы напечатать изображение...

Изображение, которое я использую, это (576x95): enter image description here

И это преобразованное изображение (я конвертирую его с верхним кодом): converted image

Inverted

Итак, ответ: что я делаю неправильно? Я думаю, что ошибка в этой команде:

  public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};

Но как я могу рассчитать правильные значения для моего изображения?, спасибо

4b9b3361

Ответ 1

Решено!, я делал неправильную инициализацию принтера... Корректный путь:

 public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};

Итак, таким образом изображение полностью напечатано

Ответ 2

РЕДАКТИРОВАТЬ: обновление основано на чтении вашего вопроса: https://stackoverflow.com/questions/16597789/print-bitmap-on-esc-pos-printer-java

Я предполагаю, что принтер, который вы печатаете, является таким же, как указано выше, то есть Термопринтер Rego. Это, как вы заметили, поддерживает Язык описания страниц ESC/POS.


Принтеры интерпретируют данные, передаваемые им как помеченный документ (аналогично тому, как браузер интерпретирует HTML). В некоторых случаях принтер буквально запускает документ как программу (например, PostScript). Ссылка: Страница описания страниц.

Общие языки:

Вам нужно прочитать спецификации вашего принтера, чтобы определить, какой язык использовать - если вам нужно поддерживать какой-либо принтер, то перед вами впереди очень большая работа: (

В ESC/POS вам нужно будет использовать команду GS v 0 (документально подтвержденную на стр. 33). Вы делаете это, отправив символы 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 

Определения параметров:

  • м:
    • 0,48: нормальный режим (шкала 1:1)
    • 1,49: double-width
    • 2,50: double-height
    • 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.
  • После печати битового изображения эта команда устанавливает положение печати в начало строки и очищает буфер.
  • Когда эта команда выполняется, данные передаются и печатаются синхронно. Поэтому никакой другой команды печати не требуется.

Есть несколько более обширных экспозиций:


К сожалению, в Android нет API-интерфейса принтера. Если вы решительно настроены на это, выполните следующие действия:

Ответ 3

Я решаю преобразование Bitmap в массив байтов. Помните, что ваше изображение должно быть черно-белого.

Для полного исходного кода: 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");
        }
    }

Ответ 4

Я тоже пробовал это, и я добрался до своего собственного решения, и я думаю, что понял, как работает команда SELECT_BIT_IMAGE_MODE.

Команда public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3}; в классе PrinterCommands - это команда POS для печати изображений.

Первые два являются довольно стандартными, следующие три определяют режим и размеры изображения для печати. Ради этого решения предположим, что второй элемент (33, мы индексируем нуль) всегда равен 33.

Последние два элемента этого байта [] относятся к свойству Ширина (в пикселях) изображения, которое вы хотите распечатать, элемент 3 иногда называют nL и элементом 4 иногда называют nH. Они на самом деле оба ссылаются на ширину, nL - это Low Byte, а nH - High Byte. Это означает, что мы можем иметь самое большее изображение с шириной 1111 1111 1111 1111b (двоичный), который равен 65535d (десятичный), хотя я еще не пробовал его. Если nL или nH не установлены на правильные значения, тогда будут напечатаны символы мусора вместе с изображением.

Как бы то ни было, Android-документы говорят нам, что пределы значения для байта в байтовом массиве равны -128 и +127, когда я попытался ввести 255, Eclipse попросил меня передать его байту.

В любом случае, возвращаясь к nL и nW, для вашего случая у вас есть изображение шириной 576, если мы преобразуем 576 в Binary, мы получим два байта, которые будут выглядеть следующим образом:

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 - действительно обширное

Другая документация

Расширенная версия кода выше, с большим количеством объяснений

Объяснение кода выше

Надеюсь, что это поможет.

Ответ 5

Я знаю, что для принтеров bluetooth evolute и AMDL. Сначала прочитайте документ защиты протокола, который сообщает вам, какие конкретные байты вам нужны для устройства -

public void connect() throws Exception 
{

    BluetoothDevice printer = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(connParams);

    Method m = printer.getClass().getMethod("createInsecureRfcommSocket",new Class[] { int.class });
    sock = (BluetoothSocket)m.invoke(printer, Integer.valueOf(1));
    sock.connect();
    os=sock.getOutputStream();
    in=sock.getInputStream();

}

После подключения через вышеуказанный код вы получите выходной сигнал сокета. Затем преобразуйте изображение в соответствующий байт через инструмент, поставляемый с принтером, вы получите что-то вроде

public byte[] Packet1={
        (byte)0X8A,(byte)0XC6,(byte)0X94,(byte)0XF4,(byte)0X0B,(byte)0X5E,(byte)0X30,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X04,(byte)0X24,(byte)0X01,(byte)0X0C,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X01,(byte)0X08,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X04,(byte)0X24,(byte)0X05,(byte)0X0C,(byte)0X00,(byte)0X60,(byte)0X00,(byte)0X18,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X30,(byte)0X1E,(byte)0X10,(byte)0X60,(byte)0X00,(byte)0X18,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X70,(byte)0X3F,(byte)0X18,(byte)0XF0,(byte)0X00,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X70,(byte)0X3C,(byte)0X39,(byte)0XF1,(byte)0X80,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF8,(byte)0X7C,(byte)0X9F,(byte)0XF1,(byte)0X80,(byte)0X7F,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF9,(byte)0X9E,(byte)0X1C,(byte)0XFF,(byte)0XC2,(byte)0X7E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF9,(byte)0X9E,(byte)0X1C,(byte)0XE7,(byte)0XE2,(byte)0X7E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XFB,(byte)0X1E,(byte)0X1C,(byte)0XFF,(byte)0XE7,(byte)0XBE,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X7B,(byte)0X16,(byte)0X1C,(byte)0XFF,(byte)0XDF,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X71,(byte)0X12,(byte)0X1C,(byte)0XE7,(byte)0XF7,(byte)0X34,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X51,(byte)0X12,(byte)0X1C,(byte)0XF7,(byte)0XF7,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X12,(byte)0X1C,(byte)0XFF,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X12,(byte)0X3F,(byte)0XFD,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X96,(byte)0X3F,(byte)0XFC,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X05,(byte)0X49,(byte)0X80,(byte)0X00,(byte)0X08,(byte)0X10,(byte)0X5E,(byte)0X28,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X30,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XE0,(byte)0X74,(byte)0XA9,(byte)0X33,(byte)0X23,(byte)0X26,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)0X04
        };

где 8A стартовый байт C6 - это режим байта (разный для смарт-карты, салфетки и отпечатка пальца), 94 - байт шрифта, а последний байт 04 - конечный байт, указывающий аппаратное обеспечение, что это конец пакета. В зависимости от размера на изображении вы получаете несколько из этих пакетов длиной 256 байт (большинство принтеров). Запишите их в outputStream.

os.write(Packet1)

Ответ 6

Я новичок в ESC/POS и борюсь с ним. Я столкнулся с этой страницей, которая, кажется, имеет некоторые полезные функции: http://code.taobao.org/p/printer/src/trunk/prtest/src/com/enjar/plugins/PrintTools_58mm.java Это по-китайски, но, возможно, стоит пройти. Если кто-нибудь это выяснит, я тоже хочу просветить...

Ответ 7

используйте этот код:

public static void print(Context context) {

    String examplePath = "file:///sdcard/dcim/Camera/20111210_181524.jpg";

    Intent sendIntent = new Intent(Intent.ACTION_SEND);
    sendIntent.setType("image/jpeg");
    sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Photo");
    sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(examplePath));
    sendIntent.putExtra(Intent.EXTRA_TEXT, "Enjoy the photo");
    context.startActivity(Intent.createChooser(sendIntent, "Email:"));
}