Aggiornamento:
Il bug nel ritaglio di immagini come sono stati recuperati da
PHImageManager
è stato risolto in iOS 8.3, quindi per quella versione di iOS e versioni successive, il mio esempio originale funziona come segue:
Sembra che i bug ci sono ancora fino a iOS 8.4 incluso, posso riprodurli con le immagini standard della fotocamera posteriore dell'iPhone 6s, prendendo un crop quadrato a grandezza naturale. Sono corretti in iOS 9.0, dove anche i grossi raccolti di un panorama a 63 megapixel funzionano bene.
L'approccio definito da Apple è il passaggio di uno CGRect
nello spazio di coordinate dell'immagine, dove l'origine è (0,0) e il massimo è (1,1). Si passa questo rettile nell'oggetto PHImageRequestOptions
, insieme a resizeMode
di PHImageRequestOptionsResizeModeExact
e quindi si dovrebbe recuperare un'immagine ritagliata.
- (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;
}];
}
Questo esempio rende sua cropRect
di lunghezza laterale uguale alla più piccola della larghezza e l'altezza della risorsa, quindi lo trasforma nello spazio di coordinate dell'immagine utilizzando CGRectApplyAffineTransform
. È possibile impostare l'origine di square
su un valore diverso da (0,0), poiché spesso si desidera che il riquadro di ritaglio sia centrato lungo l'asse dell'immagine ritagliata, ma lo lascerò come esercizio per il lettore . :-)
risposta originale:
risposta di Giovanni mi ha fatto la maggior parte del tragitto, ma utilizzando il suo codice mi è stato sempre disteso e immagini schiacciato. Ecco come ho ottenuto un imageView
per visualizzare le miniature quadrate recuperate da PHImageManager.
Innanzitutto, verificare che la proprietà contentMode
per il proprio UIImageView
sia impostata su ScaleAspectFill
. L'impostazione predefinita è ScaleToFill
, che non funziona correttamente per la visualizzazione delle miniature quadrate da PHImageManager
, quindi assicurati di modificarlo se hai istanziato lo UIImageView
nel codice o nello storyboard.
//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;
}];
Specificando PHImageRequestOptionsResizeModeExact
per la resizeMode
non è richiesto, in quanto non vi darà un'immagine ritagliata a meno che non si fornisce anche una normalizedCropRect
, e non deve essere usato qui come non c'è alcun beneficio, ed il suo utilizzo significa che don' t ottenere i benefici di immagini memorizzate nella cache rapidamente restituite.
Il UIImage
restituiti nel result
saranno le stesse proporzioni come la fonte, ma scalato correttamente per l'utilizzo in un UIImageView
che è impostato per aspetto compilare per visualizzare come un quadrato, quindi se si sta solo la visualizzazione, questo è la strada da percorrere Se hai bisogno di ritagliare l'immagine per la stampa o l'esportazione al di fuori dell'app, questo non è quello che vuoi: guarda l'uso di normalizedCropRect
per quello. (modifica- vedi sotto per esempio di cosa dovrebbe funzionare ...)
Tranne questo anche fare in modo che la si imposta la modalità contenuto del UIImageView per UIViewContentModeScaleAspectFill e che si imposta clipsToBounds = YES dalle seguenti 2 linee:
imageView.contentMode=UIViewContentModeScaleAspectFill;
imageView.clipsToBounds=YES;
Modifica per aggiungi esempio di utilizzo normalizedCropRect
ATTENZIONE - questo non funziona, ma dovrebbe in base al Apple's documentation.
L'approccio definito da Apple è il passaggio di uno CGRect
nello spazio di coordinate dell'immagine, dove l'origine è (0,0) e il massimo è (1,1). Si passa questo rettile nell'oggetto PHImageRequestOptions
, insieme a resizeMode
di PHImageRequestOptionsResizeModeExact
e quindi si dovrebbe recuperare un'immagine ritagliata. Il problema è che non lo fai, ritorna come lo aspect ratio originale e l'immagine completa.
Ho verificato che il ritaglio di ritaglio è stato creato correttamente nello spazio di coordinate dell'immagine e ha seguito l'istruzione per utilizzare PHImageRequestOptionsResizeModeExact
, ma il gestore di risultati verrà comunque passato a un'immagine con le proporzioni originali. Questo sembra essere un bug nel framework e, quando viene risolto, dovrebbe funzionare il seguente codice.
- (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;
}];
}
Tutto quello che posso suggerire è che se avete questo problema, è file a radar con Apple per richiedere che risolvere il problema!
Hi Pavel - ha fatto il mio lavoro risposta per voi? Se è così, ti preghiamo di contrassegnarlo come accettato? –
Grazie per la risposta Josh, ma la vera soluzione che funziona per me è di chiedere pollici con dimensioni 100x100 o più. La tua soluzione è solo una soluzione alternativa agli algoritmi "intelligenti" in PHImageManager, quindi scusami non posso accettarlo. –
Non è una questione di scala per gli schermi retina? Stavo partendo dal presupposto che l'obiettivo fosse un'immagine giusta per un UIImageView di 80 punti quadrati, in cui il codice richiedeva un'immagine da 80 pixel troppo piccola per le scale retiniche - questo potrebbe essere il motivo per cui la richiesta di oltre 100x100 migliora le cose. Quali algoritmi funziona il mio codice? Penso che funzioni correttamente con il framework Photos, e l'ho nella mia app, quindi se funziona contro qualcosa che mi piacerebbe conoscere, dal momento che voglio ottenere il massimo dal framework. Se si dispone di una soluzione migliore, è consigliabile rispondere alla propria domanda :) –