don / cordova-plugin-ble-central

Bluetooth Low Energy (BLE) Central plugin for Apache Cordova (aka PhoneGap)
Apache License 2.0
942 stars 603 forks source link

StringToBytes(Print chinese character) #960

Closed B200019A closed 1 year ago

B200019A commented 1 year ago

HI, i using your method(stringToBytes) but the thermal printer print the number only, what are the problem?

this is my code


var test = "你好\n";

var encodeText = new TextEncoder("GB18030", {
NONSTANDARD_allowLegacyEncoding: true,
}).encode(stringToBytes(test)+"\r\n\u001B\u0070\u0000\u000F\r\n");

ble.write(
printer_id,
"49535343-FE7D-4AE5-8FA9-9FAFD205E455",
"49535343-8841-43F4-A8D4-ECBE34729BB3",
encodeText.buffer,
(success) => {
console.log(success + ": print" + test);
},
(failure) => {
console.log(failure);
}
);

const stringToBytes =(string) => {
// based on http://ciaranj.blogspot.fr/2007/11/utf8-characters-encoding-in-javascript.html

 var bytes = [];

 for (var n = 0; n < string.length; n++) {

     var c = string.charCodeAt(n);

     if (c < 128) {

         bytes[bytes.length]= c;

     } else if((c > 127) && (c < 2048)) {

         bytes[bytes.length] = (c >> 6) | 192;
         bytes[bytes.length] = (c & 63) | 128;

     } else {

         bytes[bytes.length] = (c >> 12) | 224;
         bytes[bytes.length] = ((c >> 6) & 63) | 128;
         bytes[bytes.length] = (c & 63) | 128;

     }

 }

 return bytes;
}
peitschie commented 1 year ago

Hi @B200019A, the use of stringToBytes there does not look correct to me. The .encode function there should take a string, so in theory you can just do:

var test = "你好\n";

var encodeText = new TextEncoder("GB18030", {
NONSTANDARD_allowLegacyEncoding: true,
}).encode(test + "\r\n\u001B\u0070\u0000\u000F\r\n");

ble.write(
  printer_id,
  "49535343-FE7D-4AE5-8FA9-9FAFD205E455",
  "49535343-8841-43F4-A8D4-ECBE34729BB3",
  encodeText.buffer,
  (success) => {
    console.log(success + ": print" + test);
  },
  (failure) => {
    console.log(failure);
  }
);

If that doesn't work, I'd suggest you double check what encoding scheme the thermal printer expects, as it may be that the GB18030 encoding scheme you're using there in the encoder is not supported by the printer.

B200019A commented 1 year ago

I am check my thermal printer is support GB18030 but your suggest code cannot print it, the chinese text print garbled. I was research the printed chinese two day alr, still in this processsssss. image

peitschie commented 1 year ago

I don't think GB180301 is supported natively by TextEncoder class in the browser like you're trying to do here.

In the GB180301 encoded version of 你好 as hex is C4 E3 BA C3. Are you able to see what the encoded data you're trying to send there currently is? If you get E4 BD A0 E5 A5 BD instead, that's the utf-8 encoded version and definitely won't work.

You can easily print the hex string of a data buffer with a line like:

(Array.from(new TextEncoder().encode("你好"))).map(e => e.toString(16).toUpperCase()).join(" ")
B200019A commented 1 year ago

I try your code lar, the printer print status is successs, but no print out any text

image

this is the console of the android phone.

peitschie commented 1 year ago

@B200019A that is showing the problem I suggested above is happening. encode is not turning your string into a GB18030 encoded string like the printer requires, so it's going to print garbage.

What happens if you send this directly to the printer?

const data = [
  0xC4, 0xE3, 0xBA 0xC3, // encoded Chinese char,
  0x0D, 0x0A, 0x1B, 0x70, 0x00, 0x0F, 0x0D, 0x0A // encoded version of the trailing string your example: "\r\n\u001B...."
]

ble.write(
  printer_id,
  "49535343-FE7D-4AE5-8FA9-9FAFD205E455",
  "49535343-8841-43F4-A8D4-ECBE34729BB3",
  new Uint8Array(data).buffer,
  (success) => {
    console.log(success + ": print" + test);
  },
  (failure) => {
    console.log(failure);
  }
);
B200019A commented 1 year ago

the result is below image IMG_3886

peitschie commented 1 year ago

Interestingly, &#20320;&#22909; is the HTML encoded version of 你好. I can't really understand why the bytes you're sending are causing this.

@B200019A there's not much I can do to help here.

It's clear the encoding process you're using to turn characters into bytes is wrong, but I can't guess at what the bytes you need to send are.

The plugin itself is very careful about passing on the exact bytes it's handed, so the I don't believe there's any error happening in the plugin. The key thing you'll need to figure out is how to correctly encode the bytes you're sending to the printer.

B200019A commented 1 year ago

### 你好 this is testing my code , not your code, the next line cc9ccc is your code printout the answer

B200019A commented 1 year ago

Thank you for responce and suggestion~~ nvm, if have solve it will share in here.

peitschie commented 1 year ago

Out of interest, does the thermal printer support utf8?

B200019A commented 1 year ago

i am print the english is no any problem

like this:

var encodeText = new TextEncoder("GB18030", {
NONSTANDARD_allowLegacyEncoding: true,
}).encode("hello world"+"\r\n\u001B\u0070\u0000\u000F\r\n"); 

ble.write(
printer_id,
"49535343-FE7D-4AE5-8FA9-9FAFD205E455",
"49535343-8841-43F4-A8D4-ECBE34729BB3",
encodeText.buffer,
(success) => {
console.log(success + ": print" + test);
},
(failure) => {
console.log(failure);
}
);

The thermal prinnter is support GB18030 , but i no sure support the utf8 or not IMG_3887

peitschie commented 1 year ago

I think that the stuff you're passing in the TextEncoder constructor there isn't having any impact. I.e., this part probably isn't needed?

"GB18030", {
NONSTANDARD_allowLegacyEncoding: true,
}

What is printed out if you send this?

const data = [
  0x4F, 0x60
]

ble.write(
  printer_id,
  "49535343-FE7D-4AE5-8FA9-9FAFD205E455",
  "49535343-8841-43F4-A8D4-ECBE34729BB3",
  new Uint8Array(data).buffer,
  (success) => {
    console.log(success + ": print" + test);
  },
  (failure) => {
    console.log(failure);
  }
);
B200019A commented 1 year ago

the result is..... IMG_3888

peitschie commented 1 year ago

Do you have a link to the printer's SDK online? That response there makes it look like the previous attempt was not seen as a valid print command, as it's printing significantly more bytes than you've sent.

B200019A commented 1 year ago

What is sdk? This printer buy in the taobao, no any brand . I think receive the printer only have machine, user manual abd one cd but the cd no any device can read that

peitschie commented 1 year ago

The \u001B\u0070\u0000\u000F in your first example there looks like a printer command of some sort, possibly indicating the encoding used for the printer itself.

The key bit to figure out is what the codepage on the printer is, which is often something that's configurable.

Most printers follow something like ESC/POS for accepting data: https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=2

You could possibly test this by sending something like:

var encodeText = new TextEncoder().encode('ESC "@"\nESC "a" 1\n"TESTING"');

ble.write(
  printer_id,
  "49535343-FE7D-4AE5-8FA9-9FAFD205E455",
  "49535343-8841-43F4-A8D4-ECBE34729BB3",
  encodeText.buffer,
  (success) => {
    console.log(success + ": print" + test);
  },
  (failure) => {
    console.log(failure);
  }
);
peitschie commented 1 year ago

This library might possibly be of interest: https://github.com/paystory-de/thermal-printer-cordova-plugin

B200019A commented 1 year ago

### \u001B\u0070\u0000\u000F this command is using for counter, when done the payment the money cabinet will auto open for change return the money.

yes, i have using esc/pos command

const ESC = "\u001B";
const GS = "\u001D";
const FS = "\u001C";

//ESC command
const EscCommand = {
  InitializePrinter: ESC + "@",
  BoldOn: ESC + "E" + "\u0001",
  BoldOff: ESC + "E" + "\0",
  DoubleHeight: GS + "!" + "\u0001",
  DoubleWidth: GS + "!" + "\u0010",
  DoubleOn: GS + "!" + "\u0011", // 2x sized text (double-high + double-wide)
  DoubleOff: GS + "!" + "\0",
  PrintAndFeedMaxLine: ESC + "J" + "\u00FF", // 打印并走纸 最大255
  TextAlignLeft: ESC + "a" + "0",
  TextAlignCenter: ESC + "a" + "1",
  TextAlignRight: ESC + "a" + "2",
  UnderlineOn: ESC + "-" + "\u0001", // text underline on
  UnderlineOff: ESC + "-" + "\0", // text underline off
  LineFeed: ESC + "LF" + "3",
  PrintChinese: FS + "&", // print the chinese
  PrintChineseOff: FS + ".", //print the chinese off
};

when using these command to the printer can get the responce, such as center or underline the text.

peitschie commented 1 year ago

I'm closing this for now as it seems like the plugin is doing everything it needs, it's just a matter of figuring out the correct encoding approach in the app.

Feel free to continue the discussion here or re-open if you start to suspect a plugin problem again though!