[pukiwiki]
IronPythonで画像ファイルを扱うための簡単なモジュール。
憶えやすいように、関数名をPILっぽい名前にしてあります。
あと、IronPython2.0から、PILやNumpyなどの、Cで書かれたモジュールを呼び出す方法もメモ。
[/pukiwiki]
[pukiwiki]
作成にあたって、数え切れないほどのサイトを参考にさせていただきました。
PIL本家ではIronPILというのを開発しているみたいなのですが、現在はまだ公開されてないみたいです。残念。
*[[ironclad:http://code.google.com/p/ironclad/]]
こちらのironcladモジュールを使用すると、PIL、NumPyなどをIronPython2.0から使うことが出来ます。CPythonで慣れたモジュールが使えて楽々♪
まだ、IronPython2.6RC2では動かないみたいです。
独自に内部で各モジュールにパッチをあててるみたいで、全てのPydが動くわけでは無いみたいです。
*関数リスト
画像データは、.Netの[[System.Drawing.Bitmapクラス:http://msdn.microsoft.com/ja-jp/library/system.drawing.bitmap_members%28printer%29.aspx]]を使用することとします。
保存はBitmapオブジェクトのSave(ファイル名) メソッドで行います。
**チュートリアル
-[[DOBON.NET > プログラミング道 > .NET Tips > 画像、印刷編:http://dobon.net/vb/dotnet/graphics/index.html]]
-[[逆引き.NET:ITpro:http://itpro.nikkeibp.co.jp/develop/dotnet/index.html]]
—-
-new(mode,size)
Bitmapを作成
-load(filename)
Bitmapとして読込
-toArray(bmp)
Bitmapの画素データを配列に読み込み
-fromArray(mode,size,array)
画像データが格納された配列をBitmapに
-toMstring(bmp)
Bitmapを配列に読込。さらにMathematica形式の文字列に変換します。
-iterInt( Mstring)
Mathematica形式の文字列で表現された配列データから、整数データを一個づつ取り出すイテレータを作成。(配列の次元は無視)
-fromstring tostring
PILの同名関数同等品(?)
ただし、上下逆になってるかも
*メモ
CPythonだと、普段はデストラクタを使用しませんが、IronPytthonでは、Bitmapオブジェクトは、こまめにDispose() メソッドで削除したほうがいいかも?(よくわからず)
[/pukiwiki]
動作確認 IronPython RC2
image.pyとして保存
# -*- coding: utf8 -*- "image.py small pil" import clr import System from System import Array,Byte clr.AddReferenceByPartialName("System.Drawing") from System.Drawing import Bitmap,Rectangle,RotateFlipType,Color from System.Drawing.Imaging import PixelFormat,ImageLockMode from System.Runtime.InteropServices import Marshal def new (mode,size): w,h=size mode2,n=_mode(mode) bmp = Bitmap(w, h, mode2) return bmp def _mode(mode): mode=mode.lower() if mode=="rgb": mode2=PixelFormat.Format24bppRgb nchannel=3 elif mode in "rgba" : mode2=PixelFormat.Format32bppArgb nchannel=4 else : raise 'mode = "RGB" or "RGBA"' return mode2,nchannel def fromArray(*args): if len(args)==3: mode,size,dat=args return fromArray1D(mode,size,dat) elif len(args)==1 : dat=args[0] if isinstance(dat,Array): h,w,n=[dat.GetLength(i) for i in xrange(3)] a=Array[Byte](dat) mode=[None,None,None,"RGB","RGBA",][n] return fromArray1D(mode,(w,h),a) return None def fromArray1D(mode,size,dat): #http://d.hatena.ne.jp/okazuki/20060828/1156726184 w,h=size mode2,n=_mode(mode) bmp=new(mode,(w,h)) rct=Rectangle(0, 0, w, h) bd=bmp.LockBits( rct, ImageLockMode.WriteOnly, mode2); Marshal.Copy(dat, 0, bd.Scan0, w*h*n); bmp.UnlockBits(bd); bmp.RotateFlip(RotateFlipType.Rotate180FlipXY) return bmp def frombuffer(mode,size,buf): dat=Array[Byte](buf) return fromArray(mode,size,buf) def iterInt(txt): pat=re.compile(r"(\d+)") return (int(x.group(1)) for x in pat.finditer(txt) ) def toArray(bmp): u"Bitmapの内部データにアクセスする" #"http://d.hatena.ne.jp/Guernsey/20090226" # http://blogs.yahoo.co.jp/spike_spike690/4735887.html # Pixelデータにアクセスする領域を設定する w,h=bmp.Width,bmp.Height rect = Rectangle(0, 0, w,h) # BitmapDataクラスのインスタンスを生成し、LockBits関数でBitmapをLockする。 bmpData = bmp.LockBits(rect,ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb) # BitmapData内の各種項目を抜き出す。 ptr = bmpData.Scan0 imageStride =bmpData.Stride # コピーするデータ量を設定.PixelFormat に関わらず stride * 高さ bytes = imageStride * h imageData = Array[Byte](Length(bytes)) # 確保したデータ配列にBitmap内のデータをコピー Marshal.Copy(ptr, imageData, 0, bytes) # Bitmapのロックを解除する。 bmp.UnlockBits(bmpData) return imageData def fromMstring(mode,size,txt): "from string to Bitmap" w,h=size mode2,n=_mode(mode) dat=Array[Byte](Length(w*h*n,iterInt(txt))) im=fromArray(mode,size,dat) return im def toMstring(x): if isinstance(x,Bitmap) : bmp=x w=bmp.Width n=bmp.GetPixelFormatSize(bmp.PixelFormat)//8 a=toArray(bmp) return 'Partition[Partition[{%s},%s],%s]'%( ",".join((str(i) for i in a)),n,w) # #http://sonic64.com/2005-08-04.html def fromstring(mode,size,txt): "fromstring PIL style" w,h=size mode2,n=_mode(mode) dat=Encoding.Unicode.GetBytes(txt)[::2] im=fromArray(mode,size,dat) return im def tostring(x): "tostring PIL style" bmp=x a=toArray(bmp) return "".join((chr(i) for i in a)) def load(fname): return Bitmap(fname) import re class Length(object): def __init__(self,length,itr=None): self.length=length self.itr=itr def __len__(self): return self.length def __iter__(self): if self.itr : length=self.length def counter(var=[0]): var[0]+=1 if var[0]>length : raise StopIteration return var[0] return (counter() and i for i in self.itr ) else : return ( 0 for i in xrange(self.length))