Удаление строки состояния со скриншота на iOS

Я пытаюсь удалить верхнюю часть изображения путем обрезки, но результат неожиданный. Используемый код:

extension UIImage {
    class func removeStatusbarFromScreenshot(_ screenshot:UIImage) -> UIImage {
        let statusBarHeight = 44.0
        let newHeight = screenshot.size.height - statusBarHeight
        let newSize = CGSize(width: screenshot.size.width, height: newHeight)
        let newOrigin = CGPoint(x: 0, y: statusBarHeight)
        let imageRef:CGImage = screenshot.cgImage!.cropping(to: CGRect(origin: newOrigin, size: newSize))!
        let cropped:UIImage = UIImage(cgImage:imageRef)
        return cropped
    }
}

Моя логика заключается в том, что мне нужно сделать изображение меньше по высоте на 44 пикселя и переместить исходную точку y на 44 пикселя, но в конечном итоге это создаст изображение, намного меньшее в верхнем левом углу.

Единственный способ заставить его работать должным образом - умножить ширину на 2 и высоту на 2,5 в newSize, но это также удвоит размер созданного изображения. Что в любом случае не имеет особого смысла... может кто-нибудь помочь заставить его работать без использования магических значений?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть две основные проблемы с тем, что вы делаете:

  • UIImage имеет масштаб (обычно привязанный к разрешению экрана вашего устройства), а CGImage — нет.

  • Разные устройства имеют разную высоту «строки состояния». В общем, то, что вы хотите отрезать сверху, это не строка состояния, а безопасная область. В верхней части безопасной области начинается ваш контент.

Из-за этого:

  • Вы ошибаетесь, говоря о 44 px. Здесь нет пикселей. Пиксели — это физические атомарные подсветки на вашем экране. В коде есть точки. Точки не зависят от масштаба (а масштаб — это множитель между точками и пикселями).

  • Вы ошибаетесь, когда говорите о самом числе 44 так, будто оно жестко запрограммировано. Вместо этого вы должны добраться до вершины безопасной зоны.

  • Переходя в мир CGImage без учета масштаба, вы теряете информацию о масштабе, потому что CGImage ничего не знает о масштабе.

  • Вернувшись в мир UIImage без учета масштаба, вы получите UIImage с разрешением 1, которое может не совпадать с разрешением исходного UIImage.

Самое простое решение — не делать ничего из того, что вы делаете. Во-первых, получите высоту безопасной зоны; назовите это h. Затем просто нарисуйте изображение снимка в контексте графического изображения, который имеет тот же масштаб, что и ваше изображение (что, если вы правильно разыграете свои карты, это будет автоматически), но на h пунктов короче, чем высота вашего изображения — и нарисуйте его. с его y началом в -h, тем самым отсекая безопасную область. Извлеките полученное изображение, и все готово.

Пример! Этот код входит в контроллер представления. Во-первых, я сделаю снимок экрана текущего экрана моего собственного устройства (представление этого контроллера представления), когда мое приложение работает:

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let screenshot = renderer.image { context in
    view.layer.render(in: context.cgContext)
}

Теперь я вырезаю безопасную область в верхней части этого скриншота:

let h = view.safeAreaInsets.top
let size = screenshot.size
let r = UIGraphicsImageRenderer(
    size: .init(width: size.width, height: size.height - h)
)
let result = r.image { _ in
    screenshot.draw(at: .init(x: 0, y: -h))
}

Эксперименты подтвердят, что это отлично работает на любом устройстве, независимо от того, есть ли у него рамка и независимо от разрешения экрана: верхняя часть полученного изображения, result, является верхней частью вашего фактического содержимого.

Другие вопросы по теме