Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
22
Help us understand the problem. What is going on with this article?
@SatoshiGachiFujimoto

Pythonからサーマルプリンタ「PAPERANG」の印刷できました(Windows10、Python3.6)

More than 1 year has passed since last update.

お待たせしました!
Pythonからサーマルプリンタ「PAPERANG」の印刷できました。

サンプルコード

ここからダウンロードしてください

環境構築

$ conda create -n paperang python=3.6
$ conda activate paperang
$ cd miaomiaoji-tool
$ pip install PyBluez-win10
$ pip install opencv-python

実行

$ python message_process.py

解説

ここからフォークしたものを変更してます。

message_process.pyを実行してみるとfilter関数でエラーが出ます。47行目と64行目のfilter関数をlistでくくります。Python3におけるmap/filterの使い方

valid_devices = list(filter(lambda d: len(d) == 2 and d[1] in valid_names, nearby_devices))
・・・
valid_service = list(filter(
    lambda s: 'protocol' in s and 'name' in s and s['protocol'] == 'RFCOMM' and s['name'] == 'SerialPort',
    service_matches
))

pybluezだと63行目のfind_serviceのところでOSErrorが出るため、PyBluez-win10を用いています。※OSError when program try to use functions from bluetooth._msbt #279

service_matches = find_service(uuid=self.uuid, address=self.address)

サービス名が見つからないエラーが出るので、service_matchesをprintして表示してみましょう。

[{'host': '00:15:83:B7:11:AF', 'name': b'SerialPort', 'description': '', 'port': 1, 'protocol': 'RFCOMM', 'rawrecord': b'5J\t\x00\x00\n\x00\x01\x00\x0f\t\x00\x015\x03\x19\x11\x01\t\x00\x045\x0c5\x03\x19\x01\x005\x05\x19\x00\x03\x08\x01\t\x00\x055\x03\x19\x10\x02\t\x00\x08\x08\xff\t\x00\t5\x085\x06\x19\x11\x01\t\x01\x02\t\x01\x00%\nSerialPort', 'service-classes': [b'1101'], 'profiles': [(b'1101', 258)], 'provider': None, 'service-id': None, 'handle': 65551}, {'host': '00:15:83:B7:11:AF', 'name': b'WeChat', 'description': '', 'port': 8, 'protocol': 'RFCOMM', 'rawrecord': b'5T\t\x00\x00\n\x00\x01\x00\x0e\t\x00\x015\x11\x1c\xe5\xb1R\xedkF\t\xe9Fxf^\x9a\x97,\xbc\t\x00\x045\x0c5\x03\x19\x01\x005\x05\x19\x00\x03\x08\x08\t\x00\x055\x03\x19\x10\x02\t\x00\x08\x08\xff\t\x00\t5\x085\x06\x19\x11\x01\t\x01\x02\t\x01\x00%\x06WeChat', 'service-classes': ['E5B152ED-6B46-09E9-4678-665E9A972CBC'], 'profiles': [(b'1101', 258)], 'provider': None, 'service-id': None, 'handle': 65550}]

'name': b'SerialPort'になっているため、65行目の'SerialPort'にbを付けます。

lambda s: 'protocol' in s and 'name' in s and s['protocol'] == 'RFCOMM' and s['name'] == b'SerialPort',

あとservice_matchesをprintしたときに、下記のstruct.packのエラーが出ます。

 File "message_process.py", line 88, in packPerBytes
    result += struct.pack('<i', self.crc32(bytes))
struct.error: argument out of range

88行目の <i を <I に変更しましょう。struct — Interpret bytes as packed binary data

result += struct.pack('<I', self.crc32(bytes))

次にencodeのエラーが出るため、

File "message_process.py", line 110, in recv
    logging.info("Recv: " + raw_msg.encode('hex'))
AttributeError: 'bytes' object has no attribute 'encode'

110行目と122行目の.encode('hex')を.hex()に変えます。How do I fix AttributeError: 'bytes' object has no attribute 'encode'?

logging.info("Recv: " + raw_msg.hex())
・・・
, self.payload_length, self.payload.hex()

image_process.pyでmap関数のエラーが出るため、32行目のmap関数をlistでくくります。

File "\miaomiaoji-tool\image_process.py", line 20, in frombits
    for b in range(len(bits) / 8):
TypeError: object of type 'map' has no len()

また、20行目のfor文のrangeの範囲がfloatになっているので、intにキャストします。

for b in range(int(len(bits) / 8)):

153行目のstruct.packでエラーが出るので、コメントアウトしてOKです。

# msg = struct.pack("<%dc" % len(binary_img, *binary_img)

300行のラインを印刷するには、バイナリにする必要があります。sendImageToBtの中身はmsgにそのままバイナリの文字列を入れています。

def sendImageToBt(self, binary_img):
    self.sendPaperTypeToBt()
    # msg = struct.pack("<%dc" % len(binary_img, *binary_img)
    msg = binary_img
    self.sendToBt(msg, BtCommandByte.PRT_PRINT_DATA, need_reply=False)
    self.sendFeedLineToBt(self.padding_line)

# Print a pure black image with 300 lines
img = b'\xff' * 48 * 300
mmj.sendImageToBt(img)

印刷できました。
86242649_182835276314024_4717528697094012928_n.jpg

実は、self.sendToBtには各lineごとに送信する必要があります。

def sendImageToBt(self, binary_img):
    self.sendPaperTypeToBt()
    # msg = struct.pack("<%dc" % len(binary_img, *binary_img)
    msgs = [binary_img[x: x+192] for x in range(0, len(binary_img), 192)] # 4*48
    for msg in msgs:
        self.sendToBt(msg, BtCommandByte.PRT_PRINT_DATA, need_reply=False)
    self.sendFeedLineToBt(self.padding_line)

これが本当の300行のラインです。sendBinaryToBtという関数名に変えました。

86189532_333920134236910_8458868322023243776_n.jpg

\xffが黒で、\x00が白になります。\xffを二進数にするとわかりやすいのですが、\xffは0b11111111となり8本の黒い縦のラインが引かれることになります。なので、8ビットで画像の8ピクセル分を表現することになります。横のラインの幅は'\xff'が48個分までです。つまり、画像幅は8×48=384ピクセルになります。

画像をリサイズ、二値化し、[0,1]の値に変換、8ピクセルずつ16進数に変換し、各行ごとにプリントします。

def sendImageToBt(self, binary_img):
    self.sendPaperTypeToBt()
    height, width = binary_img.shape[:]
    for line in range(height):
        bits = [0 if x > 0 else 1 for x in binary_img[line]]
        bits = [bits[x:x+8] for x in range(0, len(bits), 8)]
        msg = ''
        for bit in bits:
            bin = '0b'+''.join(str(x) for x in bit)
            msg += '{:02x}'.format(int(bin, 0))
        msg = bytes.fromhex(msg)
        self.sendToBt(msg, BtCommandByte.PRT_PRINT_DATA, need_reply=False)
    self.sendFeedLineToBt(self.padding_line)

・・・
# Print an existing image(need opencv):
img = cv2.imread('kumamcn.png', 0)
ret, binary_img = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
height, width = binary_img.shape[:]
binary_img = cv2.resize(binary_img, (384, int(height*384.0/width)), cv2.INTER_AREA)
mmj.sendImageToBt(binary_img)

完成です。これで任意の画像を印刷できます!
86259996_614941075716724_5170025822672650240_n.jpg

この記事が役に立ったらガチ本に生牡蠣をおごってください。

22
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
SatoshiGachiFujimoto
高専で制御を学び、大学でセンシングを学び、次は脳みそ。SLAMに関連したロボット/ドローンやMRの研究開発をしています。
knowledgecommunication-inc
クラウドインテグレーター、AI・VRの分野で様々なソリューションを展開

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
22
Help us understand the problem. What is going on with this article?