Зачем использовать много памяти при рисовании изображения с помощью UIGraphicsImageRenderer? - PullRequest
0 голосов
/ 17 апреля 2020

Я хочу добавить белую рамку к фотографии, сохраняя при этом качество фотографии, поэтому я использую UIGraphicsImageRenderer, чтобы нарисовать белый фон, а затем нарисовать фотографию вверх, в результате чего * драма c увеличивается в памяти использование, есть ли лучший способ?

Разрешение оригинального изображения 4032 * 3024.

let renderer = UIGraphicsImageRenderer(size: CGSize(width: canvasSideLength, height: canvasSideLength))
let newImage = renderer.image { context in
    UIColor.white.setFill()
    context.fill(CGRect(x: 0, y: 0, width: canvasSideLength, height: canvasSideLength))
    image.draw(in: CGRect(x: photoCanvasX, y: photoCanvasY, width: photoCanvasWidth, height: photoCanvasHeight))
}

enter image description here enter image description here enter image description here

1 Ответ

1 голос
/ 17 апреля 2020

При рассмотрении используемой памяти не следует вводить в заблуждение размером файла JPG или PNG, поскольку он обычно сжат. Вам потребуется четыре байта на пиксель при выполнении операций с изображениями в памяти (например, ширина × высота × 4 в пикселях).

Хуже, по умолчанию UIGraphicsImageRenderer будет генерировать изображения с разрешением экрана (например, потенциально 2 × или 3 × в зависимости от вашего устройства). Например, на устройстве 3 × рассмотрим:

let rect = CGRect(origin: .zero, size: CGSize(width: 8_519, height: 8_519))
let image = UIGraphicsImageRenderer(bounds: rect).image { _ in
    UIColor.white.setFill()
    UIBezierPath(rect: rect).fill()
}
print(image.cgImage!.width, "×", image.cgImage!.height)

Это будет печатать:

25557 × 25557

Когда вы считаете, что это занимает 4 байта на пиксель, что составляет до 2,6 ГБ. Даже если изображение имеет размер только 4 032 × 3024, как предполагает ваш пересмотренный вопрос, это все равно 439 МБ на изображение.

Возможно, вы захотите указать явную шкалу 1:

let rect = CGRect(origin: .zero, size: CGSize(width: 8_519, height: 8_519))
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let image = UIGraphicsImageRenderer(bounds: rect, format: format).image { _ in
    UIColor.white.setFill()
    UIBezierPath(rect: rect).fill()
}
print(image.cgImage!.width, "×", image.cgImage!.height)

, которая будет печататься, как вы ожидали:

8519 × 8519

Тогда вам понадобится только 290 Мб для изображения. Это все еще много памяти, но намного меньше, чем при использовании шкалы по умолчанию (на устройствах Retina). Или, учитывая ваше исправленное изображение 4,032 × 3024, это изображение 1 × может занимать всего 49 МБ, 1/9 размера соответствующего изображения 3 ×, где вы не установили масштаб.

...