Сохранение содержимого UIView в iOS 4 с реальным размером изображений внутри (то есть масштабирование контента для сохранения)
У меня есть UIView со многими UIImageViews как subviews. Приложение работает на iOS4, и я использую изображения с разрешением экрана сетчатки (т.е. Загрузка изображений с помощью шкалы = 2)
Я хочу сохранить содержимое UIView... НО... имеют реальный размер изображений внутри. То есть вид имеет размер 200x200 и изображения со шкалой = 2 внутри, я хотел бы сохранить результирующее изображение 400x400 и все изображения с их реальным размером.
Теперь, прежде всего, нужно создать новый контекст изображения и снова загрузить все изображения внутри с помощью scale = 1, и это должно было бы сделать, но мне было интересно, есть ли еще более элегантный способ сделать это? Кажется, что талия памяти и процессорное время перезаряжают все снова, так как это уже сделано...
p.s. если у кого есть ответ - в том числе код будет приятным
Ответы
Ответ 1
Реализация для рендеринга любого UIView для изображения (работающая также для отображения сетчатки).
helper.h файл:
@interface UIView (Ext)
- (UIImage*) renderToImage;
@end
и принадлежность к реализации в файле helper.m:
#import <QuartzCore/QuartzCore.h>
@implementation UIView (Ext)
- (UIImage*) renderToImage
{
// IMPORTANT: using weak link on UIKit
if(UIGraphicsBeginImageContextWithOptions != NULL)
{
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(self.frame.size);
}
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
0.0 - масштабный коэффициент. Масштабный коэффициент для применения к растровому изображению. Если вы укажете значение 0.0, масштабный коэффициент будет установлен на масштабный коэффициент главного экрана устройства.
QuartzCore.framework также должен быть помещен в проект, потому что мы вызываем функцию на объекте слоя.
Чтобы включить слабую ссылку в инфраструктуре UIKit, нажмите на элемент проекта в левом навигаторе, выберите цель проекта → фазы сборки → ссылка на двоичный код и выберите "необязательный" (слабый) тип в каркасе UIKit.
Вот библиотека с аналогичными расширениями для UIColor, UIImage, NSArray, NSDictionary,...
Ответ 2
Я выполнил такую вещь, чтобы сохранить булавки из MKMapView в виде PNG файла (на экране сетчатки): MKPinAnnotationView: есть ли более трех цветов?
Здесь выдержка из важной части, которая выполняет сохранение UIView
( theView
) с использованием определения сетчатки:
- (void) saveMyView: (UIView *) theView { // Изображение, в котором будет сохранен контент представления. UIImage * image = nil; UIGraphicsBeginImageContextWithOptions (theView.frame.size, NO, 2.0); [theView.layer renderInContext: UIGraphicsGetCurrentContext()]; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData * imgData = UIImagePNGRпредставление (изображение); NSString * targetPath = [NSString stringWithFormat: @ "% @/% @", [self writablePath], @ "thisismyview.png" ]; [imgData writeToFile: targetPath atomically: YES];
}
- (NSString *) writablePath { NSArray * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); NSString * documentsDirectory = [paths objectAtIndex: 0]; return documentsDirectory;
}
Ответ 3
Ключом является то, что третьим параметром для UIGraphicsBeginImageContextWithOptions является масштаб, который определяет, как изображение будет в конечном счете выписано.
Если вам нужны реальные размеры пикселей, используйте масштаб [[UIScreen mainScreen]], чтобы получить текущий масштаб экрана:
UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);
Если вы используете scale = 1.0 на iPhone4, вы получите изображение с его размером в точках, и результат будет уменьшен с истинного количества пикселей. Если вы вручную выведете изображение на размер 640x960 (например, передаете пиксели в качестве первого параметра), на самом деле это будет уменьшенное изображение с масштабированием, которое выглядит так же ужасно, как вы думаете, что он будет выглядеть.
Ответ 4
Не могли бы вы просто создать новый графический контекст с нужным размером, использовать CGAffineTransform для его масштабирования, рендеринга корневого слоя корневого UIView, восстановить контекст до исходного размера и сделать изображение? Не пробовал это для содержимого сетчатки, но это, похоже, хорошо работает для больших изображений, которые были уменьшены в UIImageViews...
что-то вроде:
CGSize originalSize = myOriginalImage.size; //or whatever
//create context
UIGraphicsBeginImageContext(originalSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context); //1 original context
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, originalSize.height);
CGContextScaleCTM(context, 1.0, -1.0);
//original image
CGContextDrawImage(context, CGRectMake(0,0,originalSize.width,originalSize.height), myOriginalImage.CGImage);
CGContextRestoreGState(context);//1 restore to original for UIView render;
//scaling
CGFloat wratio = originalSize.width/self.view.frame.size.width;
CGFloat hratio = originalSize.height/self.view.frame.size.height;
//scale context to match view size
CGContextSaveGState(context); //1 pre-scaled size
CGContextScaleCTM(context, wratio, hratio);
//render
[self.view.layer renderInContext:context];
CGContextRestoreGState(context);//1 restore to pre-scaled size;
UIImage *exportImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Ответ 5
Импортировать QuartzCore (нажмите основной проект, Build Phases, import) и где вам нужно добавить:
#import <QuartzCore/QuartzCore.h>
Мои изображения - это свойства, если это не так, игнорируйте .self
и передайте imageViews в функцию в качестве параметров, затем вызовите renderInContext
на двух изображениях в новом UIGraphicsCurrentContext
- (UIImage *)saveImage
{
UIGraphicsBeginImageContextWithOptions(self.mainImage.bounds.size, NO, 0.0);
[self.backgroundImage.layer renderInContext:UIGraphicsGetCurrentContext()];
[self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *savedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return savedImage;
}