
ブラックボックス化させないくん
プログラムのコードを投げればコメントアウトで分かりやすくしてくれます。 さらなる自動化も提案してくれます。
投稿日時:
- プロンプト実行例
- プロンプトを見る
ブラックボックス化させません。
#coding:utf-8
#画像切り出しスクリプト
#@Ryo Sasaki (zonepotage) #@Seiya Shibata (sorap)
#画像を良しなに切り出すやつ #Usage: py cutImage.py [inputImagePath / ImageDirectoryPath]
#Target Python Env : 3.6 #Rev : 2018/09/14 15:48
#coding:utf-8 from PIL import Image, ImageFilter import sys import os #import math import glob import datetime
Image.MAX_IMAGE_PIXELS = 1000000000
#config (mm)
CUT_SIZE_X = 420 CUT_SIZE_Y = 297 RAP_MARGIN = 30 JPEG_QUALITY = 80
logfileName = "execLog_{0:%Y%m%d_%H%M%S}.txt".format(datetime.datetime.now())
#動作保障外関数↓ def calcCutArea(x,y,dpi):
1#mmからpxを計算
2cutSizeX = round(CUT_SIZE_X/25.4 * dpi)
3cutSizeY = round(CUT_SIZE_Y/25.4 * dpi)
4rapMargin = round(RAP_MARGIN/25.4 * dpi)
5
6if x < y:
7 cutSizeX, cutSizeY = cutSizeY, cutSizeX
8
9
10#床処理(切り上げ)
11pageX = int((x + cutSizeX - 1)/cutSizeX)
12try:
13 if rapMargin > ((pageX * cutSizeX - x) / (pageX - 1)) :
14 pageX += 1
15except:
16 pass
17
18#床処理(切り上げ)
19pageY = int((y + cutSizeY - 1)/cutSizeY)
20try:
21 if rapMargin > ((pageY * cutSizeY - y) / (pageY - 1)) :
22 pageY += 1
23except:
24 pass
25
26
27'''
28#分割ページ数を算出(切り上げ)
29pageX = x//cutSizeX
30pageY = y//cutSizeY
31'''
32#分割ページ数からラップ分を算出
33if pageX == 1:
34 rapX = 0
35else:
36 rapX = (cutSizeX*pageX-x)/(pageX-1)
37
38if pageY == 1:
39 rapY = 0
40else:
41 rapY = (cutSizeY*pageY-y)/(pageY-1)
42
43#切り出し位置(左上座標)を算出
44#結果を [[1枚目x,y],[2枚目x,y].... のように
45leftTopCode = [0,0]
46cropRequest = []
47
48for ii in range(pageY):
49 if ii==0:
50 leftTopCode[1] = 0
51 else:
52 leftTopCode[1] = round(ii*cutSizeY-rapY*ii)
53
54 for i in range(pageX) :
55 if i==0:
56 leftTopCode[0] = 0
57 else:
58 leftTopCode[0] = round(i*cutSizeX-rapX*i)
59
60 cropRequest.append(leftTopCode.copy())
61
62#辺長が切り出しサイズより小さい場合は辺長を切り出しサイズに
63if cutSizeX > x:
64 cutSizeX = x
65if cutSizeY > y:
66 cutSizeY = y
67
68
69#出力画像サイズと切り出し位置を返す
70
71return [cutSizeX,cutSizeY],cropRequestdef getImageData(image): result = {} result["height"] = image.size[1] result["width"] = image.size[0] result["format"] = image.format result["colorMode"] = image.mode if image.info["dpi"]: result["dpi"] = image.info["dpi"] return result
def logging(level,message): with open(logfileName, 'a') as fh: print('[{}] {}'.format(level,message),file = fh) return
def cutImage(image,mode,startX,startY,endX,endY): """ 指定サイズで画像を切り出す @param image Imageオブジェクト @param mode 座標指定モード (relatively:相対指定, absolutely:絶対指定) @param startX 切り出し開始X座標 @param startY 切り出し開始Y座標 @param endX 切り出し終了X座標 @param endY 切り出し終了X座標
1@return 切り出し後Image)
2"""
3
4if mode == "relatively":
5 endX += startX
6 endY += startY
7elif mode == "absolutely":
8 endX += 1
9 endY += 1
10else:
11 return None
12if 0<= startX and 0<= startY and endX <= image.size[0]+1 and endY <= image.size[1]+1 and startX < endX and startY < endY:
13 return image.crop((startX, startY, endX, endY))
14else:
15 return Noneif name == 'main':
1arguments = sys.argv
2try:
3 arguments[1]
4except:
5 print('Arguments too short.')
6
7
8#argTest = "Z:\py_cut\A1\A1_001a.jpg"
9
10try:
11
12 fileList = []
13
14 if os.path.isfile(arguments[1]):
15
16 logfileName = os.path.dirname(arguments[1]) + "/" + logfileName
17 fileList.append(arguments[1])
18 else:
19 logfileName = arguments[1] + logfileName
20 fileList.extend(glob.glob(arguments[1] + '/*.jpg'))
21 fileList.extend(glob.glob(arguments[1] + '/*.jpeg'))
22 fileList.extend(glob.glob(arguments[1] + '/*.tif'))
23 fileList.extend(glob.glob(arguments[1] + '/*.tiff'))
24 #fileList.extend(list(map(lambda x: arguments[1] + "/" + x, glob.glob(arguments[1] + '/*.jpeg'))))
25 #fileList.extend(list(map(lambda x: arguments[1] + "/" + x, glob.glob(arguments[1] + '/*.tif'))))
26 #fileList.extend(list(map(lambda x: arguments[1] + "/" + x, glob.glob(arguments[1] + '/*.tiff'))))
27
28
29 #fileList.append("Z:\py_cut\master2.jpg")
30 for processFile in fileList:
31
32 image = Image.open(processFile)
33 info = getImageData(image)
34
35 print("Format:" + info["format"],"Width:" + str(info["width"]) ,"Height:" + str(info["height"]),sep=" / ", end = "")
36
37 if image.info['dpi']:
38 print(" / Dpi:" ,info["dpi"])
39 else:
40 raise Exception("処理対象となる画像ファイルにDPI属性が存在しません。(" + processFile + ")")
41 result = calcCutArea(info["width"],info["height"],info["dpi"][0])
42
43 count = 0
44 for item in result[1]:
45 count = count + 1
46 print(os.path.splitext(processFile)[0] + "_" +str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1] + "...",end = "")
47 try:
48 if info["format"] == "JPEG":
49 cutImage(image,"relatively",item[0], item[1], result[0][0] , result[0][1]).save(os.path.splitext(processFile)[0] + "_" +str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1] , quality=JPEG_QUALITY, dpi=info["dpi"])
50 elif info["format"] == "TIFF":
51 cutImage(image,"relatively",item[0], item[1], result[0][0] , result[0][1]).save(os.path.splitext(processFile)[0] + "_" +str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1] , quality="group4", dpi=info["dpi"])
52 print("OK")
53 except:
54 raise Exception("何かしら問題が発生しました。(" + + processFile + ")")
55except Exception:
56 logging("ERROR",Exception)
57
58print("Fin.")
59
60os.system("pause > nul")
61
62
63以下に、コードの各部分にコメントアウトを追加しました。また、自動化の提案も行っています。
1#coding:utf-8
2
3#####
4# 画像切り出しスクリプト
5# @Ryo Sasaki (zonepotage)
6# @Seiya Shibata (sorap)
7# 画像を良しなに切り出すやつ
8# Usage: py cutImage.py [inputImagePath / ImageDirectoryPath]
9# Target Python Env : 3.6
10# Rev : 2018/09/14 15:48
11
12#coding:utf-8
13from PIL import Image, ImageFilter # 画像処理用ライブラリ
14import sys # システムパラメータ用ライブラリ
15import os # オペレーティングシステムとのインターフェースライブラリ
16import glob # ファイル名のパターンマッチング用ライブラリ
17import datetime # 日時処理用ライブラリ
18
19Image.MAX_IMAGE_PIXELS = 1000000000 # 最大画像ピクセル設定
20
21# 設定(mm単位)
22CUT_SIZE_X = 420 # 切り出し幅
23CUT_SIZE_Y = 297 # 切り出し高さ
24RAP_MARGIN = 30 # ラップ余白
25JPEG_QUALITY = 80 # JPEG品質設定
26
27# ログファイル名作成
28logfileName = "execLog_{0:%Y%m%d_%H%M%S}.txt".format(datetime.datetime.now())
29
30# 動作保障外関数↓
31def calcCutArea(x,y,dpi):
32 # mmからpxを計算
33 cutSizeX = round(CUT_SIZE_X/25.4 * dpi) # 切り出し幅
34 cutSizeY = round(CUT_SIZE_Y/25.4 * dpi) # 切り出し高さ
35 rapMargin = round(RAP_MARGIN/25.4 * dpi) # ラップ余白をpxに変換
36
37 # 対象画像のサイズによって縦横を入れ替え
38 if x < y:
39 cutSizeX, cutSizeY = cutSizeY, cutSizeX
40
41 # 切り出しページ数を計算
42 pageX = int((x + cutSizeX - 1)/cutSizeX) # 横方向のページ数
43 try:
44 if rapMargin > ((pageX * cutSizeX - x) / (pageX - 1)) :
45 pageX += 1 # ラップ余白を考慮してページ数+1
46 except:
47 pass
48
49 pageY = int((y + cutSizeY - 1)/cutSizeY) # 縦方向のページ数
50 try:
51 if rapMargin > ((pageY * cutSizeY - y) / (pageY - 1)) :
52 pageY += 1 # ラップ余白を考慮してページ数+1
53 except:
54 pass
55
56 # 分割ページ数からラップ分を算出
57 rapX = (cutSizeX*pageX-x)/(pageX-1) if pageX > 1 else 0
58 rapY = (cutSizeY*pageY-y)/(pageY-1) if pageY > 1 else 0
59
60 # 切り出し位置(左上座標)を算出
61 leftTopCode = [0,0]
62 cropRequest = []
63
64 # 切り出し占有位置を計算
65 for ii in range(pageY):
66 leftTopCode[1] = round(ii*cutSizeY-rapY*ii) if ii else 0
67 for i in range(pageX):
68 leftTopCode[0] = round(i*cutSizeX-rapX*i) if i else 0
69 cropRequest.append(leftTopCode.copy())
70
71 # 出力画像サイズと切り出し位置を返す
72 return [cutSizeX if cutSizeX <= x else x, cutSizeY if cutSizeY <= y else y], cropRequest
73
74def getImageData(image):
75 # 画像データを辞書形式で取得
76 result = {}
77 result["height"] = image.size[1] # 画像の高さ
78 result["width"] = image.size[0] # 画像の幅
79 result["format"] = image.format # 画像フォーマット
80 result["colorMode"] = image.mode # カラーモード
81 result["dpi"] = image.info.get("dpi") # DPI情報
82 return result
83
84def logging(level,message):
85 # ログファイルにエラーメッセージを書き込む
86 with open(logfileName, 'a') as fh:
87 print('[{}] {}'.format(level,message), file=fh)
88
89def cutImage(image,mode,startX,startY,endX,endY):
90 """
91 指定サイズで画像を切り出す
92 @param image: Imageオブジェクト
93 @param mode: 座標指定モード (relatively:相対指定, absolutely:絶対指定)
94 @param startX: 切り出し開始X座標
95 @param startY: 切り出し開始Y座標
96 @param endX: 切り出し終了X座標
97 @param endY: 切り出し終了Y座標
98 @return: 切り出し後のImage
99 """
100 if mode == "relatively":
101 endX += startX
102 endY += startY
103 elif mode == "absolutely":
104 endX += 1
105 endY += 1
106 else:
107 return None
108
109 # 切り出し範囲が正しいか確認
110 if 0 <= startX < endX <= image.size[0] + 1 and 0 <= startY < endY <= image.size[1] + 1:
111 return image.crop((startX, startY, endX, endY))
112 else:
113 return None
114
115if __name__ == '__main__':
116 # コマンドライン引数取得
117 arguments = sys.argv
118 try:
119 arguments[1]
120 except IndexError:
121 print('Arguments too short.')
122
123 try:
124 fileList = []
125 if os.path.isfile(arguments[1]):
126 logfileName = os.path.dirname(arguments[1]) + "/" + logfileName
127 fileList.append(arguments[1])
128 else:
129 logfileName = arguments[1] + logfileName
130 # 指定ディレクトリ内の画像ファイルを取得
131 fileList.extend(glob.glob(arguments[1] + '/*.jpg'))
132 fileList.extend(glob.glob(arguments[1] + '/*.jpeg'))
133 fileList.extend(glob.glob(arguments[1] + '/*.tif'))
134 fileList.extend(glob.glob(arguments[1] + '/*.tiff'))
135
136 for processFile in fileList:
137 image = Image.open(processFile) # 画像を開く
138 info = getImageData(image) # 画像の情報を取得
139
140 # 画像情報を出力
141 print("Format:" + info["format"], "Width:" + str(info["width"]), "Height:" + str(info["height"]), sep=" / ", end="")
142 if image.info['dpi']:
143 print(" / Dpi:", info["dpi"])
144 else:
145 raise Exception("処理対象となる画像ファイルにDPI属性が存在しません。(" + processFile + ")")
146
147 # 切り出し範囲を計算
148 result = calcCutArea(info["width"], info["height"], info["dpi"][0])
149 count = 0
150 for item in result[1]:
151 count += 1
152 print(os.path.splitext(processFile)[0] + "_" + str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1] + "...", end="")
153 try:
154 # 切り出し処理
155 if info["format"] == "JPEG":
156 cutImage(image, "relatively", item[0], item[1], result[0][0], result[0][1]).save(
157 os.path.splitext(processFile)[0] + "_" + str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1],
158 quality=JPEG_QUALITY,
159 dpi=info["dpi"]
160 )
161 elif info["format"] == "TIFF":
162 cutImage(image, "relatively", item[0], item[1], result[0][0], result[0][1]).save(
163 os.path.splitext(processFile)[0] + "_" + str(count) + "/" + str(len(result[1])) + os.path.splitext(processFile)[1],
164 quality="group4",
165 dpi=info["dpi"]
166 )
167 print("OK")
168 except Exception as e:
169 raise Exception("何かしら問題が発生しました。(" + processFile + ") " + str(e))
170 except Exception as e:
171 logging("ERROR", str(e))
172
173 print("Fin.")
174
175 os.system("pause > nul")
176
177# さらなる自動化の提案:
178# 1. コマンドライン引数をGUI化することで、ユーザビリティを向上させる。
179# 2. 複数形式の画像に対応するための設定を追加し、拡張性を持たせる。
180# 3. 日次・週次で自動実行されるスケジュール機能を追加し、定期的な処理を行えるようにする。
181# 4. エラーログをデータベースに記録し、後で分析できるようにする。このスクリプトは画像を切り出すためのもので、引数として指定された画像ファイルまたはディレクトリ内の画像を処理します。エラーハンドリングがあり、全ての処理はログとして記録されます。
提案した自動化内容を導入することにより、作業の効率化やトラブルシューティングが容易になるでしょう。