Проверка удаления GPS из экспортируемых фотографий iOS

Security ·~5 мин чтения

Проверка удаления GPS из экспортируемых фотографий iOS

В интерфейсе публикации фотографии место съёмки может не отображаться, но экспортированный файл всё ещё может содержать координаты. При разработке экспорта изображений в iOS проверять нужно файл, который в итоге получит адресат, а не предварительный просмотр в приложении. Тестовая фотография с GPS-данными на облачном Mac позволяет превратить это требование к приватности в воспроизводимую проверку файла.

Сначала определите границу экспорта

Типичный путь выглядит так: выбрать фотографию, отредактировать или изменить её размер, создать временный файл и передать его механизму отправки. На каждом этапе метаданные могут обрабатываться по-разному. Проверка только изображения, возвращённого средством выбора, не доказывает, что итоговый файл очищен. Проверки миниатюры перед отправкой тоже недостаточно.

Команда должна подготовить тестовый образец сама и убедиться, что исходный файл действительно содержит словарь GPS. Не используйте реальные фотографии пользователей в непрерывной интеграции и не помещайте образец с координатами в открытый репозиторий. Храните его в каталоге тестовых ресурсов с ограниченным доступом, зафиксируйте ожидаемые формат и размеры в пикселях, а после теста удаляйте созданные файлы.

Критерий прохождения здесь — «в итоговом файле нет словаря GPS», а не «экспортированный файл побайтово совпадает с оригиналом». После повторного кодирования хеш файла обычно меняется.

Создание и повторная проверка файла с помощью ImageIO

Следующий скрипт Swift читает входное изображение, декодирует его и снова кодирует в формате исходного файла. Он явно передаёт только ориентацию, а не весь словарь метаданных исходного файла. Затем скрипт повторно открывает выходной файл и проверяет словарь GPS, размеры, ориентацию и формат. Сначала сохраните скрипт под именем redact.swift в изолированном каталоге:

import Foundation
import ImageIO
import CoreGraphics

guard CommandLine.arguments.count == 3 else {
    fatalError("Usage: redact input output")
}

let input = URL(fileURLWithPath: CommandLine.arguments[1])
let output = URL(fileURLWithPath: CommandLine.arguments[2])
guard input.standardizedFileURL != output.standardizedFileURL else {
    fatalError("Input and output must differ")
}
guard let source = CGImageSourceCreateWithURL(input as CFURL, nil),
      let type = CGImageSourceGetType(source),
      let image = CGImageSourceCreateImageAtIndex(source, 0, nil),
      let original = CGImageSourceCopyPropertiesAtIndex(source, 0, nil)
        as? [CFString: Any],
      let destination = CGImageDestinationCreateWithURL(
        output as CFURL, type, 1, nil
      ) else {
    fatalError("Cannot read input or create output")
}

let orientation = original[kCGImagePropertyOrientation] ?? 1
let options: [CFString: Any] = [
    kCGImagePropertyOrientation: orientation
]
CGImageDestinationAddImage(destination, image, options as CFDictionary)
guard CGImageDestinationFinalize(destination),
      let result = CGImageSourceCreateWithURL(output as CFURL, nil),
      let finalImage = CGImageSourceCreateImageAtIndex(result, 0, nil),
      let metadata = CGImageSourceCopyPropertiesAtIndex(result, 0, nil)
        as? [CFString: Any] else {
    fatalError("Cannot verify output")
}

guard metadata[kCGImagePropertyGPSDictionary] == nil,
      CGImageSourceGetType(result) == type,
      finalImage.width == image.width,
      finalImage.height == image.height,
      String(describing: metadata[kCGImagePropertyOrientation] ?? 1)
        == String(describing: orientation) else {
    fatalError("Export verification failed")
}
print("GPS removed; format, dimensions and orientation checked")

Запустите команды в терминале облачного Mac:

swiftc -framework Foundation -framework ImageIO \
  -framework CoreGraphics redact.swift -o redact
./redact fixtures/with-gps.jpg output/without-gps.jpg

Сначала создайте каталог output и замените пример входного файла на JPEG, в котором подтверждено наличие словаря GPS. Успешное выполнение означает лишь то, что конкретный выходной файл прошёл проверку. Если в рабочем приложении есть пути с обрезкой, сжатием или расширением отправки, проверяйте итоговый файл каждого из них. Скрипт не заменяет фактическую реализацию экспорта в приложении.

Добавьте отрицательный тест

Одного успешного теста «после очистки» недостаточно, чтобы убедиться, что проверка работает. Тем же способом чтения проверьте входной образец: словарь GPS должен обнаружиться. Затем проверьте выходной файл: словаря в нём быть не должно. Если координат не было уже во входном файле, успешная проверка обоих файлов ничего не доказывает. Чтобы координаты не попали в журналы, не выводите их значения или полные метаданные.

Сохраните также копию файла без очистки в качестве отрицательного теста и убедитесь, что проверка её отклоняет. Копируйте байты файла напрямую, не пропуская его через инструменты обработки изображений, которые могут переписать метаданные. Так вы проверите и очистку, и то, что средство проверки не принимает ошибку чтения за отсутствие GPS.

Что ещё проверить после повторного кодирования

Удаление геоданных не гарантирует, что изображение во всём остальном осталось пригодным. Декодирование и повторное кодирование могут изменить качество сжатия с потерями, цветопередачу или другие метаданные, не связанные с местоположением. Совпадение размеров также не означает попиксельного совпадения. Добавьте в набор регрессионных тестов фотографии из разных источников: как минимум вертикальные и горизонтальные снимки, а также разные метки ориентации. Просмотрите итоговые файлы вручную, чтобы заметить поворот, искажение цветов или явную потерю качества.

Проверка Критерий прохождения
Геоданные В итоговом файле нет словаря GPS
Размеры изображения Ширина и высота соответствуют ожидаемым для данного пути экспорта
Ориентация Изображение отображается правильно с учётом метки ориентации выходного файла
Формат файла Адресат получает файл ожидаемого формата
Ошибка чтения Тест завершается неудачей; ошибка не считается «отсутствием GPS»

Пример скрипта требует совпадения размеров с исходным изображением и подходит для экспорта без изменения размера. Если продукт обрезает или сжимает изображение, проверяйте размеры, явно ожидаемые для соответствующего пути. Если нужно сохранить цветовой профиль или определённые поля авторских прав, напишите для них отдельные тесты. Не копируйте ради этого исходный словарь метаданных целиком.

Включите проверку в процесс приёмки на облачном Mac

Храните тестовый образец, файлы, фактически созданные приложением, и скрипт проверки отдельно. Сначала конвейер должен выполнить экспорт, затем прочитать файл по конечному пути передачи адресату. Отсутствие файла, невозможность его декодировать или ошибка чтения метаданных должны сразу приводить к провалу теста. Для параллельных заданий используйте отдельные выходные каталоги, чтобы файлы от предыдущего запуска не создали ложный успех.

В завершение проверьте результат вручную: выполните в приложении реальную отправку или сохранение и повторно проверьте файл, полученный адресатом, а не только промежуточный кеш. Так можно обнаружить ошибку пути, при которой предварительный просмотр после редактирования очищен, но при отправке приложение снова обращается к исходному файлу. После успешной проверки удалите временные экспортированные файлы. В отчёте фиксируйте только наличие или отсутствие словаря GPS, размеры, ориентацию и этап сбоя — не координаты. Тогда результат приёмки можно будет воспроизвести, не раскрывая удаляемые данные в журналах диагностики.

Часто задаваемые вопросы

Если приложение не показывает место съёмки, значит ли это, что GPS удалён?

Нет. Нужно отдельно прочитать метаданные готового экспортированного файла и убедиться, что GPS-словарь отсутствует.

Нужно ли сравнивать хеши исходного и экспортированного файлов?

Нет. Перекодирование может изменить байты файла. Проверяйте GPS-словарь, размеры, ориентацию и визуальный результат по отдельности.

Выберите срок аренды

Проверьте следующий шаг на выделенном физическом Mac mini

VMCommit предлагает выделенные физические Mac mini с чипом M4 в аренду на день, неделю, месяц или квартал. Выберите модель и локацию, а затем проверьте доступность в реальном времени в панели управления.

Арендовать Mac mini