Risparmio UIView contenuti in iOS 4 con dimensioni reali delle immagini interne (vale a dire scala contentes per Save)

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

Domanda

Ho un UIView con molti UIImageViews come subviews. Le piste app su iOS4 e io uso le immagini con risoluzione display retina (vale a dire il carico le immagini con scale = 2)

Io voglio salvare il contenuto del UIView ... MA ... avere la dimensione reale delle immagini all'interno. Cioè la vista ha dimensioni 200x200 e le immagini con scale = 2 all'interno, mi piacerebbe salvare un'immagine risultante di 400x400 e tutte le immagini con la loro dimensione reale.

Ora che cosa viene prima in mente è quello di creare un nuovo contesto di immagini e caricare di nuovo tutte le immagini all'interno con scale = 1 e che dovrebbe fare, ma mi chiedevo se c'è un modo più elegante per farlo? Sembra una vita di memoria e del processore il tempo di ricaricare tutto nuovo dal momento che è già stato fatto ...

P.S. se qualcuno ha una risposta - incluso il codice sarebbe bello

È stato utile?

Soluzione

Implementazione per il rendering di qualsiasi UIView per l'immagine (che lavora anche per il display retina).

file helper.h:

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

e di appartenenza implementazione nel file di 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 è il fattore di scala. Il fattore di scala da applicare alla bitmap. Se si specifica un valore di 0.0, il fattore di scala è impostato il fattore di scala della schermata principale del dispositivo.

QuartzCore.framework anche dovrebbe essere messo nel progetto perché siamo funzione chiamante sull'oggetto livello.

Per abilitare anello debole sul quadro UIKit, fare clic sulla voce progetto nel navigatore di sinistra, fare clic sul target del progetto -> fasi di creazione -.> Collegamento binario e scegliere il tipo di "optional" (debole) sul quadro UIKit

Ecco biblioteca con le estensioni simili per UIColor, UIImage, NSArray, NSDictionary, ...

Altri suggerimenti

Ho eseguito una cosa per salvare i perni del MKMapView come file PNG (in retina display): MKPinAnnotationView: ci sono più di tre colori disponibili

?

Ecco un estratto della parte cruciale che esegue il salvataggio di un UIView (theView) utilizzando la sua definizione della 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 chiave è che il terzo parametro UIGraphicsBeginImageContextWithOptions è la scala , che determina come l'immagine viene infine scritta fuori.

Se si desidera sempre le dimensioni in pixel reali, l'uso [[UIScreen mainScreen] scala] per ottenere la scala corrente dello schermo:

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

Se si utilizza scale = 1.0 su iPhone4, si otterrà un'immagine con la sua dimensione in punti e il risultato viene ridimensionato dal vero numero di pixel. Se si scrive a mano l'immagine fuori ad una dimensione 640x960 (ad esempio: passando pixel come primo parametro), sarà effettivamente essere l'immagine in scala ridotta che viene ridimensionato up che si guarda attorno come terribile come si immagina sarebbe risultato

Non potevi solo creare un nuovo contesto grafico alla dimensione desiderata, utilizzare un CGAffineTransform a scala verso il basso, rendono lo strato radice del UIView radice, ripristinare il contesto per le dimensioni originali e rendere l'immagine? Non ho provato questo per i contenuti della retina, ma questo sembra funzionare bene per le grandi immagini che sono state ridimensionate in UIImageViews ...

qualcosa di simile:

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

Importa QuartzCore (clicca progetto principale, fasi di creazione, importazione) e dove serve aggiungere:

#import <QuartzCore/QuartzCore.h>

I miei imageViews sono proprietà, se il vostro non sono, ignorare il .self e passare le imageViews nella funzione come parametri, renderInContext poi chiamata sulle due immagini in una nuova 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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top