Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

FOXBARCODEQR FOR UNICODE

Status
Not open for further replies.

vie3548

Programmer
Jul 12, 2021
28
AE
hi
i am using foxbarcodeqr to generate qr code, it is working fine for non unicode characters.
but if i passed string with arabic text its printing different characters.
is foxbarcodeqr supports unicode/utf-8 characters?
is there anyone has tried this? pls help.

Thank you.


Elvie


 
Vie3548, can you post an example of an Arabic text you must encode into the QR symbol?
 
hi,

i am generating static qr code (just text).
in English, its working fine. when i scan the qr code it will give me this :
Seller Name: International Gold and Diamonds

but in Arabic, when i scan the qr code, it wont give me this, its showing diff. characters.
اسم البائع: العالمية للذهب والألماس

pls help. Thanks

Elvie

Capture1_jegwc5.jpg


Capture_mfxkjf.jpg
 
The first decodes to 'ÇÓã ÇáÈÇÆÚ: ÇáÚÇáãíÉ ááÐåÈ æÇáãÇÓ'.
Well, that's what displays with Western ANSI codepage.

This will display the arabic text:
Code:
_screen.FontName= "Arial"
_screen.FontCharSet = 178 && arabic 
? STRCONV('ÇÓã ÇáÈÇÆÚ: ÇáÚÇáãíÉ ááÐåÈ æÇáãÇÓ',2)

That means converting from DBCS (arabic) to single byte (with arabic script by FontCharSet.

FontCharset also is a property of many if not all VFP controls.
Other QR codes may use UTF-8, then you either need a control capable to display UTF-8, or use STRCONV with parameter 11.

Overall take a look at what STRCONV offers, there are a lot of conversion possiniliies.

Also the usual basis for international applications supportingmore thanjust the western (latin) alphabets with some special chars is INTL Toolkit, now on Github:

Take a look into that, and you will succeed to integrate more languages, practically any.

Edit: Bummer, a Ú within code tags is converted to HTML Entity Ú
This will do the job:

_screen.FontName= "Arial"
_screen.FontCharSet = 178 && arabic
? STRCONV('ÇÓã ÇáÈÇÆÚ: ÇáÚÇáãíÉ ááÐåÈ æÇáãÇÓ',2)

May depend on your current VFP codepage, too.

Chriss
 
hi sir,

i tried using strconv, but same result.
i think the issue is on foxbarcodeqr QRCodeLib.dll library.

cString="اسم البائع: العالمية للذهب والألماس"
loFbcQ = CREATEOBJECT("FoxBarcodeQR")
loFbcQ.nCorrectionLevel = 1

in report,
loFbcQ.FullQRCodeImage(cString, , 6 * 33, 1))

my conclusion :
cString variable is already in arabic text, but the generated qrcode of FoxBarcodeQR is showing different characters.
its like the QRCodeLib.dll does not recognize the arabic text (unicode characters).
there should be some setting or property of the library to set.
like :
loFbcQ.QrCodeEncodingName="utf-8"

something like that.


Elvie



 
You missed, that I got the arabic textfrom your QR code, just by STRCONV(decoded,2) after decoding it not before creating the QR, the QR code is fine, it just needs to be interpreted by STRCONV of the resulting ANSI text.

Here's a screenshot of what your QR code gives me:

arabic_lfy455.png


If you want to encode Unicode, you have to pass unicode into the QR image creation. VFP doesn't use Unicode in source code, that's always ANSI, also when it's arabic text. So this needs conversion.
a QR code is simply encoding the bytes. A typical QR decoder on a smartphone just by default assumes it's UTF-8. So if you encode for such "dumb" apps not aware of anything but UTF-8, you have to convert to UTF-8 before creating the QR image. But after you got the decoded bytes it's just up to you to display them correctly, if they're just ANSI, then that's okay for any software decoding ANSI, too, right codepage, of course.

So to encode UTF-8 into the QR Code you would do:
Code:
cString="اسم البائع: العالمية للذهب والألماس"
loFbcQ = CREATEOBJECT("FoxBarcodeQR")
loFbcQ.nCorrectionLevel = 1
loFbcQ.FullQRCodeImage(Strconv(cString,9),, , 6 * 33, 1))

also try
Code:
loFbcQ.FullQRCodeImage(Strconv(Strconv(cString,1),9),, , 6 * 33, 1))


There will very likely be conversions confusions with this as any internet forum encodes all its text in UTF-8, usually. So to give you the exact bytes you need to encode by QR for UTF-8, that's:
Code:
cString=''+0hC387C393C3A320C387C3A1C388C387C386C39A3A20C387C3A1C39AC387C3A1C3A3C3ADC38920C3A1C3A1C390C3A5C38820C3A6C387C3A1C3A3C387C393
loFbcQ = CREATEOBJECT("FoxBarcodeQR")
loFbcQ.nCorrectionLevel = 1
loFbcQ.FullQRCodeImage(cString,, , 6 * 33, 1))

If you want to print Unicode (Microsofts UCS-2 little endian), that's:
''+0hC700D300E3002000C700E100C800C700C600DA003A002000C700E100DA00C700E100E300ED00C9002000E100E100D000E500C8002000E600C700E100E300C700D300

You get back what you put in, just have to interpret it correctly. If it's about decoding in mobile devices or in apps, The UTF-8 bytes should work. If you want to decode the QR image back into VFP strings, your QR code already allows that.

Chriss
 
hi sir,

Thank you for your time in answering my queries.
It is working now. i tried your code below :

loFbcQ.FullQRCodeImage(Strconv(Strconv(cString,1),9),, , 6 * 33, 1))

the only issue, spaces are converted to ?.

Capture2_f3kj2g.jpg


for ?, i can use strtran to remove it.
strtran(Strconv(Strconv(cString,1),9),"?"," ")

And, how to convert Strconv(Strconv(cString,1),9) in version 6.
I tried some other utf encode in internet, results are wrong.
STRCONV is not working in v6.

Thank you.

Elvie
 
In VFP6 STRCONV has fewer options, that's true. I thinkWindows offers some conversion functions in its API, but I have to look into this.

Is that the source of the questionmarks for spaces?

The decoding looks like this with the online decoder:
decoder_bykqn0.png


The decoded raw bytes are neither equal to the UTF-8 nor the UCS Unicode representation I found.

What is displayed when you do
Code:
? Createbinary(cString)

Before you use any STRCONV() conversion of the arabic text in your source code.
And what's your codepage?
Code:
? cpcurrent()
Is it 1256?

Chriss
 
hi sir,

cpcurrent() value is 1256
Createbinary(cString) value is

Capture4_zasf5t.jpg


i tried this :
loFbcQ.FullQRCodeImage(Strconv(createbinary(cString),9),, , 6 * 33, 1))

and the result is correct now without ? as spaces.

Capture6_aodnlu.jpg



i just need to convert STRCONV(,9) in v6.

i really did appreciate your help. Thank you.


Elvie
 
Good,

(it was actually the first thing you should have tried, but good you found your way).

STRCONV(string,9) means conversion from ANSI (in your case codepage 1256 into UTF-8).

Well, lets google that:

1. The topic is string conversion:

2. Codepages (you can also find a list in the Foxpro Help):

Since MultiByteToWideChar converts anything but UTF-16 to UTF-16 and WideCharToMultiByte converts UTF-16 to anything but UTF-16, you need to combine them when you want to convert frm the arabic ANSI codepage 1256 (that's within the "anyting else but UTF-16" section) to UTF-8 (which also is in the "anyting else but UTF-16" section).

So a combination of both is necessary. I'll be back with a sample when I manage to get your ANSI raw bytes to the QR code bytes.

Chriss
 
The raw bytes of the decoded QR code with the correct decoding result are
43 dd 8a 7d 8b 3d 98 52 0d 8a 7d 89 4d 8a 8d 8a
7d 8a 6d 8b 93 a2 0d 8a 7d 98 4d 8b 9d 8a 7d 98
4d 98 5d 98 ad 8a 92 0d 98 4d 98 4d 8b 0d 98 7d
8a 82 0d 98 8d 8a 7d 98 4d 98 5d 8a 7d 8b 30 ec

The raw bytes of the UTF8 string that is your arabic text are
D8 A7 D8 B3 D9 85 20 D8 A7 D9 84 D8 A8 D8 A7 D8
A6 D8 B9 3A 20 D8 A7 D9 84 D8 B9 D8 A7 D9 84 D9
85 D9 8A D8 A9 20 D9 84 D9 84 D8 B0 D9 87 D8 A8
20 D9 88 D8 A7 D9 84 D9 85 D8 A7 D8 B3

I guess I have to compensate working in codepage 1252 instead of 1256, to get to the same result. One last question, though, what is this on your system (in VFP9):

Code:
? Createbinary(Strconv(cString,9))

Chriss
 
hi sir

Createbinary(Strconv(cString,9)) value is

Capture7_i6p44f.jpg


i tried this :
loFbcQ.FullQRCodeImage(Createbinary(Strconv(cString,9)) ,, , 6 * 33, 1))

i am getting same result as Strconv(createbinary(cString),9)

اسم البائع: العالمية للذهب والألماس


Thank you.

Elvie
 
Then that's the same I got, The question now becomes why the raw bytes from the QR code differ from these UTF-8 bytes.

This code converts cString to lcUTF8Buffer (I think it's safe to use RTRIM(lcUTF8Buffer) to get the UTF8 to pass to FoxBarCodeQR):

Code:
DECLARE INTEGER MultiByteToWideChar IN kernel32;
	INTEGER  CodePg,;
	LONG     dwFlags,;
	STRING   lpMultiByteStr,;
	INTEGER  cbMultiByte,;
	STRING @ lpWideCharStr,;
	INTEGER  cchWideChar
	
DECLARE INTEGER WideCharToMultiByte IN kernel32;
	INTEGER  CodePg,;
	INTEGER  dwFlags,;
	STRING   lpWideCharStr,;
	INTEGER  cchWideChar,;
	STRING @ lpMultiByteStr,;
	INTEGER  cbMultiByte,;
	STRING   lpDefaultChar,;
	INTEGER  lpUsedDefaultChar
	
cString = ''+0hC7D3E320C7E1C8C7C6DA3A20C7E1DAC7E1E3EDC920E1E1D0E5C820E6C7E1E3C7D3

clear
*lcUTF8ByStrconv = STRCONV(cString,9,,)
*? CREATEBINARY(lcUTF8ByStrconv) && just for comparison what's the original VFP9 result.

LOCAL lcUTF16Buffer, lcUTF8Buffer
* Be generous with the bytes, usually double as many should suffice
* 2 for an eventual BOM, 4 for special surrogate characters that need two 16bit codepoints in UTF-16,
* (in the worst case all characters), 3 for three terminating 0 bytes.
lcUTF16Buffer = SPACE(2+4*LEN(cString)+3)
lcUTF8Buffer = SPACE(2+4*LEN(cString)+3)

lnResult = MultiByteToWideChar(1256,0,cString,LEN(cString),@lcUTF16Buffer,LEN(cString))
IF lnResult <> 0
   lnResult = WideCharToMultiByte(65001, 0x0080, @lcUTF16Buffer, LEN(cString), @lcUTF8Buffer, LEN(lcUTF8Buffer),0,0)
ENDIF 

IF lnResult <> 0
   ? CREATEBINARY(lcUTF16Buffer)
   ?
   ? CREATEBINARY(lcUTF8Buffer)
ENDIF

_cliptext = TRANSFORM(CREATEBINARY(RTRIM(lcUTF8Buffer)))

If any result is 0 GetLastError API function will tell about an error that happened.

Elvie said:
i am getting same result as Strconv(createbinary(cString),9)
Yes, Createbinary doesn't really do anything, it just enables you to get the hexadecimal codes for the bytes of a string. That's universal, no matter with which codepage your Windows or VFP IDE works, so such representations of ANSI strings in code are universally usable. Whether you pass Createbinary(string) or string itself to any function as string parameter won't change the outcome.

So createbinary() is more like an inline hex editor, which only shows a file in hex, it doesn't convert the file it edits.

Chriss
 
It's not so easy to use this as an expression for a report. I would create a PRG to do this conversion from Ansi 1256 to UTF8 and use that in the report.

If you prepare the buffers before running the report I think you could print something like this:
Code:
IIF(MultiByteToWideChar(...)<>0,IIF(WideCharToMultiByte(...)<>0,RTRIM(lcUTF8Buffer),'Error in WideCharToMultibyte conversion'),'Error in MultiByteToWideChar conversion')

Chriss
 
hi sir,

i was able to make it work in v6 using this and its working perfectly.

loFbcQ.FullQRCodeImage(utf8encode(cString) ,, , 6 * 33, 1))

function utf8encode(cStrText)
IF TYPE("cStrText")<>"C"
cStrText=""
ENDIF
LOCAL cRetVal As String
cFilen=FORCEEXT(SYS(2015),"txt")
lcFile=ADDBS(SYS(2023))+cFilen
ado=CREATEOBJECT("ADODB.Stream")
ado.Type=2
ado.Charset="utf-8"
ado_Open
ado.WriteText(cStrText)
ado.SaveToFile(lcFile,2) && adSaveCreateOverWrite
ado.Close
cRetVal=FILETOSTR(lcFile)
ERASE &lcFile
RETURN cRetVal
endfunc

Thank you so much for your generous time and for pointing me on the right direction.
It was really a great help!


Elvie [smile2]
 
Great,

I see the output differs slightly:

Code:
utf8encode:
0h[highlight #FCE94F]EFBBBF[/highlight]C387C393C3A320C387C3A1C388C387C386C39A3A20C387C3A1C39AC387C3A1C3A3C3ADC38920C3A1C3A1C390C3A5C38820C3A6C387C3A1C3A3C387C393
Strconv(,9) (only available in VFP9 (and the API functions, too):
0hC387C393C3A320C387C3A1C388C387C386C39A3A20C387C3A1C39AC387C3A1C3A3C3ADC38920C3A1C3A1C390C3A5C38820C3A6C387C3A1C3A3C387C393

The difference is just a BOM, byte order mark, it can tell a decoder what the string is, but is not generally supported, so you actually wouldn't want to enccode the BOM with the UTF-8 string.

ADODB.Stream is working, but I wonder if you really need to go through a file to get the converted output and why not use the API functions? You could also put them into a function (or PRG). If you'Re unsure about the right buffer size: A too size doesn't harm, only a too low size. You can use the API functions to tell you the exact necessary size, too.But that just doubles the call to these functions.

Let me see, I guess the ADO.Stream also will return the utf8 string without saving to a file.

It's possible, the ADO Stream just needs to be switched from Type 2 (adTypeText) to Type 1 (adTypeBinary), so the Read() method returns the UTF8 bytes. If you want or need the BOM, then Read from Position 0, setting Position to 3 cuts off the UTF-8 BOM. A complication is you can only switch the Type when the Position is reset to 0, and only after switching the Type you can set Position to 3 meaning skip 3 bytes (not 3 characters).

Code:
Function UTF8Encode(cStrText)
   #Define adTypeBinary	1
   #Define adTypeText	2
   If Type("cStrText")<>"C"
      cStrText=""
   Endif
   Local cRetVal As String, ado As ADODB.Stream

   ado=Createobject("ADODB.Stream")
   ado.Type = adTypeText
   ado.Charset="utf-8"
   ado.Open()
   ado.WriteText(cStrText)
   ado.SetEOS()
   ado.Position = 0
   ado.Type = adTypeBinary
   ado.Position = 3
   cRetVal=ado.Read()
   ado.Close()
   
   Return cRetVal
Endfunc

This returns 0hC387C393C3A320C387C3A1C388C387C386C39A3A20C387C3A1C39AC387C3A1C3A3C3ADC38920C3A1C3A1C390C3A5C38820C3A6C387C3A1C3A3C387C393 or the UTF-8 bytes for your text.

Of course a nice side effect of this function is, you could generalize this, by defining a charset parameter:

Code:
Function ConvertStringToCharset(cStrText, cCharset)
   #Define adTypeBinary	1
   #Define adTypeText	2
   If Type("cStrText")<>"C"
      cStrText=""
   Endif
   Local cRetVal As String, ado As ADODB.Stream

   ado=Createobject("ADODB.Stream")
   ado.Type = adTypeText
   cErrorhandler = On('Error')
   On Error *
   ado.Charset = cCharset
   On Error &cErrorhandler

   If not ado.Charset==cCharset
      Error 'charset '+cCharset+' is not supported.'
   Endif   
   ado.Open()
   ado.WriteText(cStrText)
   ado.SetEOS()
   ado.Position = 0
   ado.Type = adTypeBinary
   cRetVal=ado.Read()
   ado.Close()
   
   Return cRetVal
Endfunc

Chriss
 
hi sir,


you're right i could use read() rather than saving to file.
Thank you for pointing out.


Elvie [smile2]
 
hello
I appreciate your help. I need to display the Arabic text because I could not apply the code
Please help me. I appreciate your help. Please send a demo project that shows this
please contact me [love2]
I will send a print sample, please put the code in the correct place
best regards
Thank you very much
 
Thank you very much for the quick reply
Yes, QR printing with Arabic text does not display text fine
Please help me how to print Arabic and what are the settings in the control panel
This is a print shown in a picture with a barcode printing project. Please help in modifying a project
Thank you very much
best regards
barcod1_pnsnua.png


[URL unfurl="true"]https://res.cloudinary.com/engineering-com/raw/upload/v1637507015/tips/PRG_ar0rar.rar[/url]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top