61 件 見つかりました。
Windowsマシンで構成されたプライベートLANでpythonによるHTTPサーバを使おうとし、自PCからのアクセスには全く問題無かったが、他PCからの応答に対し5秒程度の遅延がある、という状況に出くわした。取得データに問題はなかったが、5秒もの長い間待つのは不便極まりないので、原因を調べた。
原因はSimpleHTTPRequestHandler.address_string中のsocket.getfqdnで、こいつの実行に5秒近くかかっていた。ここではログに記録するためのホスト名を取得しようとしている。アクセス元Windowsの「コンピュータ名」が結局記録されていたが、そんなもんは私の用途では全く重要ではない。なのでSimpleHTTPRequestHandlerを継承したクラスで以下のようにオーバーライドすることで解決した(IPアドレスだけ記録する)。
def address_string(self):
host, port = self.client_address[:2]
#return socket.getfqdn(host) # original
return host
バッチファイルを用意するのが簡単。
@echo off cd %1 ipythonこれをipythonstartup.batとかにしておいて下記でOK。
ipythonstartup (ディレクトリ)参考(参考ってほどでもないけれど) http://lists.ipython.scipy.org/pipermail/ipython-user/2007-October/004744.html
print os.path.abspath(os.path.dirname(__file__))ref. 134:実行しているスクリプトのパスを求める
pythonでグラフを作成したい時、matplotlibが強力で便利そうだ。
windowsのインストーラでインストールした後に、以下を実行したらそれっぽいのが出てきた。
import pylab
x = range(0,10)
y = range(10,20)
pylab.plot(x,y)
pylab.savefig('C:\\temp\\hoge.png')
とても良さそうだ。HTMLなどでは
üなどの実体参照でヘンテコめな文字を表現する場合がある。これを機械的に通常文字に変換したい。
import htmlentitydefs g = lambda match: unichr(htmlentitydefs.name2codepoint[match.group(1)]) mystring = re.sub(u'&(.+?);', g, mystring)
IPythonは色分け、補完などでインタラクティブコンソールを何かと便利にするもの。併せて使用したいのが(py)readlineなるパッケージで、これは大雑把にはctrl-f,b,a,e,d,kといったemacs系のキーバインドなどを使えるようにするもの。
Windows XP SP2で ipython-0.8.4-py2.5.eggとpyreadline-1.5.dev_r2876-py2.5.eggをeasy_installで導入してみた。便利。個人的にはキーバインドが気に入った。生コマンドプロンプトの時よりもかなり入力の効率は上がるだろう。だが、ctrl-Hはバックスペースになっていなかった。以下はこれを実現した際のメモ。
上述の通り、キーバインドはreadlineが担う。C:\Python25\Lib\site-packages\pyreadline-1.5.dev_r2876-py2.5.egg\pyreadline\modes\emacs.py を見てみると、538行目の init_editing_mode メソッドにて
self._bind_key('Control-b', self.backward_char)
などの記述を大量に発見。ここがキーバインドのキモだろう。カスタマイズの際は何か別に設定ファイル等を作るべきかもしれないが、ここは安直に大元を改造する方針でゆく。
self._bind_key('Control-h', self.backward_delete_char)
でも以下は期待通りの動作(ctrl-Xでバックスペース)を実現した。
self._bind_key('Control-x', self.backward_delete_char)
生コマンドプロンプトはctrl-Hを解釈してバックスペースにしてくれるが、これがpyreadline側のctrl-H設定と干渉を起こしておかしな事になっているのかもしれない。
self._bind_key('Control-h', self.backward_delete_char)
下記は、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)
なんちゃってwin32api(あるいはMFC)環境であるpywin32でビットマップを扱う際、意外と手間取ったのでメモ。
やりたかったことは、キャプチャしたビデオ信号のリアルタイム表示。つまり頻繁にやってくるビットマップのデータ列を頻繁に描画したいという状況。Windowsでのビットマップの描画方法は、私の理解では、多分、(有効な)ビットマップハンドルの取得方法に帰着する。なのでデータ列からビットマップハンドルを如何に作るかがここでのお題となる。今のところ、ctypesでCreateDIBSectionを呼出すのが良いと思っており、実際問題なく動作している。
win32gui.LoadImage や PyCBitmap.LoadBitmapFile は単純で簡単だが、リアルタイム表示においていちいちファイルを介するのは速度的に論外。StringIOでメモリ上にファイルオブジェクトを作成すれば速度の問題は解決するかと思い PyCBitmap.LoadBitmapFile でやってみたが、しばらくすると「このコマンドを実行する記憶域がありません」と例外が飛んでくるので、この方法も無理。
そもそもこんな状況ではwin32apiのCreateDIBSectionの使用が定石のひとつと思うが、残念なことにpywin32にこれは定義されていない。(Windows のデバイスコンテキストをビットマップファイルに変換する。Python でも参照)なのでctypesを介してこれを呼出すことにした。
とはいえ私はctypesの動作を深く理解していない(なので下記にいちいちメモをする)。そこでpygletのソースから該当部分を拝借する方法をとった。
CreateDIBSectionにはBITMAPINFOHEADERを渡す必要がある。これを定義するには如何のようにする(window/win32/types.py より)。
from ctypes import *
from ctypes.wintypes import *
class BITMAPINFOHEADER(Structure):
_fields_ = [
('biSize', DWORD),
('biWidth', LONG),
('biHeight', LONG),
('biPlanes', WORD),
('biBitCount', WORD),
('biCompression', DWORD),
('biSizeImage', DWORD),
('biXPelsPerMeter', LONG),
('biYPelsPerMeter', LONG),
('biClrUsed', DWORD),
('biClrImportant', DWORD),
]
def GetBitmapInfoHeader(w, h):
header = BITMAPINFOHEADER()
header.biSize = sizeof(header)
header.biWidth = w
header.biHeight = h
header.biPlanes = 1
header.biBitCount = 24
header.biCompression = 0
header.biSizeImage = w*h*3
header.biXPelsPerMeter = 0
header.biYPelsPerMeter = 0
header.biClrUsed = 0
header.biClrImportant = 0
return header
dataptr = c_void_p()
bitmap = windll.gdi32.CreateDIBSection(self.GetDC().GetHandleOutput(),
byref(GetBitmapInfoHeader(w, h)),
win32con.DIB_RGB_COLORS, byref(dataptr), None, 0)
memmove(dataptr, buf, len(buf))
GDIオブジェクト、デバイスコンテキスト、メモリデバイスコンテキストといった単語は作業中はなんとなく解ったつもりでいるが、少し間をおくと木端微塵に忘れる。pywin32で描画のコードを書こうとしたが、やっぱりすっかり忘れていて参った。動いたコードをメモしておく。
from pywin.mfc import dialog
import win32con, win32ui
class Mydialog(dialog.Dialog):
dlgstyle = (win32con.WS_DLGFRAME | win32con.DS_MODALFRAME | win32con.WS_POPUP |
win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU )
tmpl = [ ["my dialog", (0, 0, 200, 100), dlgstyle], ]
def __init__(self): dialog.Dialog.__init__(self, self.tmpl)
def OnPaint(self):
dc = self.GetDC()
# copy itself
dc.BitBlt((0,0), (20,20), self.GetWindowDC(), (0,0), win32con.SRCCOPY)
# line
dc.LineTo((30,30))
# line with a customized pen
cpen = win32ui.CreatePen(win32con.PS_SOLID, 5, 10000000)
dc.SelectObject(cpen)
dc.LineTo((50,50))
# drawing on memory device context
dcmem = dc.CreateCompatibleDC()
cbmp = win32ui.CreateBitmap()
cbmp.CreateCompatibleBitmap(dc, 100, 100)
dcmem.SelectObject(cbmp)
dcmem.SelectObject(cpen)
dcmem.LineTo((30,30))
dc.BitBlt((50,0), (50,50), dcmem, (0,0), win32con.SRCCOPY)
self._obj_.OnPaint()
d = Mydialog()
d.DoModal()
[2008-05-23-1]のVideoCaptureのソースをビルドした際のメモ。
WinXP MCE SP2, VS 2003, PFSDK(Windows Server 2003 SP1 SDK)
プロジェクトを開こうとすると古いとか言われたが、指示通り問題なく新しいプロジェクトに変換できた。
C/C++=>全般=>追加のインクルードディレクトリに追加:
C:\Program Files\Microsoft Platform SDK\Samples\Multimedia\DirectShow\BaseClasses
リンカ=>入力=>追加の依存ファイル で、strmbase.libの場所を変更:
上記BaseClassesディレクトリで nmake /f makefile NODEBUG=hoge としてビルド(hogeはたぶん何でもいい)しstrmbase.libを作った上で
"C:\Program Files\Microsoft Platform SDK\Samples\Multimedia\DirectShow\BaseClasses\WIN2000_RETAIL\strmbase.lib"
に変える。
以上でビルドは通る。
関数を増やしたい場合は元ソースの記述をマネして本体を記述し、Dev_methods 変数にそれを加え、VideoCapture.py も適宜変更する。
試しに、getbuffer関数をそっくりコピペしてgetbuffer2と名前を変え、返り値を下記のように変えDev_methodsとVideoCapture.pyを適宜してやってみたが、ちゃんとBITMAPINFOHEADERがpythonから取得できた。(できたvidcap.pydのサイズが配布物(20KB)より小さい(13KB)のはなぜ?)
PyObject *pbmituple;
BITMAPINFOHEADER a = pVideoHeader->bmiHeader;
pbmituple = Py_BuildValue("(k, l,l, H,H, k,k, l,l, k,k)",
a.biSize, a.biWidth, a.biHeight, a.biPlanes, a.biBitCount,
a.biCompression, a.biSizeImage, a.biXPelsPerMeter,
a.biYPelsPerMeter, a.biClrUsed, a.biClrImportant);
PyObject *value;
value = Py_BuildValue("(s#,O)", buffer, size, pbmituple);