以下、JPG形式の画像ファイルの物理サイズをA4サイズの横幅にするコード。
PNG形式の記事も参照
def parse_jpg(file_path): with open(file_path, 'rb') as f: data = f.read() i = 0 segments = {} while i < len(data): assert(data[i] == 0xff) marker = data[i:i+2] if marker[1] == 0xD8: # print("SOI") i += 2 continue elif marker[1] == 0xD9: # print("EOI") break segment_length = int.from_bytes(data[i+2:i+4], 'big') if marker[1] == 0xE0: # APP0 segment segments["APP0"] = i elif marker[1] == 0xC0: # SOF0 segment (Baseline DCT) segments["SOF0"] = i elif marker[1] == 0xDA: # Start Of Scan (SOS) segment_length = 0 j = i + segment_length + 2 while j<len(data): if data[j] == 0xFF and data[j+1] != 0x00:break segment_length+=1 j = i + segment_length + 2 # print(f"i:{i} marker:0xff{format(marker[1], 'x')} segment_length:{segment_length}") i += segment_length + 2 return segments def modify_dpi(file_path, app0_segment, sof0_segment): with open(file_path, 'rb') as f: data = f.read() identifier = data[app0_segment+4:app0_segment+4+5].decode('ascii') version = (data[app0_segment+4+5], data[app0_segment+4+6]) units = data[app0_segment+4+7] x_density = int.from_bytes(data[app0_segment+4+8:app0_segment+4+10], 'big') y_density = int.from_bytes(data[app0_segment+4+10:app0_segment+4+12], 'big') precision = data[sof0_segment+4] height = int.from_bytes(data[sof0_segment+4+1:sof0_segment+4+3], 'big') width = int.from_bytes(data[sof0_segment+4+3:sof0_segment+4+5], 'big') colors = data[sof0_segment+4+5] # print(f"Identifier: {identifier}") # print(f"Version : {version[0]}.{version[1]}") # print(f"DPI_Units : {units}") # print(f"X_DPI : {x_density}") # print(f"Y_DPI : {y_density}") # print(f"Precision : {precision} bits") # print(f"Height : {height} pixels") # print(f"Width : {width} pixels") # print(f"Colors : {colors}") a4_width = 210/25.4 #A4の幅 mm -> inch a4_dpi = round(width/a4_width) if x_density == a4_dpi: print(f"DPI: {x_density} == {a4_dpi}") return print(f"DPI: {x_density} -> {a4_dpi}") data = bytearray(data) data[app0_segment+4+7] = 1 data[app0_segment+4+8:app0_segment+4+10] = a4_dpi.to_bytes(2, 'big') data[app0_segment+4+10:app0_segment+4+12] = a4_dpi.to_bytes(2, 'big') with open(file_path, 'wb') as f: f.write(data) # ディレクトリ内のすべての jpg ファイルを変換 import glob for file_path in glob.glob("*.jpg"): segments = parse_jpg(file_path) modify_dpi(file_path,segments["APP0"],segments["SOF0"])
色々対応させたバージョン