使用PIL开发加水印程序时修改字体大小触发OSError问题求助
图片加水印程序OSError: cannot open resource问题解决
问题描述
我正在开发一款图片加水印程序,原本功能正常,但尝试修改字体大小时,持续触发错误:OSError: cannot open resource。尝试更换字体、设置默认字体,但错误仍会不定期出现。
原代码
import tkinter as tk from tkinter import filedialog from tkinter.filedialog import askopenfile from PIL import Image, ImageTk, ImageDraw, ImageFont import matplotlib.pyplot as plt window = tk.Tk() window.geometry("600x500") window.title('Upload your image') open_file_path = None label = tk.Label(window,text='Add Photo',width=30) label.grid(row=0,column=0) label.place(relx=0.25, rely=0.01) button = tk.Button(window, text='Upload File', width=20,command = lambda:upload_file()) button.grid(row=1,column=0) button.place(relx=0.29, rely=0.1) text = tk.Text(width = 40,height = 5) text.place(relx = 0.24, rely = 0.3) button_confirm = tk.Button(window,text = "Confirm text watermark",command = lambda:retrieve_input()) button_confirm.place(relx = 0.33,rely = 0.5) def retrieve_input(): input_value = text.get('1.0','end-1c') return input_value def upload_file(): global open_file_path font_type = ImageFont.truetype("arial.ttf", 18) input_text = retrieve_input() open_file_path = filedialog.askopenfilename() image = Image.open(open_file_path) width,height = image.size draw_watermark = ImageDraw.Draw(image) fill_color = (203, 201, 201) x = width/2-50 y = height/2-50 position = (x,y) draw_watermark.text(xy=position, text=input_text, fill=fill_color, font=font_type) image.save('watermark_image.jpg') # plt.imshow(image) window.mainloop()
报错堆栈
Exception in Tkinter callback Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/tkinter/__init__.py", line 1948, in __call__ return self.func(*args) ^^^^^^^^^^^^^^^^ File "/Users/admin/Desktop/Python/watermark_gui/main.py", line 17, in <lambda> button = tk.Button(window, text='Upload File', width=20,command = lambda:upload_file()) ^^^^^^^^^^^^^ File "/Users/admin/Desktop/Python/watermark_gui/main.py", line 30, in upload_file font_type = ImageFont.truetype("arial.ttf", 18) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/admin/Desktop/Python/watermark_gui/env/lib/python3.12/site-packages/PIL/ImageFont.py", line 797, in truetype return freetype(font) ^^^^^^^^^^^^^^ File "/Users/admin/Desktop/Python/watermark_gui/env/lib/python3.12/site-packages/PIL/ImageFont.py", line 794, in freetype return FreeTypeFont(font, size, index, encoding, layout_engine) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/admin/Desktop/Python/watermark_gui/env/lib/python3.12/site-packages/PIL/ImageFont.py", line 226, in __init__ self.font = core.getfont( ^^^^^^^^^^^^^ OSError: cannot open resource
解决方案
错误核心原因
ImageFont.truetype("arial.ttf")无法在系统中准确定位字体文件:
- macOS系统下直接写字体文件名,PIL无法自动识别系统字体路径
- 每次点击上传都重复加载字体,容易引发资源加载冲突
修复步骤
- 指定字体完整路径:直接使用系统字体的绝对路径,避免路径查找失败
- 提前加载字体:将字体初始化放在函数外,只加载一次
- 添加异常 fallback:加载失败时自动切换到PIL默认字体
修改后的代码
import tkinter as tk from tkinter import filedialog from PIL import Image, ImageDraw, ImageFont window = tk.Tk() window.geometry("600x500") window.title('Upload your image') open_file_path = None # 提前加载字体并添加异常处理 try: # macOS下Arial字体的默认绝对路径 font_type = ImageFont.truetype("/Library/Fonts/Arial.ttf", 18) except OSError: # 加载失败时使用PIL默认字体 font_type = ImageFont.load_default() label = tk.Label(window,text='Add Photo',width=30) label.place(relx=0.25, rely=0.01) button = tk.Button(window, text='Upload File', width=20,command = lambda:upload_file()) button.place(relx=0.29, rely=0.1) text = tk.Text(width = 40,height = 5) text.place(relx = 0.24, rely = 0.3) button_confirm = tk.Button(window,text = "Confirm text watermark",command = lambda:retrieve_input()) button_confirm.place(relx = 0.33,rely = 0.5) def retrieve_input(): input_value = text.get('1.0','end-1c') return input_value def upload_file(): global open_file_path input_text = retrieve_input() open_file_path = filedialog.askopenfilename() if not open_file_path: return # 用户取消选择文件时直接返回,避免后续报错 image = Image.open(open_file_path) width,height = image.size draw_watermark = ImageDraw.Draw(image) fill_color = (203, 201, 201) x = width/2 - 50 y = height/2 - 50 position = (x,y) draw_watermark.text(xy=position, text=input_text, fill=fill_color, font=font_type) image.save('watermark_image.jpg') window.mainloop()
多系统兼容扩展
如果需要支持Windows/Linux,可以通过判断系统来选择对应字体路径:
import sys if sys.platform == 'darwin': font_path = "/Library/Fonts/Arial.ttf" elif sys.platform == 'win32': font_path = "C:/Windows/Fonts/arial.ttf" else: # Linux下使用开源替代字体 font_path = "/usr/share/fonts/truetype/freefont/FreeSans.ttf"
内容的提问来源于stack exchange,提问作者Via4eslav Tka4enko
相关产品推荐
相关产品推荐

