2014-09-24 15 views
18

Qualcuno ha idea di come prelevare i pollici quadrati da PHImageManager? L'opzione PHImageContentModeAspectFill non ha alcun effetto.Come recuperare le miniature quadrate da PHImageManager?

[[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

Hi Pavel - ha fatto il mio lavoro risposta per voi? Se è così, ti preghiamo di contrassegnarlo come accettato? –

+0

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. –

+0

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 :) –

risposta

1

per ottenere una quadratura esatta, si dovrà indicare che si desidera una dimensione esatta per il passaggio delle opzioni, in questo modo:

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

Per me, questo comporta che alcune immagini vengano schiacciate o allungate. –

+0

Questo non funziona se si richiedono immagini di piccole dimensioni. –

+0

Solo perché chiedi la dimensione esatta non significa che la modalità di contenuto sia ignorata. In questo caso la modalità di contenuto è ancora di aspetto e quindi si otterranno immagini non quadrate (supponendo che l'originale non sia già quadrato). – EarlyRiser

19

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!

+3

Penso che dovresti usare '[UIScreen mainScreen] .scale' invece di' 2'.iPhone 6 Plus, @ 3x, e tutto il resto. – DCMaxxx

+1

Grazie DCMaxxx, buon punto. –

+0

Estremamente utile; una cosa di cui diffidare, se si sta facendo questo utilizzando una vista di raccolta, c'è la possibilità di creare un'estensione 'UICollectionViewCell' che avvolge 'UIImageView'. Uno dei problemi che stavo facendo era che stavo facendo 'cell.contentMode =' invece di 'cell.imageView.contentMode =' (questo sta usando la risposta originale) – 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

Utilizzare 'result.imageOrientation' anziché l'orientamento codificato per evitare problemi. – Andy

+0

ha funzionato bene grazie. – Rikco

0

Questo raffinato sta lavorando per me:

__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; 

    }]; 
Problemi correlati