IronPythonで画像ファイルを読み書き

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


コメントを残す

メールアドレスが公開されることはありません。