don/cordova-plugin-ble-central

StringToBytes(Print chinese character)

B200019A opened this issue · 19 comments

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

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.

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

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(" ")

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.

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

the result is below image
IMG_3886

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.

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

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

Out of interest, does the thermal printer support utf8?

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

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

the result is.....
IMG_3888

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.

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

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

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

### \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.

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!