本文发表于入职啦(公众号: ruzhila) 大家可以访问入职啦学习更多的编程实战。
项目地址
代码已经开源, resize_images_py 👏 Star
项目需求
做一个图片批量调整大小的工具,可以指定输入目录和输出目录,然后将输入目录下的所有图片调整大小后保存到输出目录,还能支持指定转换的格式:
# 将当前目录下的所有图片调整为小于100KB,保存到new_dirs目录下,格式为jpg
python resize_images.py -i . -o new_dirs -s 100k -f jpg
# 将当前目录下的所有图片调整为原先的80%,保存到new_dirs目录下,格式为png
python resize_images.py -i . -o new_dirs -s 80% --format png
项目思路
这个需求由3个部分组成:
- 解析命令行参数: 特别是-s参数,支持100k和80%这样的格式,这样我们就需要对参数进行解析,失败出是固定大小还是比例,执行的时候根据不同的参数执行不同的逻辑
- 遍历文件: 通过os.walk可以实现,遍历文件夹下的所有文件,只对.jpeg/.jpeg/.png这样的图片进行处理
- 调整图片大小: 通过Pillow库可以实现,调整图片大小,如果-f/--format不指定格式,那么就保持原来的格式
所以根据这三个部分,我们就可以实现这个需求。
先上代码:
实现解析命令行参数
我们利用内置的optparse库,可以很方便的解析命令行参数,这里我们主要解析-i、-o、-s、-f这几个参数
其中-s参数支持100k和80%这样的格式,这样我们就需要对参数进行解析是固定大小还是比例
我们识别最后一个字符,如果是%,那么就是比例,如果是k、m、g,那么就是固定大小 可以看出来Python处理字符串非常方便
def main():
parser = OptionParser()
parser.add_option("-i", "--input", dest="input",
default=".", help="Input image file", metavar="INPUT")
parser.add_option("-o", "--output", dest="output",
default=".", help="Output image file", metavar="OUTPUT")
parser.add_option("-s", "--size", dest="size", default="80%",
help="Output image size", metavar="SIZE")
parser.add_option("-f", "--format", dest="format",
default="jpeg", help="Output image format", metavar="FORMAT")
(options, _) = parser.parse_args()
max_size = options.size.lower()
percent = False
if max_size.endswith('%'):
max_size = int(max_size[:-1])
if max_size < 1 or max_size > 100:
parser.error('Invalid percentage')
max_size = max_size / 100.0
percent = True
else:
unit = max_size[-1]
units = {'k': 1024, 'm': 1024**2, 'g': 1024**3}
if unit in units:
max_size = int(max_size[:-1])
max_size *= units[unit]
else:
parser.error('Invalid size format')
遍历文件,并且只处理图片
我们可以使用os.walk来遍历文件夹下的所有文件,然后只处理.jpeg/.jpeg/.png这样的图片
遍历出的文件,我们可以通过os.path.splitext来获取文件的扩展名,然后判断是否是图片
并且我们可以通过os.path.join来拼接文件的路径
def walk_dir(input_dir, output_dir, max_size, percent, format):
"""walk through input_dir and convert images to output_dir
"""
for root, _, files in os.walk(input_dir):
for file in files:
ext = os.path.splitext[file](1).lower()
if ext not in ('.jpg', '.jpeg', '.png'):
continue
input_file = os.path.join(root, file)
output_file = input_file.replace(input_dir, output_dir)
convert_file(input_file, output_file,
max_size, percent, format)
调整图片大小
我们的算法是通过修改图片的大小来改变文件的大小,这个算法有个明显缺陷会改变图片的尺寸,如果不修改图片的尺寸,那么就需要改变图片的质量
- 调用Pillow库的Image.open来打开图片,然后获取图片的大小,然后根据图片的大小和文件的大小来计算新的大小
- 如果是百分比,那么就直接调整图片的大小
- 如果是固定大小,那么就计算新的大小,然后调整图片的大小
- 最后保存图片到输出文件,通过img.save来保存图片
with Image.open(input_file) as img:
img_size = os.path.getsize(input_file)
if percent:
width, height = img.size
max_width = int(width * max_size)
max_height = int(height * max_size)
img = img.resize((max_width, max_height), Image.LANCZOS)
else:
# check file size
if img_size < max_size:
print(f'{input_file} ({img_size}) -> {output_file} (skip)')
return
# calculate new size
width, height = img.size
scale_factor = (max_size / img_size) ** 0.59
new_width = int(width * scale_factor)
new_height = int(height * scale_factor)
img = img.resize((new_width, new_height), Image.LANCZOS)
try:
img.save(output_file, format=format)
new_size = os.path.getsize(output_file)
print(f'{input_file} ({img_size}) -> {output_file} ({new_size})')
except OSError as e:
print(f'{input_file} failed: ({e})')
总结
Python特别适合做文件处理,并且支持跨平台,日常工作中可以用Python做文件处理,比如批量处理图片,批量处理文本等。
写一个批量处理的工具可以大幅度的提升效率,这也是python作为自动化工具首选的原因
批量处理工具还需要考虑很多因素,比如目录的创建,是否要保留源文件等等,这些都是非常细节的事情,也是决定工具好坏的关键。
推荐大家学习一门静态语言,比如Java、C++,这样可以更好的理解编程语言的底层原理,同时也要掌握一门动态语言,比如Python、JavaScript,这样可以更好的提高工作效率。
所有的后端面试常见的问题,我们每天都会在我们的编程群里面讨论和Code review, 欢迎大家加入我们的编程群,一起学习和进步。
欢迎大家关注 入职啦 (公众号: ruzhila) ,获取更多有趣的编程挑战题和技术干货!