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

IronPythonで画像ファイルを扱うための簡単なモジュール。
憶えやすいように、関数名をPILっぽい名前にしてあります。

あと、IronPython2.0から、PILやNumpyなどの、Cで書かれたモジュールを呼び出す方法もメモ。

作成にあたって、数え切れないほどのサイトを参考にさせていただきました。

PIL本家ではIronPILというのを開発しているみたいなのですが、現在はまだ公開されてないみたいです。残念。

ironclad

こちらのironcladモジュールを使用すると、PIL、NumPyなどをIronPython2.0から使うことが出来ます。CPythonで慣れたモジュールが使えて楽々♪

まだ、IronPython2.6RC2では動かないみたいです。
独自に内部で各モジュールにパッチをあててるみたいで、全てのPydが動くわけでは無いみたいです。

関数リスト

画像データは、.NetのSystem.Drawing.Bitmapクラスを使用することとします。

保存はBitmapオブジェクトのSave(ファイル名) メソッドで行います。

チュートリアル


  • 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() メソッドで削除したほうがいいかも?(よくわからず)

動作確認 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))
Tags: , ,

Related posts

Tags: , ,

Comments are closed.