contenidos ahorro UIView en iOS 4 con el tamaño real de las imágenes en el interior (es decir, la escala contentes para guardar)

StackOverflow https://stackoverflow.com/questions/4213529

Pregunta

Tengo una UIView con muchas UIImageViews como subvistas. Las carreras de aplicaciones en iOS4 y utilizo imágenes con una resolución de pantalla de la retina (es decir, la carga de imágenes con la escala = 2)

quiero guardar el contenido de la UIView ... PERO ... tienen el tamaño real de las imágenes dentro. Es decir. la vista tiene un tamaño de 200x200 e imágenes con escala = 2 en el interior, me gustaría guardar una imagen resultante de 400x400 y todas las imágenes con su tamaño real.

Ahora lo que viene primero a la mente es la creación de un nuevo marco de imagen y cargar de nuevo todas las imágenes en el interior con escala = 1 y que debería hacer, pero me preguntaba si hay alguna forma más elegante de hacer eso? Parece que una cintura de la memoria y el procesador de tiempo para recargar todo de nuevo, puesto que ya ha hecho ...

p.s. si alguien tiene una respuesta - incluyendo el código sería bueno

¿Fue útil?

Solución

La aplicación para la representación cualquier UIView a la imagen (trabajando también para visualización de la retina).

archivo helper.h:

@interface UIView (Ext) 
- (UIImage*) renderToImage;
@end

y perteneciente aplicación en el archivo 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 es el factor de escala. El factor de escala para aplicar al mapa de bits. Si especifica un valor de 0,0, el factor de escala se establece en el factor de escala de la pantalla principal del dispositivo.

QuartzCore.framework también debe ser puesto en el proyecto porque estamos función de llamada en el objeto de capa.

Para habilitar el eslabón débil en el marco UIKit, haga clic en el elemento de proyecto en el navegador de la izquierda, haga clic en el objetivo del proyecto -> fases de construcción -.> Enlace binario y elegir el tipo "opcional" (débil) en el marco UIKit

Aquí es biblioteca con extensiones similares para UIColor, UIImage, NSArray, NSDictionary, ...

Otros consejos

He realizado tal cosa para salvar a los pines de la MKMapView como un archivo PNG (en la pantalla de la retina): MKPinAnnotationView: ¿hay más de tres colores disponibles

?

He aquí un extracto de la parte crucial que realiza el ahorro de un UIView (theView) utilizando su definición retina:


-(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; }

La clave es que el tercer parámetro a UIGraphicsBeginImageContextWithOptions es el escala , que determina cómo la imagen en última instancia va a ser escrito.

Si siempre quiere que las dimensiones reales de píxeles, el uso [[UIScreen mainScreen] escala] para obtener la escala actual de la pantalla:

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

Si utiliza la escala = 1.0 en iPhone4, obtendrá una imagen con su dimensión en puntos y el resultado es reducido del verdadero número de píxeles. Si escribe manualmente la imagen a una dimensión de 640x960 (por ejemplo: pasar píxeles como primer parámetro), en realidad será la imagen a escala reducida que se escala una copia de seguridad que se ve casi tan terrible como se imagina que se vería

¿No podrías crear un nuevo contexto gráfico con el tamaño deseado, use un CGAffineTransform para escalar hacia abajo, hacer que la capa de raíz de raíz UIView, restaurar el contexto de su tamaño original y producir la imagen? no han probado este contenido retina, pero esto parece que funciona bien para grandes imágenes que han sido reducido en UIImageViews ...

algo como:

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();

Importar QuartzCore (Click principal proyecto, las fases de construcción, importación) y donde lo necesite añadir:

#import <QuartzCore/QuartzCore.h>

Mis imageViews son propiedades, si no lo son, ignorar el .self y pasar los imageViews en la función como parámetros, renderInContext entonces llamada en las dos imágenes en una nueva 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top