查看: 143|回复: 1

Python批量修改图片DPI:基于Pillow实现批量脚本与参数解读

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
学术投稿、期刊论文对图片DPI有严格要求,多数期刊要求300dpi甚至600dpi,而ArcGIS截图、屏幕截图默认仅为72或96dpi。手动逐张修改费时费力,PS动作批量处理也常卡顿。本文提供一个纯Python批量修改图片DPI的解决方案,基于Pillow库实现,支持JPG/PNG/TIFF等格式,并详解参数含义与踩坑点。

一、DPI与像素的关系
DPI(Dots Per Inch)是打印分辨率标识,修改DPI不会改变图片的像素尺寸,只影响打印时的物理尺寸(物理尺寸 = 像素尺寸 / DPI)。例如,一张3000×2400像素的图,设置为300dpi时打印尺寸为10×8英寸;若设为600dpi则打印尺寸缩小为5×4英寸,但像素不变。因此,仅修改DPI元数据不会改变文件体积,仅改变打印/出版属性。

二、核心实现:单图片DPI修改
Pillow的Image.save()方法直接支持dpi参数,几行代码即可完成:
  1. from PIL import Image
  2. with Image.open('input.jpg') as img:
  3.     img.save('output.jpg', dpi=(600, 600), quality=95)
复制代码

参数说明:
- dpi:元组(x, y),建议x和y相同。对于JPG,设置dpi即可写入EXIF元数据;PNG也支持dpi元数据(部分读取器可能忽略)。
- quality(仅JPG):1-100整数,推荐95,在文件大小和画质间平衡较好。
- subsampling=0:在JPG保存时禁用4:2:0色度子采样,可避免文字边缘模糊,适合插图。

三、批量处理脚本(带错误处理与格式过滤)
以下脚本遍历输入文件夹,自动跳过非图片文件,支持JPG/JPEG/PNG,批量修改DPI并保持原文件名输出到目标文件夹:
  1. from PIL import Image
  2. import os
  3. INPUT_FOLDER = r".\input"     # 原图存放路径
  4. OUTPUT_FOLDER = r".\output"   # 输出路径
  5. TARGET_DPI = (600, 600)        # 目标DPI
  6. os.makedirs(OUTPUT_FOLDER, exist_ok=True)
  7. extensions = ('.png', '.jpg', '.jpeg')
  8. count_ok = count_skip = 0
  9. for filename in os.listdir(INPUT_FOLDER):
  10.     filepath = os.path.join(INPUT_FOLDER, filename)
  11.     if not os.path.isfile(filepath):
  12.         continue
  13.     ext = os.path.splitext(filename)[1].lower()
  14.     if ext not in extensions:
  15.         count_skip += 1
  16.         continue
  17.     try:
  18.         with Image.open(filepath) as img:
  19.             params = {'dpi': TARGET_DPI}
  20.             if ext in ('.jpg', '.jpeg'):
  21.                 params['quality'] = 95
  22.                 params['subsampling'] = 0
  23.             img.save(os.path.join(OUTPUT_FOLDER, filename), **params)
  24.             count_ok += 1
  25.     except Exception as e:
  26.         count_skip += 1
  27.         print(f'处理失败: {filename} | {e}')
  28. print(f'成功: {count_ok} 张,跳过: {count_skip} 个')
复制代码

四、使用步骤
1. 安装Pillow:pip install Pillow
2. 在脚本同级目录新建input和output文件夹。
3. 将待处理图片放入input文件夹,运行脚本。
4. 处理后的图片出现在output文件夹,右键属性→详细信息可查看DPI变化。

五、常见踩坑与解决办法
1. JPG保存后变糊:未设置quality或过低,请显式设为95,并添加subsampling=0。
2. 文件扩展名大小写:.JPG等大写后缀,脚本中使用.lower()转换即可。
3. 图片被其他程序占用(如PS打开):关闭占用程序再运行。
4. TIFF格式支持:在extensions元组中添加('.tiff', '.tif'),Pillow可处理TIFF DPI元数据。

六、高级扩展:两种DPI修改模式
除了仅修改元数据,有时需要同时重采样像素以保持打印物理尺寸一致。以下区分两种模式并提供函数实现。

模式1:仅修改DPI元数据(不改变像素尺寸)
适用于已有像素足够大、只需更新打印标识的场景。注意:PNG保存时可能丢失dpi,可转为JPEG或TIFF。
  1. def batch_set_dpi_metadata(input_dir, output_dir, target_dpi=300, extensions=('.jpg', '.jpeg', '.png', '.tiff', '.bmp')):
  2.     import os
  3.     from PIL import Image
  4.     os.makedirs(output_dir, exist_ok=True)
  5.     for fname in os.listdir(input_dir):
  6.         if not fname.lower().endswith(extensions):
  7.             continue
  8.         src = os.path.join(input_dir, fname)
  9.         dst = os.path.join(output_dir, fname)
  10.         with Image.open(src) as img:
  11.             if img.format == 'PNG' and dst.lower().endswith('.png'):
  12.                 dst = os.path.splitext(dst)[0] + '.jpg'
  13.                 img = img.convert('RGB')
  14.             img.save(dst, dpi=(target_dpi, target_dpi))
复制代码

模式2:按目标DPI重采样图像(改变像素尺寸)
若原图像素过小,仅改DPI会导致打印物理尺寸过小,需按公式“新像素 = 原像素 × (目标DPI / 原始DPI)”进行缩放。此处使用LANCZOS高质量重采样。
  1. def batch_resize_by_dpi(input_dir, output_dir, target_dpi=300):
  2.     import os
  3.     from PIL import Image
  4.     os.makedirs(output_dir, exist_ok=True)
  5.     for fname in os.listdir(input_dir):
  6.         if not fname.lower().endswith(('.jpg', '.jpeg', '.png', '.tiff')):
  7.             continue
  8.         src = os.path.join(input_dir, fname)
  9.         dst = os.path.join(output_dir, fname)
  10.         with Image.open(src) as img:
  11.             src_dpi = img.info.get('dpi', (72, 72))[0]
  12.             if src_dpi == target_dpi:
  13.                 img.save(dst)
  14.                 continue
  15.             ratio = target_dpi / src_dpi
  16.             new_size = (int(img.width * ratio), int(img.height * ratio))
  17.             resized = img.resize(new_size, Image.Resampling.LANCZOS)
  18.             resized.save(dst, dpi=(target_dpi, target_dpi))
复制代码

七、终极方案:通过piexif直接修改JPEG的EXIF DPI标签
有些期刊要求精确写入EXIF中的XResolution/YResolution,使用piexif库可绕过Pillow的封装,更可靠。
  1. import os, piexif
  2. from PIL import Image
  3. def batch_set_dpi_exif(input_dir, output_dir, target_dpi=300):
  4.     os.makedirs(output_dir, exist_ok=True)
  5.     for fname in os.listdir(input_dir):
  6.         if not fname.lower().endswith(('.jpg', '.jpeg')):
  7.             continue
  8.         src = os.path.join(input_dir, fname)
  9.         dst = os.path.join(output_dir, fname)
  10.         img = Image.open(src)
  11.         try:
  12.             exif = piexif.load(img.info.get('exif', b''))
  13.         except:
  14.             exif = {'0th': {}, 'Exif': {}, 'GPS': {}, '1st': {}}
  15.         exif['0th'][piexif.ImageIFD.XResolution] = (target_dpi, 1)
  16.         exif['0th'][piexif.ImageIFD.YResolution] = (target_dpi, 1)
  17.         exif['0th'][piexif.ImageIFD.ResolutionUnit] = 2
  18.         exif_bytes = piexif.dump(exif)
  19.         img.save(dst, exif=exif_bytes)
复制代码

总结:本文提供的Python脚本可直接用于学术投稿前的DPI批量修改,核心在于Pillow的save方法。根据需求选择仅改元数据或重采样,JPEG注意quality和subsampling参数,PNG建议转JPEG以保留DPI信息。实测处理几百张图片仅需数秒,显著提升效率。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python批量修改图片DPI:基于Pillow实现批量脚本与参数解读

感谢分享!这个批量脚本对需要处理学术论文配图的人太实用了。我之前手动用PS一张张改DPI,遇到几十张图真是崩溃。尤其你提到的 `subsampling=0` 和 `quality=95` 组合避免文字模糊,这个细节很关键,很多批量处理工具默认会压缩画质。 想请教一下:对于PNG图片改DPI后转成JPG保存,会不会因为色彩空间或透明通道造成意外?如果原图带透明背景(比如科研示意图),转JPG会丢失透明信息,有没有保留PNG格式但写入DPI元数据的更稳妥做法?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-11 11:29 , Processed in 0.031753 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部