Сохранение содержимого UIView в iOS 4 с реальным размером изображений внутри (т.е. масштаб увеличивается для сохранения) - PullRequest
10 голосов
/ 18 ноября 2010

У меня есть UIView со многими UIImageViews как подпредставления.Приложение работает на iOS4, и я использую изображения с разрешением экрана сетчатки (то есть изображения загружаются с масштабом = 2)

Я хочу сохранить содержимое UIView ... НО ... иметь реальный размеризображения внутри.Т.е. представление имеет размер 200x200 и изображения с масштабом = 2, я хотел бы сохранить результирующее изображение 400x400 и все изображения с их реальным размером.

Теперь первое, что приходит на ум, - это создатьНовый контекст изображения и снова загрузите все изображения с масштабом = 1, и это должно сработать, но мне было интересно, есть ли более элегантный способ сделать это?Кажется, тратит память и время процессора, чтобы перезагрузить все заново, поскольку это уже сделано ...

ps, если у кого-то есть ответ - включая код, было бы неплохо

Ответы [ 5 ]

25 голосов
/ 25 ноября 2010

Реализация для рендеринга любого 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, ...

4 голосов
/ 24 ноября 2010

Я выполнил такую ​​операцию, чтобы сохранить контакты из MKMapView в виде файла PNG (в сетчатке): MKPinAnnotationView: доступно более трех цветов?

Вот выдержка из важной части, которая выполняет сохранение UIView (theView), используя его определение сетчатки:


-(void) saveMyView:(UIView*)theView {
    //The image where the view content is going to be saved.
    UIImage* image = nil;
    UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, 2.0);
    [theView.layer renderInContext: UIGraphicsGetCurrentContext()];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData* imgData = UIImagePNGRepresentation(image);
    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;
}
2 голосов
/ 23 апреля 2011

Ключ в том, что третьим параметром для UIGraphicsBeginImageContextWithOptions является scale , который определяет, как в конечном итоге будет записано изображение.

Если вам всегда нужны реальные размеры в пикселях, используйте [[UIScreen mainScreen] scale], чтобы получить текущий масштаб экрана:

UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);

Если вы используете scale = 1.0 на iPhone4, вы получите изображение с его размером points , и результат будет уменьшен от истинного числа пикселей. Если вы вручную запишите изображение в размер 640x960 (например, передавая пиксели в качестве первого параметра), это будет фактически уменьшенное изображение, которое будет уменьшено, и выглядит примерно так же ужасно, как вы представляете.

0 голосов
/ 16 мая 2013

Импортируйте QuartzCore (щелкните основной проект, этапы сборки, импортируйте) и, где вам это нужно, добавьте:

#import <QuartzCore/QuartzCore.h>

Мои изображения imageViews - это свойства, если нет, игнорируйте .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;
}
0 голосов
/ 24 ноября 2010

Не могли бы вы просто создать новый графический контекст нужного размера, использовать 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();
...