Question

I am trying to use a Python program to read a series of non-western (Japanese/Chinese) Unicode character strings from an Excel .xls file and create an image file for each string. The xlrd module gives me the Unicode strings from the Excel file, where they are properly displayed.

An answer to a previous question provided some of the basic elements to use the Windows API in Python to render normal western text into an image file. However, if I change to the basic call to render 2 Japanese characters from a Unicode text string as:

f = Win32Font("MS Gothic", 24)
im = f.renderText(u'\u30bb\u30c3')
im.save("hope.png")

The code fails: UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

Any help in using the Windows API to properly render the Unicode strings would be greatly appreciated.

No correct solution

OTHER TIPS

You need to use the Unicode version of the Win32Api. At a quick glance of the link from the other question, you at least need win32gui.DrawTextW instead of win32ui.DrawText in the Win32Font implementation. Note win32gui is the native API not the MFC API that win32ui wraps. I didn't see a way to use the Unicode version of MFC calls in my quick look of the pywin32 docs, so you'll need to get the native handle out of the PyCDC using GetSafeHdc to use it with the native API.

Post a complete example if you need more help than that.

I have spent dozens of hours looking for a unicode ...W win32... function, until the answer by Mark Tolonen, which I have immediately implemented into a working example whose code follows below. If all goes right, your printer should output a string "汉字、にほんご、עברית、عربي我都会刷出。".

# -*- coding: utf-8 -*-

import win32ui, win32con, win32gui, win32print, traceback

# init, bla bla bla
printername = win32print.GetDefaultPrinter()
hprinter = win32print.OpenPrinter(printername)
# load default settings
devmode = win32print.GetPrinter(hprinter, 8)["pDevMode"]
# this is where it gets INTERESTING:
# after the following two lines, use:
# dc for win32ui calls like LineTo, SelectObject, ...
# hdc for DrawTextW, your *MAGIC* function that supports unicode output
hdc = win32gui.CreateDC("WINSPOOL", printername, devmode)
dc = win32ui.CreateDCFromHandle(hdc)

# 1440 twips = 1 inch
dc.SetMapMode(win32con.MM_TWIPS)
# 20 twips = 1 pt
scale_factor = 20

# start the document, description as unicode
description = u'Test1'
dc.StartDoc(description)

# when working with the printer, enclose any potentially failing calls within a try block,
# because if you do not properly end the print job (see bottom), after a couple of such failures,
# you might need to restart windows as it runs out of handles or something and starts
# behaving in an unpredictable way, some documents fail to print, you cannot open windows, etc.

try :

    # Use a font
    font = win32ui.CreateFont({
        "name": "Arial Unicode MS", # a font name
        "height": int(scale_factor * 10), # 10 pt
        "weight": 400, # 400 = normal
    })

    # use dc -- SelectObject is a win32ui call
    dc.SelectObject(font)

    # this is the miracle where the unicode text gets to be printed; notice hdc,
    # not dc, for DrawTextW uses a different handle, i have found this in other posts
    win32gui.DrawTextW (hdc, u"\u6C49\u5B57\u3001\u306B\u307B\u3093\u3054\u3001\u05E2\u05D1\u05E8\u05D9\u05EA\u3001\u0639\u0631\u0628\u064A\u6211\u90FD\u4F1A\u5237\u51FA\u3002", -1, (0, -2000, 4000, -4000), win32con.DT_CENTER)

except :
    traceback.print_exc()

# must not forget to tell Windows we're done. This line must get called if StartDoc 
# was called, if you fail to do so, your sys might start behaving unexpectedly
dc.EndDoc()
# -*- coding: utf-8 -*-

import win32ui, win32con, win32gui, win32print, traceback

# init, bla bla bla
printername = win32print.GetDefaultPrinter()
hprinter = win32print.OpenPrinter(printername)
# load default settings
devmode = win32print.GetPrinter(hprinter, 8)["pDevMode"]
# this is where it gets INTERESTING:
# after the following two lines, use:
# dc for win32ui calls like LineTo, SelectObject, ...
# hdc for DrawTextW, your *MAGIC* function that supports unicode output
hdc = win32gui.CreateDC("WINSPOOL", printername, devmode)
dc = win32ui.CreateDCFromHandle(hdc)

# 1440 twips = 1 inch
dc.SetMapMode(win32con.MM_TWIPS)
# 20 twips = 1 pt
scale_factor = 20

# start the document, description as unicode
description = u'Test1'
dc.StartDoc(description)

# when working with the printer, enclose any potentially failing calls within a try block,
# because if you do not properly end the print job (see bottom), after a couple of such failures,
# you might need to restart windows as it runs out of handles or something and starts
# behaving in an unpredictable way, some documents fail to print, you cannot open windows, etc.

try :

    # Use a font
    font = win32ui.CreateFont({
        "name": "Arial Unicode MS", # a font name
        "height": int(scale_factor * 10), # 10 pt
        "weight": 400, # 400 = normal
    })

    # use dc -- SelectObject is a win32ui call
    dc.SelectObject(font)

    # this is the miracle where the unicode text gets to be printed; notice hdc,
    # not dc, for DrawTextW uses a different handle, i have found this in other posts
    win32gui.DrawTextW (hdc, u"\u6C49\u5B57\u3001\u306B\u307B\u3093\u3054\u3001\u05E2\u05D1\u05E8\u05D9\u05EA\u3001\u0639\u0631\u0628\u064A\u6211\u90FD\u4F1A\u5237\u51FA\u3002", -1, (0, -2000, 4000, -4000), win32con.DT_CENTER)

except :
    traceback.print_exc()

# must not forget to tell Windows we're done. This line must get called if StartDoc 
# was called, if you fail to do so, your sys might start behaving unexpectedly
dc.EndDoc()


How to use this code to print bmp file? i need print qr code i have bmp file i get this error - ( win32gui.DrawTextW(hdc, img, -1, (0, -2100, 4000, -4000), win32con.DT_CENTER) TypeError: Objects of type 'PilImage' can not be converted to Unicode.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top