geekdoc-python-zh/docs/pythonlibrary/create-an-exif-viewer-with-...

8.1 KiB
Raw Permalink Blame History

用 PySimpleGUI 创建 Exif 查看器

原文:https://www.blog.pythonlibrary.org/2021/01/26/create-an-exif-viewer-with-pysimplegui/

Pillow package 让你能够从图像中提取 Exif(可交换图像文件格式)元数据。你可以通过 Exif 数据获得很多关于你的图片的信息。然而,有一些关键数据点比其他数据点更有用。

对于这些数据,最好创建一个 GUI以便您可以轻松查看。对于本教程您将使用 PySimpleGUI

入门指南

Pillow 和 PySimpleGUI 都需要安装,以便能够遵循本教程。您可以使用 pip 安装它们:

python -m pip install pillow PySimpleGUI

您可能希望在 Python 虚拟环境中安装这些包。可以使用 virtualenv 或者 Python 内置的 venv 模块

无论您最终选择哪种方式,您现在都已经准备好编写 GUI 代码了!

创建简单的 Exif 查看器

第一步是找到一个包含 Exif 数据的图像。如果你愿意,你可以用这个:

Bridge

当您写完代码后,您的 Exif 查看器将如下所示:

PySimpleGUI EXIF Viewer

首先,创建一个名为 exif_viewer.py 的新文件,并添加以下代码:

# exif_viewer.py

import PySimpleGUI as sg

from pathlib import Path
from PIL import Image
from PIL.ExifTags import TAGS

file_types = [("(JPEG (*.jpg)", "*.jpg"),
              ("All files (*.*)", "*.*")]

fields = {
    "File name": "File name",
    "File size": "File size",
    "Model": "Camera Model",
    "ExifImageWidth": "Width",
    "ExifImageHeight": "Height",
    "DateTime": "Creation Date",
    "static_line": "*",
    "MaxApertureValue": "Aperture",
    "ExposureTime": "Exposure",
    "FNumber": "F-Stop",
    "Flash": "Flash",
    "FocalLength": "Focal Length",
    "ISOSpeedRatings": "ISO",
    "ShutterSpeedValue": "Shutter Speed",
}

def get_exif_data(path):
    """
    Extracts the Exif information from the provided photo
    """
    exif_data = {}
    try:
        image = Image.open(path)
        info = image._getexif()
    except OSError:
        info = {}

    if info is None:
        info = {}

    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        exif_data[decoded] = value

    return exif_data

def main():
    elements = [
        [
            sg.FileBrowse(
                "Load image data", file_types=file_types, key="load",
                enable_events=True
            )
        ]
    ]
    for field in fields:
        elements += [
            [sg.Text(fields[field], size=(10, 1)),
             sg.Text("", size=(25, 1), key=field)]
        ]
    window = sg.Window("Image information", elements)

    while True:
        event, values = window.read()
        if event == "Exit" or event == sg.WIN_CLOSED:
            break
        if event == "load":
            image_path = Path(values["load"])
            exif_data = get_exif_data(image_path.absolute())
            for field in fields:
                if field == "File name":
                    window[field].update(image_path.name)
                elif field == "File size":
                    window[field].update(image_path.stat().st_size)
                else:
                    window[field].update(exif_data.get(field, "No data"))

if __name__ == "__main__":
    main()

这是一大段代码!试图一次解释所有内容会令人困惑,所以为了使事情变得简单,你将一段一段地检查代码。

下面是前几行代码:

# exif_viewer.py

import PySimpleGUI as sg

from pathlib import Path
from PIL import Image
from PIL.ExifTags import TAGS

file_types = [("(JPEG (*.jpg)", "*.jpg"),
              ("All files (*.*)", "*.*")]

fields = {
    "File name": "File name",
    "File size": "File size",
    "Model": "Camera Model",
    "ExifImageWidth": "Width",
    "ExifImageHeight": "Height",
    "DateTime": "Creation Date",
    "static_line": "*",
    "MaxApertureValue": "Aperture",
    "ExposureTime": "Exposure",
    "FNumber": "F-Stop",
    "Flash": "Flash",
    "FocalLength": "Focal Length",
    "ISOSpeedRatings": "ISO",
    "ShutterSpeedValue": "Shutter Speed",
}

这段代码的前半部分是使应用程序正常运行所需的导入。接下来,创建一个file_types变量。这在您稍后将创建的文件对话框中使用,以允许用户选择要加载的图像。

然后创建一个 Python 字典,保存所有想要显示的 Exif 字段。这个字典将 Exif 名称映射到一个更易读的名称。

现在您已经准备好学习get_exif_data()功能了:

def get_exif_data(path):
    """
    Extracts the EXIF information from the provided photo
    """
    exif_data = {}
    try:
        image = Image.open(path)
        info = image._getexif()
    except OSError:
        info = {}

    if info is None:
        info = {}

    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        exif_data[decoded] = value

    return exif_data

这个函数接收图像路径,并试图从中提取 Exif 数据。如果失败,它将info设置为一个空字典。如果_getexif()返回None,那么你也将info设置为一个空字典。如果填充了info,那么在返回之前,循环遍历它,解码 Exif 数据并填充您的exif_data字典。

接下来您可以进入main()功能:

def main():
    elements = [
        [
            sg.FileBrowse(
                "Load image data", file_types=file_types, key="load",
                enable_events=True
            )
        ]
    ]
    for field in fields:
        elements += [
            [sg.Text(fields[field], size=(10, 1)),
             sg.Text("", size=(25, 1), key=field)]
        ]
    window = sg.Window("Image information", elements)

在这里,您可以创建创建用户界面所需的所有元素。循环遍历在程序开始时定义的字段字典,并添加几个文本控件,这些控件将显示从图像中提取的 Exif 数据。

PySimpleGUI 使这变得很容易,因为您可以将新元素连接到您的elements列表中。

一旦这些都完成了,你就把elements加到你的Window上。

接下来是拼图的最后一块:

    while True:
        event, values = window.read()
        if event == "Exit" or event == sg.WIN_CLOSED:
            break
        if event == "load":
            image_path = Path(values["load"])
            exif_data = get_exif_data(image_path.absolute())
            for field in fields:
                if field == "File name":
                    window[field].update(image_path.name)
                elif field == "File size":
                    window[field].update(image_path.stat().st_size)
                else:
                    window[field].update(exif_data.get(field, "No data"))

if __name__ == "__main__":
    main()

这是您的事件循环。当用户按下“加载图像数据”按钮时,事件被设置为“加载”。在这里,您将选择的图像路径加载到 Python 的pathlib中。这允许您使用Path对象的功能和属性提取文件名、绝对路径和文件大小。

您使用字典的get()方法来获取字段。如果该字段不在字典中,则显示该字段“无数据”。

如果您想要一个小的挑战,尝试在这个 GUI 中添加一个sg.Image()元素,这样您就可以查看照片及其元数据了!

包扎

现在你知道如何从图像中解析出 EXIF 标签了。您还学习了如何使用 PySimpleGUI 创建一个简单的 GUI。这个 GUI 的总行数只有 84 行!您可以创建功能性 GUI而无需编写数百行代码。

Pillow 能做的不仅仅是提取 EXIF 数据。检查一下,看看你还能做什么!

相关阅读