リンク

2017年6月28日水曜日

pythonで画像からQRコードを読み込む


今回は、pythonを使って画像ファイル内のQRコード内容を取得する方法をご紹介します。

環境
  • macOS Sierra 10.12.5
  • python 3.4


モジュールのインストール
今回使用するのは「pyzbarモジュール」です。
python2系では「zbarモジュール」が使えるのですが、3系には対応していません。
なので「pyzbarモジュール」を使用します。

Windowsの方はコマンドプロンプト、Macの方はターミナルを起動し、次のコマンドを実行してください。
>> pip install pyzbar
もしくは下記のページからソースを直接ダウンロードしてください。
https://pypi.python.org/pypi/pyzbar/

pyzbarモジュールだけでなく「PILモジュール」も必要です。
未入手の方は次のコマンドで合わせて入手してください。
>> pip install pillow

さらに、大元となる「ZBar」も必要です。
下記のページにアクセスし、別途ダウンロードを行なってください。
http://zbar.sourceforge.net/
Macの方はHomebrewが使える状態であれば、次のコマンドでもダウンロード&インストールが完了しますので楽チンです。
>> brew install zbar

以上で環境の構築は完了です。


使用する画像
今回はpythonでQRコード画像を作成するで作成した画像ファイルを使用します。


スクリプト
pythonスクリプトファイルと同じフォルダ内にある「test.png」にアクセスし、その中のQRコード内容を出力するサンプルです。
# -*- coding: UTF-8 -*-

from pyzbar.pyzbar import decode
from PIL import Image

# 画像ファイルの指定
image = "test.png"

# QRコードの読取り
data = decode(Image.open(image))

# コード内容を出力
print(data[0][0].decode('utf-8', 'ignore'))



2017年6月27日火曜日

pythonでQRコード画像を作成する

今回は、pythonを使ってQRコードを作成する方法をご紹介します。

環境
  • macOS Sierra 10.12.5
  • python 3.4

モジュールのインストール
今回使用するのは「PyQRCodeモジュール」です。
Windowsの方はコマンドプロンプト、Macの方はターミナルを起動し、次のコマンドを実行してください。
>> pip install pyqrcode

pipが使用できない場合は以下よりソースファイルを取得し、中のsetup.pyを実行してください。
https://pypi.python.org/pypi/PyQRCode

また、ご利用の環境によっては「pypngモジュール」を別途インストールする必要があります。
>> pip install pypng
もしくは
https://pypi.python.org/pypi/pypng

モジュールの用意が整っている前提で進めます。


基本スクリプト
# -*- coding: UTF-8 -*-

import pyqrcode

a = pyqrcode.create(content='本日は晴天ナリよ')
a.png(file='test.png')

実行結果
pythonスクリプトと同じフォルダ内にtest.pngができます。
とても小さい画像になってしまいました。
これはQRコードの内容が非常に少ないからです。
内容に比例して画像サイズも大きくなります。


pythonでXMLファイルを操作する

今回はpythonからXMLファイルを開き、情報を取得&編集する方法をご紹介します。

環境
  • macOS Sierra 10.12.5
  • python 3.4

    モジュールのインストール
    今回使用するのは「xmlモジュール」です。
    これは標準モジュールなので、意識して削除していない限りインストールせずに使用することができます。


    XMLファイル
    今回はサンプルとして、下記の内容が記述されたXMLファイルを使用します
    <?xml version='1.0' encoding='utf-8'?>
    <root>
        <dir>C:\Bridge Software</dir>
        <class>
            <point>50</point>
            <name>Bridge</name>
        </class>
        <class>
            <point>100</point>
            <name>soft</name>
        </class>
        <class>
            <point>150</point>
            <name>ware</name>
        </class>
        <change>999</change>
    </root>

    pythonスクリプト(読み込み)
    ここでは例として、XMLファイル内から「dir」タグの内容と「name」タグの内容を取得します。
    # -*- coding: UTF-8 -*-
    
    # モジュールのインポート
    import xml.etree.ElementTree as ET
    
    # xmlファイルの読み込み
    tree = ET.parse('test.xml')
    
    # dirタグ
    dir_text = tree.find('dir').text
    print(dir_text)
    
    # nameタグ
    names = tree.findall('class/name')
    for name in names:
        print(name.text)

    実行結果
    ちゃんと読み取れました。


    pythonでフォルダを監視する

    今回はpythonで特定のフォルダを監視し、ファイルの発生や削除などを検知する方法をご紹介します。

    環境
    • macOS Sierra 10.12.5
    • python 3.4
    •  
       
    モジュールのインストール
    今回使用するのは「watchdogモジュール」です。
    Windowsの方はコマンドプロンプト、Macの方はターミナルを起動し、次のコマンドを実行してください。
    >> pip install watchdog

    pipが使用できない場合は以下よりソースファイルを取得し、中のsetup.pyを実行してください。
    https://pypi.python.org/pypi/watchdog

    モジュールの用意が整っている前提で進めます。

    スクリプト
    # -*- coding: utf-8 -*-
    
    from watchdog.events import FileSystemEventHandler
    from watchdog.observers import Observer
    
    import os
    import time
    
    target_dir = "監視したいフォルダのパス"
    
    
    class ChangeHandler(FileSystemEventHandler):
        def on_created(self, event):
            filepath = event.src_path
            filename = os.path.basename(filepath)
            print('%sができました' % filename)
    
        def on_modified(self, event):
            filepath = event.src_path
            filename = os.path.basename(filepath)
            print('%sを変更しました' % filename)
    
        def on_deleted(self, event):
            filepath = event.src_path
            filename = os.path.basename(filepath)
            print('%sを削除しました' % filename)
    
    
    if __name__ in '__main__':
        while 1:
            event_handler = ChangeHandler()
            observer = Observer()
            observer.schedule(event_handler, target_dir, recursive=True)
            observer.start()
            try:
                while True:
                    time.sleep(0.1)
            except KeyboardInterrupt:
                observer.stop()
            observer.join()

    wxPythonでダイアログの多重起動を防止する

    突然ですが、Excelを使ったことはありますか?
    圧倒的大多数の方はYESだと思います。

    Excelの機能の一つに「検索」があります。
    「Ctrl」 + 「F」キーでダイアログが表示されますね。
    あのダイアログ、いくつも同時に表示することはできません。
    でも表示させたままで他の作業をすることはできます。

    よくよく考えたら不思議。
    どうなっているんだろう?

    今回はそんなお話です。

    環境
    • macOS Sierra 10.12.5
    • python 3.4
    • wxPython Phoenix 4.0.0

    悪いスクリプト
    まずは悪い見本のスクリプトを記述します。
    # -*- coding: UTF-8 -*-
    
    import wx
    
    class App(wx.Frame):
        """ GUI """
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, id, title, size=(300, 300))
    
            p = wx.Panel(self, wx.ID_ANY)
    
            button = wx.Button(p, wx.ID_ANY, 'click')
            button.Bind(wx.EVT_BUTTON, self.show_dialog)
    
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(button, flag=wx.ALL, border=10)
            p.SetSizer(layout)
    
            self.Show()
    
        def show_dialog(self, event):
            dialog = CustomDialog(self)
            dialog.Show()
    
    
    class CustomDialog(wx.Dialog):
        """ カスタムダイアログ """
    
        def __init__(self, parent):
            wx.Dialog.__init__(self, parent, wx.ID_ANY, 'だいあろぐ', size=(150, 100))
    
            p = wx.Panel(self, wx.ID_ANY)
    
            label = wx.StaticText(p, wx.ID_ANY, 'さんぷる だいあろぐ')
    
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(label, flag=wx.ALL, border=10)
            p.SetSizer(layout)
    
            self.Centre()
    
    
    app = wx.App()
    App(None, wx.ID_ANY, 'タイトル')
    app.MainLoop()

    <実行結果>


    解 説
    悪いスクリプトでは、ボタンのクリックイベント内で別途作成したカスタムダイアログ・クラスを呼び出しています。
    Excelの検索ダイアログのように、ダイアログを表示しながら他の作業ができるようにするにはモードレス表示にする必要がありますので「.ShowModal()」ではなく「.Show()」とする必要があります。

    この場合、多重起動を制御する文を記述していませんので、ボタンをクリックする度にカスタムダイアログが表示されてしまいます。

    良いスクリプト
    # -*- coding: UTF-8 -*-
    
    import wx
    
    class App(wx.Frame):
        """ GUI """
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, id, title, size=(300, 300), style=wx.DEFAULT_FRAME_STYLE)
    
            p = wx.Panel(self, wx.ID_ANY)
    
            button = wx.Button(p, wx.ID_ANY, 'click')
            button.Bind(wx.EVT_BUTTON, self.show_dialog)
    
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(button, flag=wx.ALL, border=10)
            p.SetSizer(layout)
    
            self.Show()
    
        def show_dialog(self, event):
    
            if self.FindWindowByName('だいあろぐ') is None:
                dialog = CustomDialog(self)
                dialog.Show()
            else:
                dialog = wx.MessageDialog(self, 'すでに表示されています', 'エラー', wx.ICON_ERROR) 
                dialog.ShowModal() 
                dialog.Destroy()
    
    
    class CustomDialog(wx.Dialog):
        """ カスタムダイアログ """
    
        def __init__(self, parent):
            wx.Dialog.__init__(self, parent, wx.ID_ANY, 'だいあろぐ', size=(150, 100))
    
            p = wx.Panel(self, wx.ID_ANY)
    
            label = wx.StaticText(p, wx.ID_ANY, 'さんぷる だいあろぐ')
    
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(label, flag=wx.ALL, border=10)
            p.SetSizer(layout)
    
            self.Centre()
    
    
    app = wx.App()
    App(None, wx.ID_ANY, 'タイトル')
    app.MainLoop()

    <実行結果> ↓ ↓ ↓

    wxPythonでアプリの多重起動を防止する

    様々なアプリケーションを作成していく中で、「同じアプリケーションが同時に実行されては困る」場合があります。

    今回はwxPythonで複数起動しないように制御する方法をご紹介します。

    環境
    • macOS Sierra 10.12.5
    • python 3.4
    • wxPython Phoenix 4.0.0


    それでは早速スクリプトです。
    # -*- coding: UTF-8 -*-
    
    import wx
    
    class App(wx.Frame):
        """ GUI """
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, id, title, size=(300, 300), style=wx.DEFAULT_FRAME_STYLE)
    
            # 二重起動の防止
            self.instance = wx.SingleInstanceChecker(self.GetTitle())
    
            if self.instance.IsAnotherRunning():
                dialog = wx.MessageDialog(None, '%sはすでに起動中です。' % self.GetTitle(), 'エラー', wx.ICON_ERROR)
                dialog.ShowModal()
                dialog.Destroy()
                wx.Exit()
    
            self.Show()
    
    
    app = wx.App()
    App(None, wx.ID_ANY, 'sample')
    app.MainLoop()

    <結果> ↓ ↓ ↓

    pythonでGUIツールを作る ~ ListCtrl (レポートビュー)~

    今回は数あるウィジットの中でもよく使用されるListCtrlについて書いていきます。

    環境
    • macOS Sierra 10.12.5
    • python 3.4
    • wxPython Phoenix 4.0.0

    wxPythonのListCtrlには以下の4つのスタイルがあります。
    1. wx.LC_ICON
    2. wx.LC_SMALL_ICON
    3. wx.LC_LIST
    4. wx.LC_REPORT
    今回はその中のwx.LC_REPORTをご紹介します。
    wx.LC_ICON、wx.LC_SMALL_ICON、wx.LC_LISTの3つについてはこちらをご覧ください。

     wx.LC_REPORTスタイルは「レポートビュー」と呼ばれ、いわゆる「詳細表示」を行うスタイルです。
    フォルダを詳細表示にした時の見た目と通じるものがありますね。


    それではスクリプトを記述します。
    # -*- coding: UTF-8 -*-
    
    import wx
    
    class App(wx.Frame):
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, id, title, size=(400, 300), style=wx.DEFAULT_FRAME_STYLE)
    
            # ステータスバー
            self.CreateStatusBar()
    
            # パネル
            p = wx.Panel(self, wx.ID_ANY)
    
            # インスタンス化
            self.listctrl = wx.ListCtrl(p, wx.ID_ANY, style=wx.LC_REPORT)
            self.listctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.item_select)
    
            # カラム
            self.listctrl.InsertColumn(0, "氏名", wx.LIST_FORMAT_LEFT, 150)
            self.listctrl.InsertColumn(1, "性別", wx.LIST_FORMAT_LEFT, 100)
            self.listctrl.InsertColumn(2, "年齢", wx.LIST_FORMAT_LEFT, 100)
    
            # ListCtrlにアイテムを追加
            for x in range(4):
                self.listctrl.InsertItem(x, '山田 %s郎' % x)
                self.listctrl.SetItem(x, 1, "男")
                self.listctrl.SetItem(x, 2, str((x + 1) * 5))
    
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(self.listctrl, flag=wx.EXPAND | wx.ALL, border=10, proportion=1)
            p.SetSizer(layout)
    
            self.Show()
    
        def item_select(self, event):
            """ アイテム選択時のイベントハンドラー """
            # 選択したアイテムのインデックスを取得する
            select_index = self.listctrl.GetFirstSelected()
    
            # インデックスのアイテムからテキストを取得する
            text0 = self.listctrl.GetItemText(select_index, 0)  # 氏名
            text1 = self.listctrl.GetItemText(select_index, 1)  # 性別
            text2 = self.listctrl.GetItemText(select_index, 2)  # 年齢
    
            item_label = text0 + "は" + text1 + "で" + text2 + "歳です"
    
            # ステータスバーの文字列を変更
            self.SetStatusText(item_label)
    
    app = wx.App()
    App(None, wx.ID_ANY, 'ListCtrl REPORT')
    app.MainLoop()
    

    <結果> ↓ ↓ ↓