2014-09-24 2 views
18

Hat jemand eine Idee, wie man quadratische Daumen von PHImageManager holt? Die Option PHImageContentModeAspectFill hat keine Auswirkungen.Wie kann man quadratische Thumbnails von PHImageManager holen?

[[PHImageManager defaultManager] 
    requestImageForAsset:(PHAsset *)_asset 
      targetSize:CGSizeMake(80, 80) 
      contentMode:PHImageContentModeAspectFill 
       options:nil 
     resultHandler:^(UIImage *result, NSDictionary *info) { 
    // sadly result is not a squared image 
    imageView.image = result; 
}]; 
+0

Hallo Pavel - hat für Sie meine Antwort Arbeit? Wenn ja, würden Sie es bitte als akzeptiert markieren? –

+0

Danke für die Antwort Josh, aber die wirkliche Lösung, die für mich funktioniert, ist es, Daumen mit der Größe 100x100 oder mehr anzufordern. Ihre Lösung ist nur ein Workaround gegen "intelligente" Algorithmen in PHImageManager, also entschuldige, dass ich sie nicht akzeptieren kann. –

+0

Ist das nicht ein Maßstab für Retina-Bildschirme? Ich ging davon aus, dass das Ziel ein Bild war, das für ein UiMageView mit 80 Punkten genau richtig ist, wo Ihr Code ein 80-Pixel-Bild verlangte, das bei Retina-Skalierungen zu klein ist - das könnte der Grund sein, mehr als 100x100 zu verbessern. Mit welchen Algorithmen arbeitet mein Code? Ich denke, es funktioniert korrekt mit dem Photos-Framework, und ich habe es in meiner App, wenn es gegen etwas arbeitet, würde ich gerne wissen, da ich das Framework optimal nutzen möchte. Wenn Sie eine bessere Lösung haben, wird die Beantwortung Ihrer eigenen Frage empfohlen :) –

Antwort

1

Um einen genauen Platz zu bekommen, werden Sie müssen zeigen, dass Sie durch das Weiterleiten von Optionen eine exakte Größe wünschen, etwa so:

PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 

    // No, really, we want this exact size  
    options.resizeMode = PHImageRequestOptionsResizeModeExact 

    [[PHImageManager defaultManager] 
      requestImageForAsset:(PHAsset *)_asset 
         targetSize:CGSizeMake(160, 160) 
         contentMode:PHImageContentModeAspectFill 
          options:options 
        resultHandler:^(UIImage *result, NSDictionary *info) { 

    // Happily, result is now a squared image 
    imageView.image = result; 
    }]; 
+0

Für mich führt dies dazu, dass einige Bilder gequetscht oder gedehnt werden. –

+0

Das funktioniert nicht, wenn Sie kleine Bilder anfordern. –

+0

Nur weil Sie nach der genauen Größe fragen, heißt das nicht, dass der Inhaltsmodus ignoriert wird. In diesem Fall ist der Inhaltsmodus immer noch aspect fill und Sie erhalten also nicht quadratische Bilder zurück (vorausgesetzt, das Original ist nicht bereits quadratisch). – EarlyRiser

19

Update:

Der Bug beim Beschneiden Bilder, wie sie von PHImageManager abgerufen wurden, wurde in iOS 8.3 behoben, so dass für diese Version von iOS und später, mein ursprüngliches Beispiel, wie folgt funktioniert: Es scheint die Fehler sind immer noch da und bis iOS 8.4, kann ich sie mit Standard-iPhone 6s zurück Kamerabilder reproduzieren, wobei eine volle Größe Platz Ernte. Sie sind in iOS 9.0 richtig behoben, wo selbst große Bilder eines 63-Megapixel-Panoramas gut funktionieren.

Der von Apple definierte Ansatz besteht darin, eine CGRect im Koordinatenraum des Bildes zu übergeben, wobei der Ursprung (0,0) und das Maximum (1,1) ist. Sie übergeben diese Rect im PHImageRequestOptions Objekt, zusammen mit einem resizeMode von PHImageRequestOptionsResizeModeExact, und dann sollten Sie ein beschnittenes Bild zurück erhalten.

- (void)showSquareImageForAsset:(PHAsset *)asset 
{ 
    NSInteger retinaScale = [UIScreen mainScreen].scale; 
    CGSize retinaSquare = CGSizeMake(100*retinaScale, 100*retinaScale); 

    PHImageRequestOptions *cropToSquare = [[PHImageRequestOptions alloc] init]; 
    cropToSquare.resizeMode = PHImageRequestOptionsResizeModeExact; 

    CGFloat cropSideLength = MIN(asset.pixelWidth, asset.pixelHeight); 
    CGRect square = CGRectMake(0, 0, cropSideLength, cropSideLength); 
    CGRect cropRect = CGRectApplyAffineTransform(square, 
               CGAffineTransformMakeScale(1.0/asset.pixelWidth, 
                      1.0/asset.pixelHeight)); 

    cropToSquare.normalizedCropRect = cropRect; 

    [[PHImageManager defaultManager] 
    requestImageForAsset:(PHAsset *)asset 
    targetSize:retinaSquare 
    contentMode:PHImageContentModeAspectFit 
    options:cropToSquare 
    resultHandler:^(UIImage *result, NSDictionary *info) { 
     self.imageView.image = result; 
    }]; 
} 

Dieses Beispiel macht seine cropRect der Seitenlänge gleich dem kleineren von der Breite und Höhe des Vermögenswerts, und dann in dem Koordinatenraum des Bildes wandelt sie unter Verwendung von CGRectApplyAffineTransform. Vielleicht möchten Sie den Ursprung von square auf etwas anderes als (0,0) setzen, so oft Sie möchten, dass das Crop-Quadrat entlang der Achse des Bildes, das abgeschnitten wird, zentriert ist, aber ich lasse das als Übung für den Leser . :-)

Ursprüngliche Antwort:

John Antwort hat mich da die meisten die Art und Weise, aber seinen Code Ich war gespannt zu werden und zerquetscht Bilder. Hier ist, wie ich eine imageView bekommen habe, um quadratische Thumbnails aus dem PHImageManager anzuzeigen.

Stellen Sie zunächst sicher, dass die Eigenschaft contentMode für Ihre UIImageView auf ScaleAspectFill festgelegt ist. Der Standardwert ist ScaleToFill, der nicht korrekt funktioniert, um quadratische Miniaturbilder aus PHImageManager anzuzeigen, also stellen Sie sicher, dass Sie dies ändern, ob Sie die UIImageView in Code oder im Storyboard instanziiert haben.

//view dimensions are based on points, but we're requesting pixels from PHImageManager 
NSInteger retinaMultiplier = [UIScreen mainScreen].scale; 
CGSize retinaSquare = CGSizeMake(imageView.bounds.size.width * retinaMultiplier, imageView.bounds.size.height * retinaMultiplier); 

[[PHImageManager defaultManager] 
    requestImageForAsset:(PHAsset *)_asset 
       targetSize:retinaSquare 
       contentMode:PHImageContentModeAspectFill 
        options:nil 
      resultHandler:^(UIImage *result, NSDictionary *info) { 

    // The result is not square, but correctly displays as a square using AspectFill 
    imageView.image = result; 
}]; 

Angabe PHImageRequestOptionsResizeModeExact für die resizeMode nicht erforderlich ist, da es Sie nicht eine beschnittene Bild geben, wenn Sie auch eine normalizedCropRect liefern, und hier nicht verwendet werden sollte, da es keinen Nutzen ist, und dessen Verwendung bedeutet, dass Sie don‘ t die Vorteile von schnell zurückgespeicherten Bildern nutzen.

Die UIImage in result zurückgegeben wird das gleiche Seitenverhältnis wie die Quelle sein, aber richtig zur Verwendung in einem UIImageView skaliert, dem Aspekts gesetzt füllen als ein Quadrat angezeigt werden, also, wenn Sie es gerade angezeigt wird, ist dies der Weg, den man gehen sollte. Wenn Sie das Bild für den Druck oder Export außerhalb der App zuschneiden müssen, ist dies nicht das, was Sie wollen - schauen Sie sich die Verwendung von normalizedCropRect dafür an. (Bearbeiten- siehe unten zum Beispiel, was funktionieren soll ...

)

Außer dies auch sicherstellen, dass der Sie den Inhalt Modus des UIImageView UIViewContentModeScaleAspectFill gesetzt und dass Sie setzen clipsToBounds = YES durch die folgenden zwei Zeilen:

imageView.contentMode=UIViewContentModeScaleAspectFill; 
imageView.clipsToBounds=YES; 

bearbeiten zu Fügen Sie normalizedCropRect Verwendungsbeispiel hinzu
WARNUNG - das funktioniert nicht, sollte aber gemäß Apple's documentation.

Der von Apple definierte Ansatz besteht darin, eine CGRect im Koordinatenraum des Bildes zu übergeben, wobei der Ursprung (0,0) und das Maximum (1,1) ist. Sie übergeben diese Rect im PHImageRequestOptions Objekt, zusammen mit einem resizeMode von PHImageRequestOptionsResizeModeExact, und dann sollten Sie ein beschnittenes Bild zurück erhalten. Das Problem ist, dass Sie es nicht tun, es kommt zurück wie das ursprüngliche Seitenverhältnis und das vollständige Bild.

Ich habe überprüft, dass das Crop-Rect korrekt im Koordinatenraum des Bildes erstellt wurde, und folgte der Anweisung PHImageRequestOptionsResizeModeExact zu verwenden, aber dem Ergebnishandler wird immer noch ein Bild im ursprünglichen Seitenverhältnis übergeben. Dies scheint ein Fehler im Framework zu sein, und wenn es behoben ist, sollte der folgende Code funktionieren.

- (void)showSquareImageForAsset:(PHAsset *)asset 
{ 
    NSInteger retinaScale = [UIScreen mainScreen].scale; 
    CGSize retinaSquare = CGSizeMake(100*retinaScale, 100*retinaScale); 

    PHImageRequestOptions *cropToSquare = [[PHImageRequestOptions alloc] init]; 
    cropToSquare.resizeMode = PHImageRequestOptionsResizeModeExact; 

    CGFloat cropSideLength = MIN(asset.pixelWidth, asset.pixelHeight); 
    CGRect square = CGRectMake(0, 0, cropSideLength, cropSideLength); 
    CGRect cropRect = CGRectApplyAffineTransform(square, 
               CGAffineTransformMakeScale(1.0/asset.pixelWidth, 
                      1.0/asset.pixelHeight)); 

    cropToSquare.normalizedCropRect = cropRect; 

    [[PHImageManager defaultManager] 
    requestImageForAsset:(PHAsset *)asset 
    targetSize:retinaSquare 
    contentMode:PHImageContentModeAspectFit 
    options:cropToSquare 
    resultHandler:^(UIImage *result, NSDictionary *info) { 
     self.imageView.image = result; 
    }]; 
} 

Alles, was ich vorschlagen kann, ist, dass, wenn Sie dieses Problem haben, Sie file a radar mit Apple zu verlangen, dass sie es zu beheben!

+3

Ich denke, Sie sollten '[UIScreen mainScreen] .scale' anstelle von' 2' verwenden.iPhone 6 Plus, @ 3x und all das. – DCMaxxx

+1

Danke DCMaxxx, guter Punkt. –

+0

Extrem hilfreich; Eine Sache, vor der Sie gewarnt sein sollten, wenn Sie dies mit einer Sammlungsansicht tun, besteht die Möglichkeit, dass Sie eine 'UICollectionViewCell'-Erweiterung erstellt haben, die Ihre' UIImageView' umschließt. Eines der Probleme, die ich hatte war, dass ich 'cell.contentMode =' anstelle von 'cell.imageView.contentMode =' (das ist die Verwendung der ursprünglichen Antwort) – mike

5
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 
    options.resizeMode = PHImageRequestOptionsResizeModeExact; 

    NSInteger retinaMultiplier = [UIScreen mainScreen].scale; 
    CGSize retinaSquare = CGSizeMake(imageView.bounds.size.width * retinaMultiplier, imageView.bounds.size.height * retinaMultiplier); 

    [[PHImageManager defaultManager] 
      requestImageForAsset:(PHAsset *)_asset 
         targetSize:retinaSquare 
         contentMode:PHImageContentModeAspectFill 
          options:options 
        resultHandler:^(UIImage *result, NSDictionary *info) { 

        imageView.image =[UIImage imageWithCGImage:result.CGImage scale:retinaMultiplier orientation:result.imageOrientation]; 

    }]; 
+1

Verwenden Sie 'result.imageOrientation' anstelle von fest codierter Ausrichtung, um Probleme zu vermeiden. – Andy

+0

hat gut funktioniert thx. – Rikco

0

Dies funktioniert gut für mich:

__block UIImage* imgThumb; 

CGSize size=CGSizeMake(45, 45);// Size for Square image 

[self.imageManager requestImageForAsset:<your_current_phAsset> 
          targetSize:size 
          contentMode:PHImageContentModeAspectFill 
           options:nil 
          resultHandler:^(UIImage *result, NSDictionary *info) { 

           imgThumb = result; 

    }];