我必须在热蓝牙打印机上打印一些数据,我正在这样做:
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(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的方法,并且我正在发送一个位图,这就是代码:
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());
}
}
这是我正在使用的printer,分辨率:8点/ mm,576点/行
这就是我喜欢做的事情(我使用相同的打印机,但是从Play商店下载的应用程序)
这就是我现在所得到的
更紧密:
Closer2:
可以看到图像的一小部分,所以我认为我更接近可以打印图像......
我正在使用的图像是这个(576x95):
这是转换后的图像(我用高级代码转换它):
所以,答案是:我做错了什么?,我认为错误在于这个命令:
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
但是,我怎样才能为我的图像计算正确的值?,谢谢
答案 0 :(得分:12)
我解决了将Bitmap转换为Byte数组的问题。请记住,您的图片必须是黑色和白色格式。
完整的源代码: 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");
}
}
答案 1 :(得分:9)
解决了!,我正在做错误的打印机初始化......正确的方法是:
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};
因此,通过这种方式,图像被完全打印
答案 2 :(得分:8)
编辑:根据您的问题更新:https://stackoverflow.com/questions/16597789/print-bitmap-on-esc-pos-printer-java
我将假设您要打印的打印机与上面相同,即Rego热敏打印机。如您所知,这支持ESC/POS Page Description Language。
打印机将流式传输的数据解释为标记文档(与浏览器解释HTML的方式类似)。在某些情况下,打印机将文档作为程序(例如PostScript)运行。链接:Page Description Languages。
常用语言是:
您需要阅读打印机的规格以确定使用哪种语言 - 如果您需要支持任何打印机,那么您面前的工作量非常大:(
在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
参数定义:
注意:
还有几个更广泛的阐述:
不幸的是Android中没有打印机API。如果你对此有强烈的感受,请遵循以下问题:
答案 3 :(得分:8)
我也尝试了这个,我得到了自己的解决方案,我想我发现了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转换为二进制,我们得到两个字节,如下所示:
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 Mobile Printer Documentation
ECS-POS programming guide - really extensive
The expanded version of the code above, with more explanation
希望这些有所帮助。
答案 4 :(得分:3)
我是ESC / POS的新手并且正在努力解决它。我遇到了这个似乎有一些有用功能的页面:http://code.taobao.org/p/printer/src/trunk/prtest/src/com/enjar/plugins/PrintTools_58mm.java 虽然它是中文的,但可能值得一试。如果有人想出来的话,我也希望得到开悟......
答案 5 :(得分:2)
我知道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();
}
通过上面的代码连接后,你得到socket的输出流。然后通过打印机提供的工具将你的图像转换为相应的字节,你会得到类似的东西
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 :(得分:0)
这对我有用:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTargetDensity = 200;
options.inDensity = 200;
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), img, options);
在使用BitmapFactory.Options之前,我只能打印60X60的图像尺寸,现在我也可以打印更大尺寸的图像。
答案 7 :(得分:-5)
使用此代码:
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:"));
}