"Ascii" codes to Hex (again)

  • Thread starter =?ISO-8859-15?Q?Kai_B=F8hli?=
  • Start date
?

=?ISO-8859-15?Q?Kai_B=F8hli?=

Hi all !

I've got a lot of feedback from (the always helpful) Jon Skeet on this
subject before. Dispite this I'm still not there - due to my own lack of
knowledge of course.

Anyway, I'm "talking to" different labelprinters. They got one thing in
common -> A char value above 127 must be written in the "dos way". The
best way to do this AFAIK is to use hex values. By reading hundreds of
messages in this group, I've come to the code below. It does not work
properly though. The result of this code is the hex value 0x0 followed
by the next two signs for the hex value.

If I just can get this to work, then I'm solved the (by far) largest
problem I've had porting my projects from Delphi.

Any help are greatly apprecitated

protected internal string StringToAscii(string s)
{
Encoding en = UTF8Encoding.GetEncoding(850);
byte[] codedBytes = en.GetBytes(s);
char[] codedChars = en.GetChars(codedBytes);

StringBuilder sb = new StringBuilder();
foreach (char c in codedChars)
{
int si = (int)c;
if (si > 127)
{
sb.AppendFormat("\0x{0:x2}",(int)c);
}
else
{
sb.AppendFormat("{0}",(char)si);
}
}
string newString = sb.ToString();
return newString;
}
 
J

Jon Skeet [C# MVP]

Kai Bøhli said:
I've got a lot of feedback from (the always helpful) Jon Skeet on this
subject before. Dispite this I'm still not there - due to my own lack of
knowledge of course.

Don't worry, we'll crack it :)
Anyway, I'm "talking to" different labelprinters. They got one thing in
common -> A char value above 127 must be written in the "dos way".

*Which* DOS way? Installed in different places, you'll need different
encodings. You may be able to leave that question for the moment though
- let's get it working with one particular encoding first...
The best way to do this AFAIK is to use hex values.

What exactly do you mean by "use hex values"? What bytes are you
expecting to send to the printer?
By reading hundreds of
messages in this group, I've come to the code below. It does not work
properly though. The result of this code is the hex value 0x0 followed
by the next two signs for the hex value.

Yes, it would...
If I just can get this to work, then I'm solved the (by far) largest
problem I've had porting my projects from Delphi.

Any help are greatly apprecitated

protected internal string StringToAscii(string s)
{
Encoding en = UTF8Encoding.GetEncoding(850);

First, change that to Encoding.GetEncoding(850);
You're not doing anything UTF8Encoding specific, or indeed doing
anything related to UTF-8 at all - the above gives the wrong
impression. It's not actually going to be causing any errors - just
confusion.
byte[] codedBytes = en.GetBytes(s);
char[] codedChars = en.GetChars(codedBytes);

What are you hoping to achieve with this pair of lines? All it will do
is convert characters which aren't in CodePage 850 to question marks,
if you're lucky. Your string will still contain the Unicode characters
you started off with.
StringBuilder sb = new StringBuilder();
foreach (char c in codedChars)
{
int si = (int)c;
if (si > 127)
{
sb.AppendFormat("\0x{0:x2}",(int)c);
}
else
{
sb.AppendFormat("{0}",(char)si);
}
}
string newString = sb.ToString();
return newString;
}

The string you return is going to be very odd, to be honest. By the
time you get to a stage dealing with encodings, you shouldn't be
dealing with strings - you should be dealing with bytes. How are you
sending the data to the printer in the end? *Something's* got to be
converting the text data to bytes, and *that's* where you want the
encoding to go.
 
?

=?ISO-8859-15?Q?Kai_B=F8hli?=

Hi again Jon !

Thanks a lot for your help again. It's really appreciated !
*Which* DOS way? Installed in different places, you'll need different
encodings. You may be able to leave that question for the moment though
- let's get it working with one particular encoding first...

I can tell the printer what code page it shall use - eg 850. I've tested
a lot of encodings though and it will only work if I send the char value
0x9b (155) in code page 850.

What exactly do you mean by "use hex values"? What bytes are you
expecting to send to the printer?

The printer expects for instance 0x9b (155) or 0x8f (143).

The best way is to send it the same way that I send the CTRL+B code
(0x2). The code for this is :

string dmImperial = "\x02n"; // units in imperial measure

Now if I could do something in the same way of the above for each char
above value 127, I think the problem will be solved.
First, change that to Encoding.GetEncoding(850);
Ok, I'll do that !
 
?

=?ISO-8859-15?Q?Kai_B=F8hli?=

Hi and thanks for your reply !
you can replace 'w' with your foreach variable
the returned string can then be slotted into the origonal string in place of your character (plus whatever formatting you need before hex numbers)

does that help?

No, it gave me a single number (4) istead of the intended hex value.
 
J

Jon Skeet [C# MVP]

Kai Bøhli said:
Thanks a lot for your help again. It's really appreciated !

No problem.
I can tell the printer what code page it shall use - eg 850.

Ah yes, I remember now.
I've tested
a lot of encodings though and it will only work if I send the char value
0x9b (155) in code page 850.
Right.


The printer expects for instance 0x9b (155) or 0x8f (143).

The best way is to send it the same way that I send the CTRL+B code
(0x2). The code for this is :

string dmImperial = "\x02n"; // units in imperial measure

Well, that's okay for 0x02, because that's ASCII "start of text" too,
so it's Unicode start of text as well. I'm not sure where the 'n' fits
in the above though...
Now if I could do something in the same way of the above for each char
above value 127, I think the problem will be solved.

No, because the reason the above works is because you're talking about
the same Unicode character - character 2.

As I said before, by the time you need to worry about encodings, you
should only be dealing in bytes. If you want byte 150 to go to the
printer, you shouldn't be going through *character* 150 which is
probably something entirely different. Convert your string to a byte
array with the appropriate encoding, and that byte array is what you
should send to the printer.
 
?

=?ISO-8859-15?Q?Kai_B=F8hli?=

Hi again Jon !
As I said before, by the time you need to worry about encodings, you
should only be dealing in bytes. If you want byte 150 to go to the
printer, you shouldn't be going through *character* 150 which is
probably something entirely different. Convert your string to a byte
array with the appropriate encoding, and that byte array is what you
should send to the printer.

Ok, I've rewritten the code to do this
protected internal byte[] StringToAscii(string s)
{
Encoding en = Encoding.GetEncoding(850);
byte[] codedBytes = en.GetBytes(s);
return codedBytes;
}

And I've changed all the callers to expect a byte array.
But how do I write this to the memorystream which will be sendt to the
printerport. I mean, I'm using a StreamWriter to write all other text
(Coordinates etc. are written in plain text)

eg:
MemoryStream memStrm = new MemoryStream();
StreamWriter sw = new StreamWriter(memStrm);
sw.WriteLine("\x02ySE1");
// draw lines and boxes
sw.WriteLine(dmLineHead + "0171" + "0001" + "L" + "393" + "002");
sw.WriteLine(dmLineHead + "0233" + "0021" + "L" + "109" + "014");
sw.WriteLine(dmLineHead + "0261" + "0001" + "L" + "011" + "072");
....
....

I've tried to write the same data using a BinaryWriter, and then the
labelprinter just dumped everything out in binary code - no format or
normal text.

I'm off to vacation now (a week in the southern Norway), but would like
to say it again: I'm really greatful for all your help !!
 
J

Jon Skeet [C# MVP]

Kai Bøhli said:
Hi again Jon !
As I said before, by the time you need to worry about encodings, you
should only be dealing in bytes. If you want byte 150 to go to the
printer, you shouldn't be going through *character* 150 which is
probably something entirely different. Convert your string to a byte
array with the appropriate encoding, and that byte array is what you
should send to the printer.

Ok, I've rewritten the code to do this
protected internal byte[] StringToAscii(string s)
{
Encoding en = Encoding.GetEncoding(850);
byte[] codedBytes = en.GetBytes(s);
return codedBytes;
}

Right. Apart from the name of the method, which I believe is
misleading, that's fine. Admittedly you could make it somewhat simpler
by just exposing a read-only encoding:

static readonly internal Encoding Encoding = Encoding.GetEncoding(850);

and then people could just call Encoding.GetBytes(s) without the need
for an extra method. Anyway, that's by-the-by.
And I've changed all the callers to expect a byte array.
But how do I write this to the memorystream which will be sendt to the
printerport.

Very easily indeed!

stream.Write(bytes, 0, bytes.Length);

Streams are specifically for binary data, so you're fine there.
I mean, I'm using a StreamWriter to write all other text
(Coordinates etc. are written in plain text)

eg:
MemoryStream memStrm = new MemoryStream();
StreamWriter sw = new StreamWriter(memStrm);
sw.WriteLine("\x02ySE1");
// draw lines and boxes
sw.WriteLine(dmLineHead + "0171" + "0001" + "L" + "393" + "002");
sw.WriteLine(dmLineHead + "0233" + "0021" + "L" + "109" + "014");
sw.WriteLine(dmLineHead + "0261" + "0001" + "L" + "011" + "072");
...
...

Okay. You can either keep the StreamWriter, but Flush it every time
you're then going to write directly to the stream, or call
StringToAscii on *everything*, or just give your StreamWriter the
correct encoding to start with:

StreamWriter sw = new StreamWriter(memStrm, Encoding.GetEncoding(850));

and it will take care of the encoding for you.
I've tried to write the same data using a BinaryWriter, and then the
labelprinter just dumped everything out in binary code - no format or
normal text.

BinaryWriter is almost certainly not the way to go here.
I'm off to vacation now (a week in the southern Norway), but would like
to say it again: I'm really greatful for all your help !!

No problem - hope it helps.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top