Загрузка данных
import sys
import os
from PIL import Image
import piexif
from fractions import Fraction
def dms_to_decimal(gps_data, gps_ref):
"""
Преобразует координаты из формата градусы/минуты/секунды (рациональные числа)
в десятичные градусы.
gps_data: кортеж из трёх рациональных чисел ((deg_num, deg_den), (min_num, min_den), (sec_num, sec_den))
gps_ref: символ направления ('N', 'S', 'E', 'W')
"""
if not gps_data:
return None
# Извлекаем градусы, минуты, секунды как float
deg = gps_data[0][0] / gps_data[0][1] if gps_data[0][1] != 0 else 0
minutes = gps_data[1][0] / gps_data[1][1] if gps_data[1][1] != 0 else 0
seconds = gps_data[2][0] / gps_data[2][1] if gps_data[2][1] != 0 else 0
decimal = deg + minutes / 60.0 + seconds / 3600.0
# Корректируем знак в зависимости от полушария
if gps_ref in ['S', 'W']:
decimal = -decimal
return decimal
def format_value(value):
"""
Преобразует значение тега в читаемую строку.
Обрабатывает bytes, рациональные числа, списки и т.д.
"""
if isinstance(value, bytes):
try:
return value.decode('utf-8', errors='replace')
except:
return str(value)
elif isinstance(value, tuple) and all(isinstance(x, tuple) for x in value):
# Предполагаем рациональные числа
formatted = []
for num, den in value:
if den == 0:
formatted.append('0')
else:
# Сокращаем дробь, если нужно, или выводим как десятичную
frac = Fraction(num, den)
if frac.denominator == 1:
formatted.append(str(frac.numerator))
else:
formatted.append(f"{num}/{den} ({num/den:.3f})")
return ', '.join(formatted)
elif isinstance(value, tuple):
# Простой кортеж (например, версия)
return ', '.join(str(x) for x in value)
else:
return str(value)
def extract_metadata(image_path):
"""
Извлекает и выводит все метаданные изображения.
Возвращает координаты (lat, lon) в десятичных градусах, если они есть.
"""
if not os.path.isfile(image_path):
print(f"Ошибка: файл '{image_path}' не найден.")
return None
# 1. Основная информация через Pillow
try:
img = Image.open(image_path)
print("\n=== Основная информация ===")
print(f"Формат: {img.format}")
print(f"Размер: {img.size[0]} x {img.size[1]} пикселей")
print(f"Режим: {img.mode}")
if hasattr(img, 'info') and img.info:
print("\n--- Дополнительные поля из img.info ---")
for key, value in img.info.items():
if key != 'exif': # EXIF обработаем отдельно
print(f"{key}: {format_value(value)}")
except Exception as e:
print(f"Не удалось открыть изображение: {e}")
return None
# 2. EXIF данные
print("\n=== EXIF метаданные ===")
lat = lon = None
try:
exif_dict = piexif.load(image_path)
except Exception as e:
print(f"Не удалось загрузить EXIF: {e}")
exif_dict = {}
# Словари с именами тегов для каждого IFD
ifd_names = {
'0th': 'Изображение (0th)',
'Exif': 'Exif',
'GPS': 'GPS',
'Interop': 'Interoperability',
'1st': 'Thumbnail (1st)'
}
for ifd_name, ifd_data in exif_dict.items():
if ifd_name == 'thumbnail':
if ifd_data:
print(f"\n--- Thumbnail ---")
print(f"Размер thumbnail: {len(ifd_data)} байт")
continue
if not ifd_data:
continue
print(f"\n--- {ifd_names.get(ifd_name, ifd_name)} ---")
# Получаем словарь тегов для этого IFD
tags = piexif.TAGS.get(ifd_name, {})
for tag_id, value in ifd_data.items():
tag_name = tags.get(tag_id, {}).get('name', f'Unknown (0x{tag_id:04X})')
# Преобразуем значение в читаемый вид
readable_value = format_value(value)
print(f"{tag_name} ({tag_id}): {readable_value}")
# Извлекаем GPS координаты, если они есть
if ifd_name == 'GPS':
if tag_id == piexif.GPSIFD.GPSLatitude:
lat_data = value
elif tag_id == piexif.GPSIFD.GPSLatitudeRef:
lat_ref = value.decode() if isinstance(value, bytes) else value
elif tag_id == piexif.GPSIFD.GPSLongitude:
lon_data = value
elif tag_id == piexif.GPSIFD.GPSLongitudeRef:
lon_ref = value.decode() if isinstance(value, bytes) else value
# 3. Преобразуем GPS координаты в десятичный формат
if 'lat_data' in locals() and 'lat_ref' in locals() and 'lon_data' in locals() and 'lon_ref' in locals():
lat = dms_to_decimal(lat_data, lat_ref)
lon = dms_to_decimal(lon_data, lon_ref)
print(f"\n--- GPS координаты (десятичные) ---")
print(f"Широта: {lat:.6f}, Долгота: {lon:.6f}")
else:
print("\nGPS координаты не найдены.")
return lat, lon
def generate_google_maps_link(lat, lon):
"""Генерирует ссылку на Google Maps для заданных координат."""
if lat is not None and lon is not None:
return f"https://www.google.com/maps?q={lat},{lon}"
else:
return None
if __name__ == "__main__":
# Получаем имя файла из аргументов командной строки или запрашиваем ввод
if len(sys.argv) > 1:
filename = sys.argv[1]
else:
filename = input("Введите путь к изображению: ").strip()
coords = extract_metadata(filename)
if coords and coords[0] is not None and coords[1] is not None:
link = generate_google_maps_link(coords[0], coords[1])
print(f"\n=== Ссылка на Google Maps ===\n{link}")
else:
print("\nНе удалось определить GPS-координаты для построения ссылки.")