[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))