15 Stimmen

Wie kann ich ein UIImage aus einer 3D-transformierten UIImageView erstellen/darstellen?

Nachdem ich eine 3D-Transformation auf eine UIImageView.layer angewendet habe, muss ich die resultierende "Ansicht" als ein neues UIImage speichern... Schien wie eine einfache Aufgabe auf den ersten :-) aber kein Glück so weit, und die Suche hat keine Hinweise gefunden :-( so ich hoffe, jemand wird so freundlich sein, mich in die richtige Richtung zeigen.

Ein sehr einfaches iPhone-Projekt ist verfügbar aquí .

Gracias.

- (void)transformImage {
    float degrees = 12.0;
    float zDistance = 250;
    CATransform3D transform3D = CATransform3DIdentity;
    transform3D.m34 = 1.0 / zDistance; // the m34 cell of the matrix controls perspective, and zDistance affects the "sharpness" of the transform
    transform3D = CATransform3DRotate(transform3D, DEGREES_TO_RADIANS(degrees), 1, 0, 0); // perspective transform on y-axis
    imageView.layer.transform = transform3D;
}

/* FAIL : capturing layer contents doesn't get the transformed image -- just the original

CGImageRef newImageRef = (CGImageRef)imageView.layer.contents;

UIImage *image = [UIImage imageWithCGImage:newImageRef];

*/

/* FAIL : docs for renderInContext states that it does not render 3D transforms

UIGraphicsBeginImageContext(imageView.image.size);

[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

*/
//
// header
//
#import <QuartzCore/QuartzCore.h>
#define DEGREES_TO_RADIANS(x) x * M_PI / 180
UIImageView *imageView;
@property (nonatomic, retain) IBOutlet UIImageView *imageView;

//
// code
//
@synthesize imageView;

- (void)transformImage {
    float degrees = 12.0;
    float zDistance = 250;
    CATransform3D transform3D = CATransform3DIdentity;
    transform3D.m34 = 1.0 / zDistance; // the m34 cell of the matrix controls perspective, and zDistance affects the "sharpness" of the transform
    transform3D = CATransform3DRotate(transform3D, DEGREES_TO_RADIANS(degrees), 1, 0, 0); // perspective transform on y-axis
    imageView.layer.transform = transform3D;
}

- (UIImage *)captureView:(UIImageView *)view {
    UIGraphicsBeginImageContext(view.frame.size);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

- (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSString *title = @"Save to Photo Album";
    NSString *message = (error ? [error description] : @"Success!");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

- (IBAction)saveButtonClicked:(id)sender {
    UIImage *newImage = [self captureView:imageView];
    UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), nil);  
}

0 Stimmen

Haben Sie versucht, die Ansicht, die Ihre transformierte Ansicht enthält, zu greifen?

0 Stimmen

Nicht ganz sicher, was Sie meinen... Ich habe es mit [view image] versucht (wobei view mein UIImageView ist), aber das zurückgegebene Bild ist nicht das transformierte Bild.

1 Stimmen

Haben Sie eine Antwort auf diese Frage gefunden?

0voto

benzado Punkte 78100

In Ihrem captureView: Methode, versuchen Sie, diese Zeile zu ersetzen:

[view.layer renderInContext:UIGraphicsGetCurrentContext()];

damit:

[view.layer.superlayer renderInContext:UIGraphicsGetCurrentContext()];

Möglicherweise müssen Sie die Größe anpassen, die Sie zur Erstellung des Bildkontexts verwenden.

Ich finde in der API-Dokumentation nichts, was besagt, dass renderInContext: 3D-Transformationen ignoriert. Die Transformationen gelten jedoch für die Ebene, nicht für ihren Inhalt, weshalb Sie die übergeordnete Ebene rendern müssen, um die angewandte Transformation zu sehen.

Beachten Sie, dass der Aufruf von drawRect: in der Superview wird definitiv nicht funktionieren, da drawRect: zeichnet keine Unteransichten.

-1voto

Arash Punkte 1236

Eine Lösung, die zumindest in meinem Fall funktioniert hat, war die Unterklasse CALayer . Wenn ein renderInContext: Nachricht an eine Schicht gesendet wird, leitet diese Schicht diese Nachricht automatisch an alle ihre Unterschichten weiter. Alles, was ich also tun musste, war, die Unterklasse CALayer und überschreiben Sie die renderInContext: Methode und gerendert, was ich brauchte, um in dem bereitgestellten Kontext gerendert werden.

In meinem Code hatte ich zum Beispiel eine Ebene, deren Inhalt ich auf ein Bild eines Pfeils setzte:

UIImage *image = [UIImage imageNamed:@"arrow.png"];
MYLayer *myLayer = [[CALayer alloc] init];
[myLayer setContents:(__bridge id)[image CGImage]];
[self.mainLayer addSublayer:myLayer];

Als ich nun eine 3D-Drehung von 180 Grad über die Y-Achse auf den Pfeil anwandte und versuchte, eine [self.mainLayer renderInContext:context] Danach erhielt ich immer noch das ungedrehte Bild.

Also in meiner Unterklasse MyLayer Ich habe mich über renderInContext: und ein bereits gedrehtes Bild verwendet, um einen vorgegebenen Kontext einzuzeichnen:

- (void)renderInContext:(CGContextRef)ctx
{
    NSLog(@"Rendered in context");
    UIImage *image = [UIImage imageNamed:@"arrow_rotated.png"];
    CGContextDrawImage(ctx, self.bounds, image.CGImage);
}

In meinem Fall hat das funktioniert, aber ich kann mir vorstellen, dass man bei vielen 3D-Transformationen nicht für jedes mögliche Szenario ein Bild bereithalten kann. In vielen anderen Fällen sollte es jedoch möglich sein, das Ergebnis der 3D-Transformation mit 2D-Transformationen im übergebenen Kontext zu rendern. Zum Beispiel in meinem Fall, anstatt ein anderes Bild zu verwenden arrow_rotated.png Ich könnte die arrow.png spiegeln und in den Kontext einzeichnen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X