You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python和Piexif为JPG添加EXIF GPS数据时遇struct.error错误求助

问题:使用Piexif添加GPS EXIF数据时触发struct.error: argument out of range错误

运行脚本时出现如下报错:

(venv) C:\projects\geo-photo>python test2.py
Traceback (most recent call last):
  File "C:\projects\geo-photo\test2.py", line 31, in <module>
    add_geolocation(image_path, latitude, longitude)
  File "C:\projects\geo-photo\test2.py", line 21, in add_geolocation
    exif_bytes = piexif.dump(exif_dict)
                 ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\projects\geo-photo\venv\Lib\site-packages\piexif\_dump.py", line 74, in dump
    gps_set = _dict_to_bytes(gps_ifd, "GPS", zeroth_length + exif_length)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\projects\geo-photo\venv\Lib\site-packages\piexif\_dump.py", line 335, in _dict_to_bytes
    length_str, value_str, four_bytes_over = _value_to_bytes(raw_value,
                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\projects\geo-photo\venv\Lib\site-packages\piexif\_dump.py", line 244, in _value_to_bytes
    new_value += (struct.pack(">L", num) +
struct.error: argument out of range

完整脚本

import piexif

def add_geolocation(image_path, latitude, longitude):
    exif_dict = piexif.load(image_path)

    # Convert latitude and longitude to degrees, minutes, seconds format
    def deg_to_dms(deg):
        d = int(deg)
        m = int((deg - d) * 60)
        s = int(((deg - d) * 60 - m) * 60)
        return ((d, 1), (m, 1), (s, 1))

    lat_dms = deg_to_dms(latitude)
    lon_dms = deg_to_dms(longitude)

    exif_dict["GPS"][piexif.GPSIFD.GPSLatitude] = lat_dms
    exif_dict["GPS"][piexif.GPSIFD.GPSLongitude] = lon_dms
    exif_dict["GPS"][piexif.GPSIFD.GPSLatitudeRef] = 'N' if latitude >= 0 else 'S'
    exif_dict["GPS"][piexif.GPSIFD.GPSLongitudeRef] = 'E' if longitude >= 0 else 'W'

    exif_bytes = piexif.dump(exif_dict)
    piexif.insert(exif_bytes, image_path)

    print("Geolocation data added to", image_path)

# Example usage
latitude = 34.0522  # Example latitude coordinates
longitude = -118.2437  # Example longitude coordinates
image_path = 'test.jpg'  # Path to your image

add_geolocation(image_path, latitude, longitude)

错误原因及修复方案

错误原因

问题出在负经度的转换逻辑:

  1. 当传入负经度(示例中的-118.2437)时,deg_to_dms函数里d = int(deg)会得到-118这个负数。
  2. Piexif在把EXIF字典转成字节流时,会用struct.pack(">L", num)打包GPS坐标数值,其中>L代表大端无符号长整型,无法处理负数,直接触发"参数超出范围"的错误。
  3. 按照EXIF规范,GPS坐标的度数、分、秒都应该是非负数值,正负完全由GPSLatitudeRef(N/S)和GPSLongitudeRef(E/W)字段标记,不需要把负数写入坐标值本身。

修复方案

修改deg_to_dms函数,先取输入度数的绝对值再进行分秒转换,确保生成的所有坐标分量都是非负的:

def deg_to_dms(deg):
    abs_deg = abs(deg)
    d = int(abs_deg)
    m = int((abs_deg - d) * 60)
    s = int(((abs_deg - d) * 60 - m) * 60)
    return ((d, 1), (m, 1), (s, 1))

可选优化:保留秒的精度

如果需要更精确的坐标,可以把秒用分数形式表示(EXIF支持分数格式的秒):

def deg_to_dms(deg):
    abs_deg = abs(deg)
    d = int(abs_deg)
    m = int((abs_deg - d) * 60)
    s = (abs_deg - d) * 60 * 60 - m * 60
    # 用6位小数精度的分数表示秒
    return ((d, 1), (m, 1), (int(s * 1000000), 1000000))

验证说明

修改后,负经度会被正确处理:

  • 度数取绝对值118,分、秒按正数计算
  • 经度方向通过GPSLongitudeRef设为'W'标记西经,完全符合EXIF GPS规范,Piexif可以正常打包数据,不会再触发struct错误。

内容的提问来源于stack exchange,提问作者Mike Resoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 08:26:34