2013-07-26 15 views
14

Nella mia app l'utente seleziona un'immagine o scatta una foto usando UIImagePickerViewController. Una volta selezionata l'immagine, voglio visualizzare la sua miniatura su un UIImageView quadrato (90x90).Miniatura quadrata da UIImagePickerViewController image

Sto usando Apple's code per creare una miniatura. Il problema è che la miniatura non è quadrata, la funzione, dopo aver impostato la chiave kCGImageSourceThumbnailMaxPixelSize a 90, sembra solo ridimensionare l'altezza dell'immagine e, per quanto ne so, la chiave kCGImageSourceThumbnailMaxPixelSize dovrebbe essere responsabile dell'impostazione dell'altezza e della larghezza della miniatura.

Ecco un assaggio del mio codice:

- (void)imagePickerController:(UIImagePickerController *)picker 
    didFinishPickingMediaWithInfo:(NSDictionary *)info { 

    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    NSData *imageData = UIImageJPEGRepresentation (image, 0.5); 

    // My image view is 90x90 
    UIImage *thumbImage = MyCreateThumbnailImageFromData(imageData, 90); 

    [myImageView setImage:thumbImage]; 

    if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) { 

     UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 
    } 

    [picker dismissViewControllerAnimated:YES completion:nil]; 
} 

UIImage* MyCreateThumbnailImageFromData (NSData * data, int imageSize) { 

    CGImageRef  myThumbnailImage = NULL; 
    CGImageSourceRef myImageSource; 
    CFDictionaryRef myOptions = NULL; 
    CFStringRef  myKeys[3]; 
    CFTypeRef   myValues[3]; 
    CFNumberRef  thumbnailSize; 

    // Create an image source from NSData; no options. 
    myImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, 
               NULL); 

    // Make sure the image source exists before continuing. 
    if (myImageSource == NULL){ 
     fprintf(stderr, "Image source is NULL."); 
     return NULL; 
    } 

    // Package the integer as a CFNumber object. Using CFTypes allows you 
    // to more easily create the options dictionary later. 
    thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize); 

    // Set up the thumbnail options. 
    myKeys[0] = kCGImageSourceCreateThumbnailWithTransform; 
    myValues[0] = (CFTypeRef)kCFBooleanTrue; 
    myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent; 
    myValues[1] = (CFTypeRef)kCFBooleanTrue; 
    myKeys[2] = kCGImageSourceThumbnailMaxPixelSize; 
    myValues[2] = thumbnailSize; 

    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys, 
            (const void **) myValues, 2, 
            &kCFTypeDictionaryKeyCallBacks, 
            & kCFTypeDictionaryValueCallBacks); 

    // Create the thumbnail image using the specified options. 
    myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource, 
                  0, 
                  myOptions); 

    UIImage* scaled = [UIImage imageWithCGImage:myThumbnailImage]; 

    // Release the options dictionary and the image source 
    // when you no longer need them. 

    CFRelease(thumbnailSize); 
    CFRelease(myOptions); 
    CFRelease(myImageSource); 

    // Make sure the thumbnail image exists before continuing. 
    if (myThumbnailImage == NULL) { 
     fprintf(stderr, "Thumbnail image not created from image source."); 
     return NULL; 
    } 
    return scaled; 
} 

E questo come mio punto di vista dell'immagine è istanziato:

myImageView = [[UIImageView alloc] init]; 
imageView.contentMode = UIViewContentModeScaleAspectFit; 

CGRect rect = imageView.frame; 
rect.size.height = 90; 
rect.size.width = 90; 

imageView.frame = rect; 
[imageView setUserInteractionEnabled:YES]; 

Se non metto imageView.contentMode = UIViewContentModeScaleAspectFit; sarà distorto la miniatura, dal momento che è solo una versione della mia immagine originale con altezza di 90 pixel.

Quindi, perché la mia miniatura non è al quadrato?

+0

Nota - un utente Meta con nessuna conoscenza di iOS modificato via un po 'di codice super-utile dalla risposta di Clever in basso. se in realtà stai programmando e vuoi una risposta utile e vuoi veramente usare le idee (spettacolari) di Clever, fai clic sul pulsante "modificato" in basso, visualizzerai la cronologia e puoi tagliare, incollare e inviare all'app store:) – Fattie

+0

@JoeBlow Non vedo alcun codice rimosso nella [modifica cronologia] (http://stackoverflow.com/posts/17884863/revisions) della risposta di Clever Error. – cpburnz

+0

http://stackoverflow.com/posts/17884863/revisions rev "5" – Fattie

risposta

52

La cosa più semplice da fare sarebbe impostare contentMode sul proprio imageView come UIViewContentModeScaleAspectFill. Tuttavia, questo potrebbe non essere l'ideale dato che manterrebbe l'intera immagine in memoria.

Ecco un codice che uso per ridimensionare le immagini.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size 
{ 
    UIGraphicsBeginImageContextWithOptions(size, NO, 0); 
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 

Questa versione manterrà l'immagine distorta se la dimensione non è dello stesso formato dell'immagine.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToFillSize:(CGSize)size 
{ 
    CGFloat scale = MAX(size.width/image.size.width, size.height/image.size.height); 
    CGFloat width = image.size.width * scale; 
    CGFloat height = image.size.height * scale; 
    CGRect imageRect = CGRectMake((size.width - width)/2.0f, 
            (size.height - height)/2.0f, 
            width, 
            height); 

    UIGraphicsBeginImageContextWithOptions(size, NO, 0); 
    [image drawInRect:imageRect]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 

Spesso si desidera solo il piano quadrato di un'immagine (invece che al centro). E vuoi che l'immagine finale abbia una certa dimensione, ad esempio 128x128, come nell'esempio qui sotto.

- (UIImage *)squareAndSmall // as a category (so, 'self' is the input image) 
{ 
    // fromCleverError's original 
    // http://stackoverflow.com/questions/17884555 
    CGSize finalsize = CGSizeMake(128,128); 

    CGFloat scale = MAX(
     finalsize.width/self.size.width, 
     finalsize.height/self.size.height); 
    CGFloat width = self.size.width * scale; 
    CGFloat height = self.size.height * scale; 

    CGRect rr = CGRectMake(0, 0, width, height); 

    UIGraphicsBeginImageContextWithOptions(finalsize, NO, 0); 
    [self drawInRect:rr]; 
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 
    return newImage; 
} 
+0

Questo approccio distorce l'immagine, ho già provato qualcosa di simile. – douglasd3

+2

Ho aggiunto una versione che non dovrebbe distorcere l'immagine. –

+0

Ora non distorce, ma l'immagine di anteprima non è quadrata, cioè, è 90x90 ma l'immagine non è stata ridimensionata per riempire il quadrato. – douglasd3

6

Ecco un link è possibile fare riferimento a:

1) UIImage+Resize

2) UIImage+ProportionalFill

Qui è possibile ridimensionare la vista e anche aggiungere riempimento proporzionale in modo che in proporzione il rapporto di aspetto e di altri funziona come ritaglio, scala, ecc.

È possibile utilizzare il metodo -(UIImage*)resizedImageToSize:(CGSize*)size sotto il collegamento di riferimento UIImmagine + Ridimensiona sopra solo per ridimensionare l'immagine.

Spero che questo ti aiuti.

Fatemi sapere se volete ulteriore aiuto.

+0

Il secondo collegamento è stato davvero utile! Ancora non so quale fosse il problema, ma ora sta funzionando e mi farà risparmiare molto tempo. Grazie! – douglasd3

+1

@ douglasd3: il secondo link è molto utile per molte funzionalità come il ritaglio e il ridimensionamento. –

0

Un altro modo per fare questo - ha funzionato in un problema, l'altro giorno e le altre persone potrebbero avere lo stesso problema quando si utilizza il apple sample code che è meglio per immagini di grandi dimensioni.

Come accennato nella risposta accettata, questo ha il problema di caricare l'intera immagine in memoria e iOS può uccidere la tua app se è troppo grande.CGImageSourceCreateThumbnailAtIndex nel codice di esempio di Apple è più efficiente, tuttavia nell'esempio c'è un bug. Il terzo parametro in CFDictionaryCreate è "numValues" da copiare. Ha bisogno di essere non 2.

myOptions = CFDictionaryCreate(NULL, (const void **) myKeys, 
           (const void **) myValues, 
           3, //Changed to 3 
           &kCFTypeDictionaryKeyCallBacks, 
           & kCFTypeDictionaryValueCallBacks); 
+1

ok, ma ho provato questo metodo rispetto alla risposta di accettazione usando Quartz e la risposta accettata è 15 volte più veloce, specialmente se hai già il 'UIImage', perché devi convertirlo in' CFData' in modo da poter usare 'CGImageSourceCreateThumbnailAtIndex' . L'intero processo è 15 volte più lento. – SpaceDog

3

versione 2.x Swift della risposta di Clever errore precedente:

// Define thumbnail size 
    let size = CGSize(width: 100, height: 100) 

    // Define rect for thumbnail 
    let scale = max(size.width/image.size.width, size.height/image.size.height) 
    let width = image.size.width * scale 
    let height = image.size.height * scale 
    let x = (size.width - width)/CGFloat(2) 
    let y = (size.height - height)/CGFloat(2) 
    let thumbnailRect = CGRectMake(x, y, width, height) 

    // Generate thumbnail from image 
    UIGraphicsBeginImageContextWithOptions(size, false, 0) 
    image.drawInRect(thumbnailRect) 
    let thumbnail = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
+1

Per Swift 3, modifica l'assegnazione let thumbnailRect a CGRect (x: x, y: y, larghezza: larghezza, altezza: altezza) –

Problemi correlati