残念ながらIronPythonには[記事] のようなcProfileは無いので、別の方法で行う。
見つけた方法は、An IronPython Profiler。[Iron Curt]
IronPython2.7で動作確認したけど、動くようだ。
ipy –X:EnableProfiler プログラム名
「type」で始まるのが.Netで、ModuleはPythonのコードらしい。
PILでは扱えなかった[記事]が、IronPtyhonの.Netライブラリだと普通に扱えたので、更新しておく。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 引数で指定したフォルダの画像ファイルを
# 出力先フォルダに縮小・回転しながらコピーする
from __future__ import print_function
from __future__ import division
import os,sys,glob
import shutil
import clr
clr.AddReferenceByPartialName('System.Drawing')
from System.Drawing import *
# 出力先フォルダ指定。
TARGET_DIR = 'C:\\Photo'
#COWON A3向け
#max_size = (800, 480)
#PSP向け
#max_size = (480, 270)
#Ziio向け
max_size = (480, 800)
#対象拡張子
ext_dic = ['.jpg','.jpeg','.png','.bmp','.tiff']
#強制変換対象フォーマット
forceCompressFormat = [Imaging.ImageFormat.Bmp,Imaging.ImageFormat.Tiff]
#ファイル名のprefix
DEST_PREFIX = 's_'
#JPEG品質
JPEG_QUALITY = 75
def makeOutputDirectory(outputDirPath):
if os.path.isdir(outputDirPath) == False:
os.makedirs(outputDirPath)
def isTarget(ext):
return True if ext.lower() in ext_dic else False
class ProgressBar:
def __init__(self,totalNum):
self.totalNum = totalNum
self.counter = 0
self.chr = u"*"
self.width = 40
def addCounter(self,incrementNum):
self.counter += incrementNum
def show(self):
pbar_chrs = self.chr * (self.width * self.counter // self.totalNum)
percentage = 100 * self.counter // self.totalNum
meter = '\r|{0}{1}| {2}/{3}個 ({4}%)'.format(pbar_chrs,u' ' * (self.width - len(pbar_chrs)),self.counter,self.totalNum, percentage)
sys.stdout.write(meter)
sys.stdout.flush()
def createJpegEncoder():
jpgEncoder = [codec for codec in Imaging.ImageCodecInfo.GetImageEncoders() if codec.FormatID == Imaging.ImageFormat.Jpeg.Guid][0]
encParam = Imaging.EncoderParameter(Imaging.Encoder.Quality,JPEG_QUALITY)
encParams = Imaging.EncoderParameters(1)
encParams.Param[0] = encParam
return (jpgEncoder,encParams)
def shrinkImage(srcFileName, dstFileName,jpgEncoder):
srcImg = Bitmap.FromFile(srcFileName)
if srcImg.Width > max_size[0] or srcImg.Height > max_size[1] or (srcImg.RawFormat in forceCompressFormat):
# BMP/TIFFの場合、JPEGにする
if srcImg.RawFormat in forceCompressFormat:
format = Imaging.ImageFormat.Jpeg
root,ext = os.path.splitext(dstFileName)
dstFileName = root + '.jpg'
else:
format = srcImg.RawFormat
srcWidth = srcImg.Width
srcHeight = srcImg.Height
if max_size[0] > max_size[1]:
#横が長いディスプレイの場合は縦長の画像を回転させた絵を作る
if srcImg.Width < srcImg.Height:
srcWidth = srcImg.Height
srcHeight = srcImg.Width
srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
else:
#縦が長いディスプレイの場合は横長の画像を回転させた絵を作る
if srcImg.Width > srcImg.Height:
srcWidth = srcImg.Height
srcHeight = srcImg.Width
srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
# 画面より画像が小さい場合はスケーリングしない
if max_size[0] < srcWidth or max_size[1] < srcHeight:
scalerate = min(max_size[0]/srcWidth,max_size[1]/srcHeight)
destWidth = int(round(scalerate * srcWidth))
destHeight = int(round(scalerate * srcHeight))
else:
destWidth = srcWidth
destHeight = srcHeight
destImg = Bitmap(destWidth,destHeight)
grphics = Graphics.FromImage(destImg)
grphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
grphics.DrawImage(srcImg,0,0,destWidth,destHeight)
if format == Imaging.ImageFormat.Jpeg:
destImg.Save(dstFileName,jpgEncoder[0], jpgEncoder[1])
else:
destImg.Save(dstFileName,format)
destImg.Dispose()
else:
# 画面に収まらない or BMP/TIFF形式以外の場合は、再圧縮する必要ないので普通のコピーにする
shutil.copy(srcFileName,dstFileName)
srcImg.Dispose()
def copyImageTree(targetList,progress):
jpgEncoder = createJpegEncoder()
for target in targetList:
srcname = target[0]
dstname = target[1]
try:
makeOutputDirectory(os.path.dirname(dstname))
shrinkImage(srcname,dstname,jpgEncoder)
progress.addCounter(1)
progress.show()
except (IOError, os.error), why:
print("Cant' copy",srcname,'to',dstname,':',str(why))
def createTargetImagePath( path,targetBaseDirectory ):
targetPath = []
names = os.listdir(path)
targetDirectory = targetBaseDirectory
for name in names:
srcname = os.path.join(path, name)
try:
if os.path.isdir(srcname):
targetDirectory = os.path.join(targetBaseDirectory, name)
targetPath += createTargetImagePath( srcname,targetDirectory )
else:
root, ext = os.path.splitext(srcname)
if isTarget(ext) == True:
targetPath.append((srcname,os.path.join(targetDirectory,DEST_PREFIX + name)))
except (IOError, os.error), why:
print("Can't copy",srcname,':',str(why))
return (targetPath)
if __name__=='__main__':
#引数がおかしい場合
if len(sys.argv) < 2:
print('Usage: # Python ',sys.argv[0],' [SouceImageDirectoryPath]...')
raw_input()
quit()
targetPathList = []
for x in range(1,len(sys.argv)):
sourcePath = os.path.dirname(sys.argv[x] + '\\')
if os.path.isdir(sourcePath) == False: #存在しないPathを指定した場合
print('[',sourcePath,']: Src directory does not exist.')
raw_input()
quit()
elif os.path.isdir(TARGET_DIR) == False: #存在しないPathを指定した場合
print('[',TARGET_DIR,']: Dest directory does not exist.')
raw_input()
quit()
elif sourcePath == TARGET_DIR: #入力先と出力先が同じ場合
print('The input destination is the same as the output destination.')
raw_input()
quit()
else:
targetPathList += createTargetImagePath(sourcePath,(TARGET_DIR + '\\' + os.path.basename(sourcePath)))
if len(targetPathList) == 0:
print('File does not exist.')
quit()
progress = ProgressBar(len(targetPathList))
copyImageTree(targetPathList,progress)
IronPythonには、pythonのモジュールであるcsvモジュールが無い。
なので、VB.NetのCSVを扱うライブラリを使う。
以下は、UTF-8のtest.csvを読み込むときのコード。
Excelからcsvを保存するとShift-JISになるので、その時はGetEncodingを「Shift_JIS」に変えればよい。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import clr
clr.AddReferenceByPartialName('Microsoft.VisualBasic')
clr.AddReferenceByPartialName('mscorlib')
from Microsoft.VisualBasic.FileIO import *
from System.Text import *
if __name__ == "__main__":
parser = TextFieldParser("test.csv",Encoding.GetEncoding("UTF-8"))
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while parser.EndOfData == False:
print(parser.ReadFields())
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import clr
clr.AddReferenceByPartialName('Microsoft.VisualBasic')
clr.AddReferenceByPartialName('mscorlib')
from Microsoft.VisualBasic.FileIO import *
from System.Text import *
if __name__ == "__main__":
parser = TextFieldParser("test.csv",Encoding.GetEncoding("UTF-8"))
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
print(parser.ReadToEnd())
Python[記事]とIronPython[記事]で同じプログラム(っていっても微妙に違うけど)を作ってみたので、簡単に速度比較してみた。
519枚のBMP,JPG,PNGのファイルを圧縮するのを、6回ほど計測してみた。
| 回数\実装 | Iron Python 単位:sec | CPython 単位:sec |
|---|---|---|
| 1回目 | 45.94 | 23.17 |
| 2回目 | 45.84 | 23.21 |
| 3回目 | 45.81 | 23.21 |
| 4回目 | 45.61 | 23.02 |
| 5回目 | 45.64 | 23.05 |
| 6回目 | 46.00 | 23.46 |
| 平均 | 45.81 | 23.19 |
Google Chartで棒グラフにもしてみた。
IronPythonがダブルスコアで負けてる・・・。
遅すぎるぜ、IronPython。
関数単位でもうちょい解析してみるかなぁ。自分のコーディングがタコなのもあるのだろうし。
Python[記事]で書いていたが、Pythonのサイトに「IronPython has no GIL and multi-threaded code can use multi core processors 」と書いてあったので、ひとまず移植してみた。
勉強がてら、Python Imaging Libraryから.Netのライブラリに変更してみたんだけど、
移植して思うのはPILってよくできてるよな〜ってところ。
PILだと26行くらいで済んでたコードが、55行とほぼ倍になってしまった。
IronPythonの文字は全部Unicodeで統一されているので、日本語の処理はCPythonより楽でよいんだけど。
しかし、IronPythonはやっぱ日本語のページがあんま無いね。
基本は.Netだから同じなんだけど、C#もVB.Netも殆どやってないから、C#の画像圧縮について書いてあるサイトを見ながら、なんとか作ってみた。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 引数で指定したフォルダの画像ファイルを
# 出力先フォルダに縮小・回転しながらコピーする
from __future__ import print_function
from __future__ import division
import os,sys,glob
import shutil
import clr
clr.AddReferenceByPartialName('System.Drawing')
from System.Drawing import *
# 出力先フォルダ指定。
TARGET_DIR = 'C:\\Photo'
#COWON A3向け
#max_size = (800, 480)
#PSP向け
#max_size = (480, 270)
#Ziio向け
max_size = (480, 800)
#対象拡張子
ext_dic = ['.jpg','.jpeg','.png','.bmp']
#ファイル名のprefix
DEST_PREFIX = 's_'
#JPEG品質
JPEG_QUALITY = 75
def makeOutputDirectory(outputDirPath):
if os.path.isdir(outputDirPath) == False:
os.makedirs(outputDirPath)
def isTarget(ext):
return True if ext.lower() in ext_dic else False
class ProgressBar:
def __init__(self,totalNum):
self.totalNum = totalNum
self.counter = 0
self.chr = u"*"
self.width = 40
def addCounter(self,incrementNum):
self.counter += incrementNum
def show(self):
pbar_chrs = self.chr * (self.width * self.counter // self.totalNum)
percentage = 100 * self.counter // self.totalNum
meter = '\r|{0}{1}| {2}/{3}個 ({4}%)'.format(pbar_chrs,u' ' * (self.width - len(pbar_chrs)),self.counter,self.totalNum, percentage)
sys.stdout.write(meter)
sys.stdout.flush()
def createJpegEncoder():
jpgEncoder = [codec for codec in Imaging.ImageCodecInfo.GetImageEncoders() if codec.FormatID == Imaging.ImageFormat.Jpeg.Guid][0]
encParam = Imaging.EncoderParameter(Imaging.Encoder.Quality,JPEG_QUALITY)
encParams = Imaging.EncoderParameters(1)
encParams.Param[0] = encParam
return (jpgEncoder,encParams)
def shrinkImage(srcFileName, dstFileName,jpgEncoder):
srcImg = Bitmap.FromFile(srcFileName)
if srcImg.Width > max_size[0] or srcImg.Height > max_size[1] or srcImg.RawFormat.Equals(Imaging.ImageFormat.Bmp):
# BMPの場合、JPEGにする
if srcImg.RawFormat.Equals(Imaging.ImageFormat.Bmp):
format = Imaging.ImageFormat.Jpeg
root,ext = os.path.splitext(dstFileName)
dstFileName = root + '.jpg'
else:
format = srcImg.RawFormat
srcWidth = srcImg.Width
srcHeight = srcImg.Height
if max_size[0] > max_size[1]:
#横が長いディスプレイの場合は縦長の画像を回転させた絵を作る
if srcImg.Width < srcImg.Height:
srcWidth = srcImg.Height
srcHeight = srcImg.Width
srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
else:
#縦が長いディスプレイの場合は横長の画像を回転させた絵を作る
if srcImg.Width > srcImg.Height:
srcWidth = srcImg.Height
srcHeight = srcImg.Width
srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
# 画面より画像が小さい場合はスケーリングしない
if max_size[0] < srcWidth or max_size[1] < srcHeight:
scalerate = min(max_size[0]/srcWidth,max_size[1]/srcHeight)
destWidth = int(round(scalerate * srcWidth))
destHeight = int(round(scalerate * srcHeight))
else:
destWidth = srcWidth
destHeight = srcHeight
destImg = Bitmap(destWidth,destHeight)
grphics = Graphics.FromImage(destImg)
grphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
grphics.DrawImage(srcImg,0,0,destWidth,destHeight)
if format == Imaging.ImageFormat.Jpeg:
destImg.Save(dstFileName,jpgEncoder[0], jpgEncoder[1])
else:
destImg.Save(dstFileName,format)
destImg.Dispose()
else:
# 画面に収まらないor BMP形式以外の場合は、再圧縮する必要ないので普通のコピーにする
shutil.copy(srcFileName,dstFileName)
srcImg.Dispose()
def copyImageTree(targetList,progress):
jpgEncoder = createJpegEncoder()
for target in targetList:
srcname = target[0]
dstname = target[1]
try:
makeOutputDirectory(os.path.dirname(dstname))
shrinkImage(srcname,dstname,jpgEncoder)
progress.addCounter(1)
progress.show()
except (IOError, os.error), why:
print("Cant' copy",srcname,'to',dstname,':',str(why))
def createTargetImagePath( path,targetBaseDirectory ):
targetPath = []
names = os.listdir(path)
targetDirectory = targetBaseDirectory
for name in names:
srcname = os.path.join(path, name)
try:
if os.path.isdir(srcname):
targetDirectory = os.path.join(targetBaseDirectory, name)
targetPath += createTargetImagePath( srcname,targetDirectory )
else:
root, ext = os.path.splitext(srcname)
if isTarget(ext) == True:
targetPath.append((srcname,os.path.join(targetDirectory,DEST_PREFIX + name)))
except (IOError, os.error), why:
print("Can't copy",srcname,':',str(why))
return (targetPath)
if __name__=='__main__':
#引数がおかしい場合
if len(sys.argv) < 2:
print('Usage: # Python ',sys.argv[0],' [SouceImageDirectoryPath]...')
raw_input()
quit()
targetPathList = []
for x in range(1,len(sys.argv)):
sourcePath = os.path.dirname(sys.argv[x] + '\\')
if os.path.isdir(sourcePath) == False: #存在しないPathを指定した場合
print('[',sourcePath,']: Src directory does not exist.')
raw_input()
quit()
elif os.path.isdir(TARGET_DIR) == False: #存在しないPathを指定した場合
print('[',TARGET_DIR,']: Dest directory does not exist.')
raw_input()
quit()
elif sourcePath == TARGET_DIR: #入力先と出力先が同じ場合
print('The input destination is the same as the output destination.')
raw_input()
quit()
else:
targetPathList += createTargetImagePath(sourcePath,(TARGET_DIR + '\\' + os.path.basename(sourcePath)))
if len(targetPathList) == 0:
print('File does not exist.')
quit()
progress = ProgressBar(len(targetPathList))
copyImageTree(targetPathList,progress)
この広告は90日以上新しい記事の投稿がないブログに表示されております。