4

I have an Odoo implementation, and I need to print Arabic words to an ESC/POS printer.

The Odoo community has already developed a Python module that translates UTF-8 text to ESC/POS Code Page. The problem is that when I print Arabic text I'm getting reversed text and disconnected letters.

How do I print correct Arabic word from Python to ESC/POS?

See the Escpos.text method from escpos.py for reference.

Jongware
  • 22,200
  • 8
  • 54
  • 100
Radwan S
  • 51
  • 1
  • 5
  • I'd guess your Arabic text is supposed to be displayed from right to left, rather than left to right. If the printer can only do left to right text, you might need to edit the encoding conversion code to also reverse the character order whenever appropriate. I think there are special Unicode characters that tell you when the direction of text changes, but I'm not well enough informed on the details to describe how it works in an answer. – Blckknght Aug 01 '16 at 21:18
  • "Printing Arabic text correctly" is *not* merely converting from UTF8 to your printer's character set. As you have seen, (1: "reversed") the text needs to appear right-to-left, while the codes are (most likely) send in left-to-right order. But software can fix that, trivially. Alas, (2: "disconnected") correctly calculate initial, medial, and final joining characters is a bit harder. – Jongware Aug 01 '16 at 21:21
  • (For interested lurkers: Arabic letters need joining to form proper words. What Radwan sees now is the analog of `TEXTLIKETHIS`. And it's in the wrong order as well, so `SIHTEKILEROM`.) – Jongware Aug 01 '16 at 21:23
  • 1
    … not to mention neat things like terminal forms, where letters take different shapes depending where they are in the word. And ligatures! Lotsa ligatures — it's a very calligraphic written form. I don't know if the simple thermal printers are quite up to doing acceptable Arabic in text mode. Here's a potential duplicate question, with an answer that might work: [How to print right-to-left report on odoo 8](https://stackoverflow.com/questions/35317338/how-to-print-right-to-left-report-on-odoo-8 "How to print right-to-left report on odoo 8") – scruss Aug 02 '16 at 12:22
  • It's possible using a conversion library such as ICU and IBM-864 encoding. A Java example is available here: https://github.com/qzind/tray/issues/304 – tresf Oct 21 '18 at 05:42

1 Answers1

4

As noted in the comments, it is not a trivial task display UTF-8 Arabic text correctly on an embedded device. You need to handle text direction, joining and character encoding.

I've had an attempt at this in the past for a PHP ESC/POS driver that I maintain, and was unable to get joined Arabic characters in native ESC/POS. However, I did end up settling on this workaround (PHP) that printed images instead.

The basic steps to working around this are:

  • Get an Arabic font, some text libraries, and an image library
  • Join ('reshape') the characters
  • Convert the UTF-8 to LTR (print) order, using the bidi text layout algorithm
  • Slap it on an image, right aligned
  • Print the image

To port this to python, I lent on this answer using Wand. The Python Image Library (PIL) was displaying diacritics as separate characters, making the output unsuitable.

The dependencies are listed in the comments.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Print an Arabic string to a printer.
# Based on example from escpos-php

# Dependencies-
# - pip install wand python-bidi python-escpos
# - sudo apt-get install fonts-hosny-thabit
# - download arabic_reshaper and place in arabic_reshaper/ subfolder

import arabic_reshaper
from escpos import printer
from bidi.algorithm import get_display
from wand.image import Image as wImage
from wand.drawing import Drawing as wDrawing
from wand.color import Color as wColor

# Some variables
fontPath = "/usr/share/fonts/opentype/fonts-hosny-thabit/Thabit.ttf"
textUtf8 = u"بعض النصوص من جوجل ترجمة"
tmpImage = 'my-text.png'
printFile = "/dev/usb/lp0"
printWidth = 550

# Get the characters in order
textReshaped = arabic_reshaper.reshape(textUtf8)
textDisplay = get_display(textReshaped)

# PIL can't do this correctly, need to use 'wand'.
# Based on
# https://stackoverflow.com/questions/5732408/printing-bidi-text-to-an-image
im = wImage(width=printWidth, height=36, background=wColor('#ffffff'))
draw = wDrawing()
draw.text_alignment = 'right';
draw.text_antialias = False
draw.text_encoding = 'utf-8'
draw.text_kerning = 0.0
draw.font = fontPath
draw.font_size = 36
draw.text(printWidth, 22, textDisplay)
draw(im)
im.save(filename=tmpImage)

# Print an image with your printer library
printer = printer.File(printFile)
printer.set(align="right")
printer.image(tmpImage)
printer.cut()

Running the script gives you a PNG, and prints the same to a printer at "/dev/usb/lp0".

Output example

This is a standalone python-escpos demo, but I'm assuming that Odoo has similar commands for alignment and image output.

Disclaimer: I don't speak or write Arabic even slightly, so I can't be sure this is correct. I'm just visually comparing the print-out to what Google translate gave me.

Google translate in use

Community
  • 1
  • 1
mike42
  • 1,608
  • 14
  • 24
  • Turns out it's technically possible using a conversion library such as ICU and IBM-864 encoding. A Java example is available here: https://github.com/qzind/tray/issues/304 – tresf Oct 21 '18 at 05:43