Saving UIView Inhalte in iOS 4 mit realer Größe der Bilder im Innern (das heißt Skala contentes bis zum Speichern)

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

Frage

Ich habe eine UIView mit vielen UIImageViews als Subviews. Die App läuft auf iOS4 und ich Bilder mit Retina Display Auflösung (das heißt, die Bilder Last mit Skala = 2)

Ich möchte den Inhalt des UIView retten ... ABER ... haben die reale Größe der inneren Bilder. D. h die Ansicht hat eine Größe 200x200 und Bilder mit Skala = 2 nach innen, ich mag ein resultierendes Bild von 400x400 und alle die Bilder mit ihrer tatsächlichen Größe speichern.

Nun, was kommt zuerst in dem Sinn ist es, einen neues Bild Kontext und lädt wieder alle Bilder im Innern mit Skala = 1 zu schaffen, und das sollte tun, aber ich habe mich gefragt, ob es eine elegantere Möglichkeit ist, das zu tun? Scheint wie eine Taille von Speicher und Prozessorzeit wieder neu zu laden alles da ist es schon getan ...

P. S. wenn jemand eine Antwort hat - einschließlich Code wäre schön

War es hilfreich?

Lösung

Die Umsetzung für das Rendern jede UIView Bild (Arbeits auch für Retina Display).

helper.h-Datei:

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

und die zugehörige Implementierung in helper.m-Datei:

#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 ist der Skalierungsfaktor. Der Skalierungsfaktor auf die Bitmap anwenden. Wenn Sie einen Wert von 0,0 angeben, wird der Skalierungsfaktor auf den Skalierungsfaktor des Hauptbildschirms des Geräts.

QuartzCore.framework auch in das Projekt gesteckt werden sollten, weil wir die Funktion auf dem Layer-Objekt aufrufen.

Um schwache Verbindung auf UIKit Rahmen zu aktivieren, klicken Sie auf das Projektelement in der linken Navigator auf das Projektziel -> Build-Phasen. -> Link binär und wählen "optional" (schwach) Typ auf UIKit Rahmen

Hier ist Bibliothek mit ähnlichen Erweiterungen für UIColor, UIImage, NSArray, NSDictionary, ...

Andere Tipps

Ich habe so etwas durchgeführt, die Stifte aus der MKMapView als PNG-Datei (in Retina-Display) zu speichern: MKPinAnnotationView: gibt es mehr als drei Farben verfügbar

?

Hier ist ein Auszug aus der entscheidenden Rolle, die das führt einen UIView Speicher (theView) seine Netzhaut Definition:


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

Der Schlüssel ist, dass der dritte Parameter zu UIGraphicsBeginImageContextWithOptions ist die scale , die bestimmt, wie das Bild schließlich heraus geschrieben werden.

Wenn Sie immer die tatsächlichen Pixelabmessungen wollen, verwenden Sie [[UIScreen mainscreen] Skala] den aktuellen Maßstab des Bildschirms erhalten:

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

Wenn Sie Skala verwenden = 1,0 auf iPhone4, werden Sie ein Bild mit seiner Dimension erhalten in Punkte und das Ergebnis skaliert wird von der wahren Pixelzahl nach unten. Wenn Sie das Bild manuell schreiben, auf eine 640x960 Dimension (zB: passing Pixel als ersten Parameter), wird es tatsächlich die abgespeckte Bild sein, das wieder nach oben skaliert wird, die Blicke über so schrecklich, wie Sie sich vorstellen würde es aussehen

Könnten Sie nicht erstellen Sie einfach einen neuen Grafikkontext in der gewünschten Größe, verwenden Sie ein CGAffineTransform es verkleinern, macht die Wurzellage der Wurzel UIView, den Kontext auf die ursprüngliche Größe wieder herzustellen und das Bild machen? Haben Sie nicht versucht, dies für Retina-Gehalt, aber dies scheint zu funktionieren gut für große Bilder, die in UIImageViews verkleinert wurden ...

so etwas wie:

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

Import Quartz (Klicken Hauptprojekt, Build-Phasen, Import) und wo Sie es hinzufügen müssen:

#import <QuartzCore/QuartzCore.h>

Meine imageViews sind Eigenschaften, wenn Sie nicht, die .self ignorieren und die imageViews in die Funktion als Parameter übergeben, dann Aufruf renderInContext auf den beiden Bildern in einem neuen 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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top