﻿# Application signature
APP_NAME = 'Image Fitter'
PROG_VER = '050719-15:01'

# このプログラムの説明
# プロンプトにて入力されたフォルダ以下に存在する画像をリサイズする。
# 携帯端末で閲覧する際に、データサイズを抑えたい場合に使用する。

# 注意
# ・このプログラムの使用には、ImageMagickがインストールされていることが前提
# ・画像ファイルは上書きされるため、上書きが困る場合にはオリジナルは
#   保存しておくこと。

# 調整率
# スクリーンの横サイズが640ピクセル場合(VGA or WVGA)を基準として、
# それに対して、調整する割合を設定する変数。
# XGAにする場合には、1.6を設定する。
# ただし、この値が画像ファイルサイズに影響するので、
# 低画質でも良い場合は、0.2-0.5程度少なめに設定するのが良い。
FITTING_RATE = 1.0


# ここから：処理コード

import os
import string
import re

# Imagemagicker
# Imagemagickへのラッピングクラス
class Imagemagicker:
    ########################################
    # ここから：Imagemagickの各種コマンド名定義

    # 画像ファイル情報表示コマンド    
    CMD_IDENTIFY = 'identify'

    # 画像ファイル拡大縮小コマンド
    CMD_MOGRIFY = 'mogrify'
    
    # ここまで：Imagemagickの各種コマンド名定義
    ########################################

    # コンストラクタ
    # @param p_fileName 操作対象となる画像のファイル名
    def __init__( self, p_fileName ):

        # 操作対象画像ファイル名称
        self.fileName = p_fileName

        # 画像情報を最新に更新する
        self.reloadImageInfo()

    # 画像情報を最新に更新する
    def reloadImageInfo( self ) :
        # 画像ファイル情報読み込み
        self.cmdLine = Imagemagicker.CMD_IDENTIFY + ' -verbose "' + self.fileName + '"'
        self.cmd = os.popen( self.cmdLine )
        self.redirect = self.cmd.read()
        self.cmdRes = self.cmd.close()

        # コマンドの実行に失敗したら、エラーメッセージを出力して終了
        if self.cmdRes != None :
            raise IOError, self.cmdRes

        # 画像情報を解析する
        self.analyze( self.redirect )

    # 画像情報を解析する
    # privateメソッド
    # @param p_infoString 画像情報文字列
    def analyze( self, p_infoString ) :
        ##############################
        # ここから：画像サイズを解析する
        self.matchee = re.findall( 'Geometry: .+', p_infoString )               
        self.items = re.findall( '[0-9]+', self.matchee[ 0 ] )

        # 画像サイズを取得する
        self.width = self.items[ 0 ]
        self.height = self.items[ 1 ]
        # ここまで：画像サイズを解析する
        ##############################

        ##############################
        # ここから：画像形式を解析する
        self.matchee = re.findall( 'Format: .+', p_infoString )               

        # 画像形式, 画像形式情報を取得する
        #self.formatType = re.findall( '[A-Z]+', self.matchee[ 0 ] )
        #self.formatType = self.formatType[ 1 ] 

        #self.formatInfo = re.findall( '\(.+\)', self.matchee[ 0 ] )
        #self.formatInfo = string.strip( self.formatInfo[ 0 ], '()')
        # ここまで：画像形式を解析する
        ##############################

    # 画像ファイル名称を取得する
    # @return 画像ファイル名称
    def getFileName( self ) :
        return self.fileName

    # 画像幅を取得する
    # @return 画像幅
    def getWidth( self ) :
        return int( self.width )

    # 画像高さを取得する
    # @return 画像高さ
    def getHeight( self ) :
        return int( self.height )

    # 画像形式を取得する
    # @return 画像形式
    #def getFormatType( self ) :
    #    return self.formatType

    # 画像形式情報を取得する
    # @return 画像形式情報
    #def getFormatInfo( self ) :
    #    return self.formatInfo

    # 画像を拡大縮小する
    # 注意）画像ファイルを上書きする
    # @param p_ration 拡大縮小率
    def resize( self, p_ration ) :
        self.cmd = os.popen( Imagemagicker.CMD_MOGRIFY + ' -resize ' + str( p_ration ) + '% "' + self.fileName + '"' )
        self.redirect = self.cmd.read()
        self.cmdRes = self.cmd.close()

        # コマンドの実行に失敗したら、エラーメッセージを出力して終了
        if self.cmdRes != None :
            raise IOError, self.cmdRes

##############################################################

import imghdr

def resize2( p_fileName ) :
    
        im = Imagemagicker( p_fileName )
        width = im.getWidth()
        height = im.getHeight()

        # 縦長の画像の場合
        if height > width :
            minLength = width
            criterion = 640.0 * FITTING_RATE
        # 横長の画像の場合
        else :
            minLength = height
            criterion = 1280.0 * FITTING_RATE

        # 縮小率を確定する
        ratio = criterion / minLength * 100.0

        # 縮小対象画像であれば、縮小処理を行う
        if ratio < 100.0 :
            im.resize( ratio )

# 指定したディレクトリ以下に含まれる画像ファイルの名称リストを取得する
# @param p_dir 画像名称リストを調べたいトップディレクトリ
# @return 画像ファイル名称(フルパス)
def getImageFiles( p_dir ) :

    fileList = []

    for root, dirs, files in os.walk( p_dir ) :

        for fileName in files :

            fileName = os.path.abspath( os.path.join( root, fileName ) )

            if imghdr.what( fileName ) :
                fileList.append( fileName )

    return fileList  

import sys
import time
def main() :

    print APP_NAME + '(' + PROG_VER + ')'
    dir = raw_input( 'Enter a parent path to images due for resizing.\n' )

    if dir == '' :
        sys.exit( 1 )

    # クォートを取り除く
    dir = string.replace( dir, '"', "" )
    dir = string.replace( dir, "'", "" )

    imageFiles = getImageFiles( dir )

    # 処理開始時間を記録する
    t0 = time.time()

    # 画像サイズの最適化を行う

    progressCount = 0
    total = len( imageFiles )

    print 'Resizing', total, 'images...'

    for imageFile in imageFiles :

        resize2( imageFile )

        progressCount = progressCount + 1
        nowTime = time.time()
        elapseTime = nowTime - t0
        estimatedTime = elapseTime * total / progressCount
        remainTime = estimatedTime - elapseTime

        print progressCount, '/', total,
        print 'done.',
        print 'Remain time = ', time.strftime( "%X", time.gmtime( remainTime ) )
 
    # 最適化処理の消費時間を表示する
    print 'Finished.'
    print 'TIME of consumption :', time.strftime( "%X", time.gmtime( time.time() - t0 ) )

    # raw_input( 'Hit Return key to end.' )

main()


