27 件 見つかりました。

CHALOW Search - hiChangeLog ChangeLog INDEX

1 2 3 [ 次へ ]

IronPythonとIronPython Studioで楽々開発か [python][Windowsプログラミング]

WindowsプログラミングにはIronPythonが便利そうだなと思っていたが、同じ開発元からIronPython StudioなるIDEまでリリースされていたことを知り、導入に踏み切った。その際のメモ。

pre-requistiesを見てみるとVisual Studio 2008 Shell Isolated Mode Redistributable packageがあったのでダウンロードしインストール。場所としてC:\VS 2008 Shell Redist以下を指定し、しばらく待ったら終わった。だがその後に C:\VS 2008 Shell Redist\Isolated Mode\vs_shell_isolated.enu.exe を実行せねばインストールが真に終わらない(*)とのことで、実行した。.NET Framework 3.5のインストールの後にVS2008Shellなんちゃらのインストールが始まった。

(*) pre-requistiesのページに以下の記述があった。
After you run the Install for the MS VS 2008 Shell Isolated Mode Redistributable, you must then go to the folder (in my case: C:\VS 2008 Shell Redist\Isolated Mode) and click on: "vsshellisolated_enu.exe" to actually install the redistributable runtime.

のちに IronPythonStudioIsolated.zip をダウンロードしインストールした。スタートメニューにIronPython Studioが登場したので実行したが、ちゃんと起動できた。

Windows Applicationの新規プロジェクトを立ち上げ、Formに適当に貼り付けて実行する(この操作はVS 2003と同様)と、ちゃんと実行できた。すごい。コントロールをダブルクリックするとちゃんとpythonソースのイベントハンドラの所に飛ぶ。これはもっとすごい。

作成したプロジェクトのbinディレクトリを見ると実行ファイルができていた。同じくIronMath.dll、IronPython.dllもあり、これら3つを別のPCに持っていって、プログラムを実行できるのを確認した。うまくいきすぎて拍子抜けした。プロジェクトのプロパティで"Target Platform"が選べて、ここの値の.NETが入っているPCなら動くのだろうと理解。

できれば実行ファイルでなくスクリプトのままで動かしたいところだが、ひと手間かかるようだ。Visual Studio 2005 for IronPythonで作ったコードを ipy.exe 単体で動かせるようにするには? - ふにゃるん

起動はとても遅い。FormにボタンとNumericUpDownを配置し、メッセージボックスを出すだけのReleaseビルド実行ファイルの起動にかかる時間は、Athlon 64 X2 3800+ 2GB RAMマシンで2秒ほど、Celeron 2.5GHz 2.5GB RAMマシンに至っては15秒前後かかる。起動後の動作に特に不自然な印象は無い。

だけどまあ素早い開発ができそうなのは良い。PyWin32も結構便利な環境だが、IDEがあるあたりが良い。個人的には、NumericUpDownが簡単に使えるのが動機の大きい割合を占める。

参考:IronPythonプログラミングの始め方 − @IT

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)を利活用する2 [PyWin32][Windowsプログラミング]

[2008-08-16]の続き。ちょっと実際に試してわかったことをメモする。

結論:ResEditを使う際、win32rcparser.pyを変更した方が良い。変更箇所はこのメモ後半に示す。

ResEditで配置する場合、いくつか「地雷」なコントロールがある。

(1) チェックボックス、ラジオボタン
チェックボックスやラジオボタンを配置したリソーススクリプトを使うと、pythonスクリプト実行時ダイアログ自体も表示されなかった。
ResEditでチェックボックス(ラジオボタンも同様)を配置すると以下のようなリソーススクリプトとなる。win32rcparser.pyはこれをちゃんと解釈してくれないようだ。

AUTOCHECKBOX    "Check1", IDC_CHECKBOX1, 10, 43, 40, 10
C:\Python25\Lib\site-packages\win32\test\win32rcparser\test.rc を見ると以下の記述は正しく解釈されているようだった。
CONTROL         "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,52,68,12
両者はリソーススクリプト的には等価だが、前者の記述はwin32rcparser.pyは想定してなかった、といったところか。

(2) コモンコントロールとピクチャコントロール
スピン、プログレスバーも同様、使用するとダイアログが表示されなかった。
ResEdit、上記test.rcによるリソーススクリプトの記述を順に示す。
CONTROL         "", IDC_SPIN1, UPDOWN_CLASS, UDS_ARROWKEYS, 10, 119, 9, 14
CONTROL         "Spin1",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,7,71,14,22
というわけで、ResEditのウィンドウクラスの表現(UPDOWN_CLASS)がwin32rcparserに解釈できなかった、という感じ。ピクチャコントロールも同様に躓いた模様。

凝ったUIは趣味ではないが、チェックボックスやスピンが自由に使えないとなると結構つらい。
これらをどう解決するか?
win32rcparser.pyに修正を施すのがあるべき対処。明快だし、多分比較的難しくない。
もうひとつの方法は、リソーススクリプト読み込み時に、win32rcparserが解釈できる形式に変換すること。ちょっと面倒だが、既存物を変更する必要が無いので、役割分担が明確で、変化にも柔軟に対応できるだろう。
ここでは安直に前者を選択した。場当たり的な対処を施したパッチが以下(前メモの、ヘッダ解釈にまつわる変更も含む)。これにより、プッシュボタン、チェックボックス、ラジオボタン、グループボックス、スタティックテキスト、ピクチャコントロール、スクロールバー、エディットボックス、リストボックス、コンボボックス、スピン、スライダー、プログレスバー、タブ、リストビュー、ツリービュー、IPアドレスコントロール、日付選択、カレンダー、を配置したダイアログボックスを無事に解釈し表示できた。イベントを割当ててどうのこうのはまだ行っていないが、多分問題ないだろう。
--- C:/Python25/Lib/site-packages/win32/lib/win32rcparser_orig.py	Thu Jul 29 00:25:22 2004
+++ C:/temp/e/f/win32rcparser.py	Sun Aug 17 14:25:20 2008
@@ -199,10 +199,12 @@
 
     def parseH(self, file):
         lex = shlex.shlex(file)
         lex.commenters = "//"
         token = " "
+        lex.whitespace += '()'
+        lex.wordchars += '-'
         while token is not None:
             token = lex.get_token()
             if token == "" or token is None:
                 token = None
             else:
@@ -456,10 +458,17 @@
             self.getCommaToken()
 
             if control.controlType == "CONTROL":
                 self.getToken()
                 control.subType = self.token[1:-1]
+
+                # ad hoc handling for ResEdit's common-controls by H.Itoh
+                # ex. 'UPDOWN_CLASS' => 'UPDOWN_CLASSA' => "msctls_updown32" (see commctrl l.731) etc.
+                try: control.subType = getattr(commctrl, self.token+'A')
+                except AttributeError: pass
+                if self.token=='WC_STATIC': control.subType = 'Static'
+
                 thisDefaultStyle = defaultControlStyle | \
                                    _addDefaults.get(control.subType, 0)
                 # Styles
                 self.getCommaToken()
                 self.getToken()
@@ -483,10 +492,21 @@
                 self.getToken()
                 control.style, control.styles = self.styles([], thisDefaultStyle)
             if self.token==",":
                 self.getToken()
                 control.styleEx, control.stylesEx = self.styles([], defaultControlStyleEx)
+
+            # ad hoc handling for ResEdit by H.Itoh
+            f = lambda s: control.controlType.endswith(s)
+            if f('CHECKBOX') | f('RADIOBUTTON'):
+                for s in ['BS_'+control.controlType, 'WS_TABSTOP']:
+                    control.styles.append(s)
+                    control.style |= getattr(win32con, s)
+                control.controlType = 'CONTROL'
+                control.subType = 'Button'
+                control.style |= defaultControlStyle
+
             #print control.toString()
             dlg.controls.append(control)
 
 def ParseStreams(rc_file, h_file):
     rcp = RCParser()

上記の修正は関係ないが、win32rcparser.pyは下記のように使う(下記はダイアログを表示させるだけ。イベントハンドラの記述については[2008-06-07-1]を参照)。my.rcが作成したリソーススクリプト。
from pywin.mfc import dialog
import win32rcparser

class Mydialog(dialog.Dialog):

    def __init__(self, ddef):
        dialog.Dialog.__init__(self, ddef)
        
    def OnInitDialog(self):
        return dialog.Dialog.OnInitDialog(self)

if __name__=='__main__':
    rc = win32rcparser.Parse('my.rc')
    ddef = rc.dialogs['IDD_DIALOG1']
    w = Mydialog(ddef)
    w.DoModal()

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)を利活用する [PyWin32][Windowsプログラミング]

[2008-06-09-2]で、pythonによるwindowsプログラミングにおいてリソース(スクリプト/エディタ)が使えそうである旨メモした。
その時はリソーススクリプトをパースする在野のpythonスクリプトを見つけ出したと思っていたが、実は手元のpywin32(-211)に同様のものが含まれていた。
本体は C:\Python25\Lib\site-packages\win32\lib\win32rcparser.py にあり、C:\Python25\Lib\site-packages\win32\Demos\win32rcparser_demo.py でその動作っぷりが確かめられる。これで、個人的には、pythonによるwindowsプログラミングの敷居がぐっと下がったのではと感じる。

ただこれをResEditで利用する場合、そのままでは動かない。以下を参照。

- ANSI版のResEditを使うべき。Unicode版はUTF16のリソーススクリプトを吐くが、win32rcparser.py はこれをうまく読んでくれなかった。本来はwin32rcparser.pyに修正を施すべきだが、これは面倒。作成後にリソーススクリプトをANSIに変換しても良いけれど、そんなことするくらいなら最初からANSI版を使うのが良い。
- ResEditの吐くヘッダ中の

#define IDC_STATIC (-1)
が、そのままでは通らない。これは、カッコと負号がちゃんとパースされていないため。この行を編集(消すなり、カッコ無しの正数にしたり)するのがひとつの対策。即ちアプリケーション本体の実行時に動的にこの行をフィルタしてwin32rcparserに渡す、など。もうひとつの対策は、win32rcparser.pyに修正を施すこと。場当たり的だが以下のような簡単に修正できるので、こちらの方が良さそう。
@@ -199,10 +199,12 @@
 
     def parseH(self, file):
         lex = shlex.shlex(file)
         lex.commenters = "//"
         token = " "
+        lex.whitespace += '()'
+        lex.wordchars += '-'
         while token is not None:
             token = lex.get_token()
             if token == "" or token is None:
                 token = None
             else:

これでpythonによるwindowsアプリの量産態勢に入れるだろうか。

ツールバーのボタンを外部プログラムから押すにはどうすればよいか [Windowsプログラミング]

SendInputでクリックイベントを送るのが確実だけど、位置合わせが面倒。

ボタンのウィンドウハンドルを取得すればどうにでもなると思ったが、あまり単純な話ではないようだ。
http://m--takahashi.com/bbs/pastlog/06400/06309.html

なんで、押すこと自体は諦め、代わりにSendInputからキーイベントを送ってメニューから実行したと見做させるのが良いように思う。

pythonからSendInput [Windowsプログラミング][python][PyWin32]

下記は、windowsのAPIのSendInputをpythonから呼ぶ例。
Adobe Readerに右矢印入力を10発送りこむ(開いてるPDFを10ページ進める)。エラー処理は省略。
この手のことはAutoHotKeyが専門だけど、pythonでできるにこしたことはない。
AppendKeyInput で win32con.KEYEVENTF_KEYUP を入れないと、同じキーの連続入力が出来ない。
http://mail.python.org/pipermail/python-win32/2005-April/003131.html を参照。

from ctypes import *
import win32ui, win32con

PUL = POINTER(c_ulong)
class KeyBdInput(Structure):
    _fields_ = [("wVk", c_ushort),
                ("wScan", c_ushort),
                ("dwFlags", c_ulong),
                ("time", c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(Structure):
    _fields_ = [("uMsg", c_ulong),
                ("wParamL", c_short),
                ("wParamH", c_ushort)]

class MouseInput(Structure):
    _fields_ = [("dx", c_long),
                ("dy", c_long),
                ("mouseData", c_ulong),
                ("dwFlags", c_ulong),
                ("time",c_ulong),
                ("dwExtraInfo", PUL)]
               
class Input_I(Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(Structure):
    _fields_ = [("type", c_ulong),
                ("ii", Input_I)]


def AppendKeyInput(vk):
    ret = []
    extra = c_ulong(0)
    ii_ = Input_I()
    scan = windll.user32.MapVirtualKeyA(vk, 0)
    ii_.ki = KeyBdInput(vk, scan, 0, 0, pointer(extra) )
    ret.append( ( win32con.INPUT_KEYBOARD, ii_ ) )

    ii2_ = Input_I()
    scan = windll.user32.MapVirtualKeyA(vk, 0)
    ii2_.ki = KeyBdInput(vk, scan, win32con.KEYEVENTF_KEYUP, 0, pointer(extra) )
    ret.append( ( win32con.INPUT_KEYBOARD, ii2_ ) )
    return ret

def ExecSendInput(inputs):
    num = len(inputs)
    FInputs = Input * num
    x = FInputs(*inputs)
    windll.user32.SendInput(num, pointer(x), sizeof(x[0]))
    

if __name__ == '__main__':
    inputs = []
    for i in range(10):
        inputs += AppendKeyInput(win32con.VK_RIGHT)
    
    acrobat = win32ui.FindWindowEx(None, None, 'AdobeAcrobat', None)
    acrobat.SetForegroundWindow()
    ExecSendInput(inputs)

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)が利活用できるか? [PyWin32][Windowsプログラミング]

[2008-06-07]でPyWinのMFC(GUI)プログラミングが有望っぽい事をメモした。
さてGUIプログラミングではコントロールの配置がキモである。ソース内にベタ書きするのは、ファイルが1つで済むので好きだけど、ある程度の規模に膨れるとそうも言ってられなくなる。Visual Studioによるwin32/MFC開発ではリソースエディタでもってコントロールの配置を行い、それをリソーススクリプトに保存するが、これが中々具合が良い。これをPyWin32にも活用できないものだろうか?

ResEditなるものがあるようだ。ちょっと導入してみたけど中々良い。リソースの作成はこれで大丈夫そう。(Visual Studioが使えない時という意味で)

では如何にそれをpythonに喰わせるか?という話になる。[Spambayes-checkins] spambayes/Outlook2000/dialogs/resources rcparser.py, NONE, 1.1.2.1 にそれっぽいコードがある。今度試してみよう。

Referrer (Inside): [2008-08-16-1]

pywin32によるMFCアプリケーションの雛形 [python][PyWin32][Windowsプログラミング]

pywin32のmfcラッパを試している。pythonで結構簡単にWindowsのダイアログが作れて、良さそう。
とりあえず手元で試して動いたコードをメモ。

とにかくダイアログを出す、という例が以下。拡張子をpywにして保存しダブルクリックすればOK。

from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_DLGFRAME | win32con.DS_MODALFRAME | win32con.WS_POPUP |
                win32con.WS_VISIBLE |  win32con.WS_CAPTION  | win32con.WS_SYSMENU )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)    
    dlgButton = 0x0080
    tmpl = [
        ["my dialog", (0, 0, 200, 100), dlgstyle], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5, 55, 190, 40), btnstyle], # button
        ]
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)


d = Mydialog()
d.DoModal()

ボタンを作成しハンドラを割当てた例が以下。アプリケーション作成にあたっての出発点的なもの。
from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
                win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
                win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)    
    IDC_MYBUTTON = 1025
    dlgButton = 0x0080
    tmpl = [
        ["my dialog", (0, 0, 200, 100), dlgstyle], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5,  5, 190, 40), btnstyle], # button
        [dlgButton, "my button", IDC_MYBUTTON,  (5, 55, 190, 40), btnstyle], # button
        ]
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)
        
    def OnInitDialog(self):
        rc = dialog.Dialog.OnInitDialog(self)
        self.HookCommand(self.OnMyButton, self.IDC_MYBUTTON)
        self.btn = self.GetDlgItem(self.IDC_MYBUTTON)
        return rc

    def OnMyButton(self, id, cmd):
        if cmd==win32con.BN_CLICKED:
            ret = self.MessageBox('hello, my button', 'my caption', win32con.MB_YESNO)
            if ret==win32con.IDYES: cap = 'yes'
            else: cap = 'no'
            self.btn.SetWindowText(cap)
        
    def OnOK(self):
        rc = dialog.Dialog.OnOK(self)
        self.MessageBox('OnOK!', 'farewell')
        return rc

    def OnCancel(self):
        rc = dialog.Dialog.OnCancel(self)
        self.MessageBox('OnCancel!', 'farewell')
        return rc



d = Mydialog()
d.DoModal()

上では、Mydialogのコンストラクタに渡す引数でもってボタンを作成している。
でも以下をOnInitDialogに仕込んでも良い。
(こちらで指定するサイズは(たぶん)ピクセル単位で、一方tmplで指定したサイズはダイアログユニットなので、
大きさに関する数値は異なる。変換はself.MapDialogRectで行える。)
self.btn = win32ui.CreateButton()
self.btn.CreateWindow('my button', self.btnstyle, (10, 75, 340, 140), self, self.IDC_MYBUTTON)



上の例で、ダイアログのフォントを変え、タイマーを仕込んだ例が以下。
from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
                win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
                win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)
    staticstyle = (win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.SS_LEFT)
    IDC_MYBUTTON = 1025
    IDC_MYSTATIC = 1026
    dlgButton = 0x0080
    dlgStatic = 0x0082
    tmpl = [
        ["my dialog", (0, 0, 200, 130), dlgstyle, None, (14,'Arial')], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5,  5, 190, 40), btnstyle], # button
        [dlgButton, "my button", IDC_MYBUTTON,  (5, 55, 190, 40), btnstyle], # button
        [dlgStatic, "my static", IDC_MYSTATIC,  (5,105, 190, 20), staticstyle], # static
        ]
    timerid = 1
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)
        
    def OnInitDialog(self):
        rc = dialog.Dialog.OnInitDialog(self)
        self.HookCommand(self.OnMyButton, self.IDC_MYBUTTON)
        self.static = self.GetDlgItem(self.IDC_MYSTATIC)
        self.timerflag = False
        self.timercount = 0
        return rc

    def OnMyButton(self, id, cmd):
        if cmd==win32con.BN_CLICKED:
            if self.timerflag: self.KillTimer(self.timerid)
            else: self.SetTimer(self.timerid, 500) # 0.5s
            self.timerflag = not self.timerflag

    def OnTimer(self, nIDEvent):
        self.timercount += 1
        self.static.SetWindowText('timer! %d' % self.timercount)

        
    def OnOK(self):
        rc = dialog.Dialog.OnOK(self)
        self.MessageBox('OnOK!', 'farewell')
        return rc

    def OnCancel(self):
        rc = dialog.Dialog.OnCancel(self)
        self.MessageBox('OnCancel!', 'farewell')
        return rc



d = Mydialog()
d.DoModal()


上記はpywin32に付属のsliderdemo.pyが基なので、致命的な間違いは無いと思うし、実際手元ではちゃんと動いている。
ここまでくれば、後はMFCの知識だけでグリグリ書き進められそう。

Referrer (Inside): [2008-08-17-1]

簡易入力ダイアログ [PyWin32][python][Windowsプログラミング]

pythonでCOMを使うためPython for Windows extensions (see also: Mark Hammond's Free Stuff)を導入した。他の機能にも触れてみようとしている。mfcまわりもラップされているのでGUIアプリケーションも書けるようだ。windowsに特化するなら、MFCへの慣れを勘案すれば、wxPythonよりこっちを使う方がラクかな?

とりあえず簡易な入力ダイアログが非常に簡単に作成できるようなのでメモ。後々重宝しそうな気がする。

import pywin.mfc.dialog
print pywin.mfc.dialog.GetSimpleInput("my textbox title", 'my default value', 'my window title')

UTF-8文字列への変換 [Windowsプログラミング]

Windowsプログラミングにおいて、UTF-8文字列を用意したい場合にはどうすればよいか?

次の作業を行えばよい:MultiByteToWideCharでUnicodeに変換 => WideCharToMultiByteでUTF-8に変換

UTF-8エンコードについて
Yu TANAKA's Works:S-JISからUTF-8への変換

PNGにコメントを埋め込む [画像ファイル][Windowsプログラミング]

画像は情報量が多く情報伝達媒体として極めて優秀だが、ちと検索が難しいので後々の整理が悩ましい。画像のキーワードが既知であれば、それを元に文字からの検索が可能となるので、後々の整理で威力を発揮するだろう。要は画像ファイルにコメントとしてキーワードが埋め込まれていれば便利そうだという話。PNGについてこのへんの事情を調べた。[2006-12-05]も参照。

【前提知識】

もともとPNGファイルにはtEXtチャンクなるコメント用の領域が用意されている。もちろん、libpngからの読み書きが可能である。
PNG利用術
PNGファイル(2)  PNG操作の手順

しかしながら、ここには日本語のデータを入れてはいけない模様。とても残念な仕様である。
PNG Specification: Chunk Specifications 中に次の記述が:"The text string can contain any Latin-1 character."
お絵描き研究室:PNG(原理編)
PNG チャンク編集ツール < 10 < November < 2004 < nulog, NULL::something : out of the headphone

その不満を受けてのことだろうが、iTXtチャンクなる、UTF-8を入れてもいいコメント領域が追加されたようだ。「PNGの常識」と捉えるにはまだ早いのかな?
PNG Specification: Chunk Specifications
煤 - Note 0312


【コード】

tEXtチャンクの読み書きはPNG利用術を見るとよくわかる。
だけどiTXtのサンプルコードはあんまり見ない。Re: g_warnings in png loaderくらい?ちょっとやってみて、独断でうまくいったっぽいと感じたのでメモする。

libpngは libpng-1.2.22-no-config.tar.gz を使用。このバージョンでは、iTXtの機能はデフォルトでは無効になっている(pngconf.h の474行目 "iTXt support was turned off by default")。これを有効にするために、503行目あたり(iTXt関連の#defineが終わった直後)に無理矢理以下をねじこみ、その上でコンパイルしてライブラリを作成した。

#define PNG_iTXt_SUPPORTED
#define PNG_READ_iTXt_SUPPORTED
#define PNG_READ_iTXt
#define PNG_WRITE_iTXt_SUPPORTED
#define PNG_WRITE_iTXt

そのライブラリを使ったプログラム中で、下記のコードでiTXtにコメントを埋め込めたようだ。見ての通り文字列の宣言と変換はお手軽いいかげんなコードだが、これは現在の本質ではない。
png_text text_ptr[3];
const WCHAR* wstr[3] = {L"これが1番目です", L"これは2番目かも", L"そして3番目だ"};
char str[3][1024];
char key[3][32];
for(int i=0; i<3; i++){
    sprintf(key[i], "My Key %d", i);
    WideCharToMultiByte(CP_UTF8, 0, wstr[i], -1, str[i], 1024, NULL, NULL);
    text_ptr[i].key = key[i];
    text_ptr[i].text = str[i];
    text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
    text_ptr[i].text_length = 0;
    text_ptr[i].itxt_length = strlen(text_ptr[i].text);
    text_ptr[i].lang = NULL;
    text_ptr[i].lang_key = NULL;
}
png_set_text(png_ptr, info_ptr, text_ptr, 3);
こうして作ったPNGは次の通り:
上記コードでコメントを埋め込んだPNG

コメントの有無の確認はpngtxtで行った。TweakPNG(ver. 1.2.1)でもiTXtチャンクの有無は確認できたが、日本語は表示できないみたい。ソースが入手できるので、表示できるように修正できるかなと思ったが面倒なのでやめた。

読み込む際のコードはtEXtの場合と特に違いはなさそう。下記内容のmain.cppを用意し、ビルドしたらば、ちゃんとUTF-8でコメントを吐いてくれた(標準出力をテキストファイルにリダイレクトした上で見た)。なお下記はPNG利用術の「読み込み」節のコードをここでの目的に照らして必要最小限に削ったものである。省略は私が勝手に行ったことであり、また、コードそのものに私のオリジナルな部分は一切無い。

ビルドのコマンドライン:
cl /MD main.cpp libpng.lib zlib.lib

main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "png.h"

void check_if_png(char *file_name, FILE **fp);
void read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr);

#define PNG_BYTES_TO_CHECK (4)

int main()
{
  FILE            *fp;
  png_structp     png_ptr;
  png_infop       info_ptr;
  png_uint_32     i;
  
    check_if_png("test.png", &fp);
  read_png_info(fp, &png_ptr, &info_ptr);

{         // 以下8行はtEXtチャンクを取得し表示します
  png_textp       text_ptr;
  int             num_text;
  
  if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text))
          for (i = 0; i < num_text; i++)
                  printf("%s", text_ptr[i].text);
}
  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
  fclose(fp);
  return 0;
}

void check_if_png(char *file_name, FILE **fp)
{
  char    sig[PNG_BYTES_TO_CHECK];
  
  if ((*fp = fopen(file_name, "rb")) == NULL)
          exit(EXIT_FAILURE);
  if (fread(sig, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) {
          fclose(*fp);
          exit(EXIT_FAILURE);
  }
}

void read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr)
{
  *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (*png_ptr == NULL) {
          fclose(fp);
          exit(EXIT_FAILURE);
  }
  *info_ptr = png_create_info_struct(*png_ptr);
  if (*info_ptr == NULL) {
          png_destroy_read_struct(png_ptr, (png_infopp)NULL, (png_infopp)NULL);
          fclose(fp);
          exit(EXIT_FAILURE);
  }
  if (setjmp((*png_ptr)->jmpbuf)) {
          png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
          fclose(fp);
          exit(EXIT_FAILURE);
  }
  png_init_io(*png_ptr, fp);
  png_set_sig_bytes(*png_ptr, PNG_BYTES_TO_CHECK);
  png_read_info(*png_ptr, *info_ptr);
}

1 2 3 [ 次へ ]

ChangeLog INDEX
Powered by chalow