2012-02-29 14 views
24

vorrei comprimere le immagini (biblioteca fotocamera/foto) e poi inviarlo al server. So che posso comprimere in base all'altezza e alla larghezza, ma vorrei comprimere le immagini in base alle dimensioni solo a una dimensione fissa (200 KB) e mantenere l'altezza e la larghezza originali. Il fattore di scala in JPEGRepresentation non rappresenta la dimensione e solo la qualità di compressione. Come posso ottenerlo (comprimere a una dimensione fissa) senza utilizzare alcuna libreria di terze parti? Grazie per l'aiuto.compressione delle immagini in base alle dimensioni - iPhone SDK

+0

Non v'è alcuna API per esso nel SDK. Come hai scoperto, puoi ridimensionare per risoluzione o per qualità. Abbiamo avuto lo stesso problema e alla fine abbiamo deciso di ridimensionare la visualizzazione dello schermo e di comprimerla dell'85%, il che riduce drasticamente le dimensioni del file, ma offre comunque un'ottima qualità dell'immagine. –

risposta

62

Ecco qualche esempio di codice che tenterà di comprimere l'immagine per voi in modo che non superi né una compressione massima o la dimensione massima del file

CGFloat compression = 0.9f; 
CGFloat maxCompression = 0.1f; 
int maxFileSize = 250*1024; 

NSData *imageData = UIImageJPEGRepresentation(yourImage, compression); 

while ([imageData length] > maxFileSize && compression > maxCompression) 
{ 
    compression -= 0.1; 
    imageData = UIImageJPEGRepresentation(yourImage, compression); 
} 
+2

Il codice scritto sopra funziona alla grande :). Ma voglio che la mia immagine comprima fino a 20 kb, ho provato a giocare con il tuo codice. Ma solo in grado di ottenere la dimensione di circa 200 kb, puoi guidarmi come posso ottenere 20 kb. –

+0

@DeepK Ciò che sopra la soluzione fa è comprimere l'immagine originale. La compressione massima potrebbe non ottenere la soluzione prevista. Quindi creare l'immagine dai dati compressi e quindi comprimere nuovamente l'immagine fino ad ottenere ciò che si desidera. solo un'idea. – CodetrixStudio

+0

@Codetrix Grazie per aver suggerito la soluzione. –

3

Un modo per farlo è comprimere nuovamente il file in un ciclo, finché non si trova la dimensione desiderata. Puoi innanzitutto trovare altezza e larghezza, e indovinare il fattore di compressione (immagine più grande più compressione), quindi dopo averlo compresso, controllare le dimensioni e dividere nuovamente la differenza.

So che questo non è super efficiente, ma non credo che ci sia una singola chiamata per ottenere un'immagine di una dimensione specifica.

1

Qui, JPEGRepresentation è la memoria abbastanza lunga e se usiamo in Loop quindi è un consumo di memoria estremamente elevato. Quindi utilizzare sotto il codice & ImageSize non sarà più di 200 KB.

UIImage* newImage = [self captureView:yourUIView]; 


- (UIImage*)captureView:(UIView *)view { 
CGRect rect = view.bounds; 
UIGraphicsBeginImageContext(rect.size); 
CGContextRef context = UIGraphicsGetCurrentContext(); 

[view.layer renderInContext:context]; 
UIImage* img = [UIImage alloc]init]; 
img = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
NSLog(@"img=%@",img); 
return img; 
} 
-1
- (UIImage *)resizeImageToSize:(CGSize)targetSize 
{ 
    UIImage *sourceImage = captureImage; 
    UIImage *newImage = nil; 

    CGSize imageSize = sourceImage.size; 
    CGFloat width = imageSize.width; 
    CGFloat height = imageSize.height; 

    CGFloat targetWidth = targetSize.width; 
    CGFloat targetHeight = targetSize.height; 

    CGFloat scaleFactor = 0.0; 
    CGFloat scaledWidth = targetWidth; 
    CGFloat scaledHeight = targetHeight; 

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0); 

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) { 

     CGFloat widthFactor = targetWidth/width; 
     CGFloat heightFactor = targetHeight/height; 

     if (widthFactor < heightFactor) 
      scaleFactor = widthFactor; 
     else 
      scaleFactor = heightFactor; 

     scaledWidth = width * scaleFactor; 
     scaledHeight = height * scaleFactor; 

     // make image center aligned 
     if (widthFactor < heightFactor) 
     { 
      thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
     } 
     else if (widthFactor > heightFactor) 
     { 
      thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; 
     } 
    } 

    UIGraphicsBeginImageContext(targetSize); 
    CGRect thumbnailRect = CGRectZero; 
    thumbnailRect.origin = thumbnailPoint; 
    thumbnailRect.size.width = scaledWidth; 
    thumbnailRect.size.height = scaledHeight; 

    [sourceImage drawInRect:thumbnailRect]; 
    newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    if(newImage == nil) 
     NSLog(@"could not scale image"); 

    return newImage ; 
} 
+0

La domanda sta chiedendo specificamente per _file size_, non le dimensioni dell'immagine – bengoesboom

0

Dopo aver fatto alcuni test, sono stato in grado di trovare A relationship between image size and compression value. Poiché questa relazione è lineare per tutti i valori in cui la compressione è inferiore a 1, ho creato un algoritmo per provare a comprimere sempre le immagini su un determinato valore.

//Use 0.99 because at 1, the relationship between the compression and the file size is not linear 
NSData *image = UIImageJPEGRepresentation(currentImage, 0.99); 
float maxFileSize = MAX_IMAGE_SIZE * 1024; 

//If the image is bigger than the max file size, try to bring it down to the max file size 
if ([image length] > maxFileSize) { 
    image = UIImageJPEGRepresentation(currentImage, maxFileSize/[image length]); 
} 
+2

Questa risposta è non corretto e fuorviante. Si prega di prendere in considerazione la rimozione – ikbal

0

ho preso la risposta di @kgutteridge e fece una soluzione simile per Swift 3.0 utilizzando ricorsiva:

extension UIImage { 
    static func compress(image: UIImage, maxFileSize: Int, compression: CGFloat = 1.0, maxCompression: CGFloat = 0.4) -> Data? { 

     if let data = UIImageJPEGRepresentation(image, compression) { 

      let bcf = ByteCountFormatter() 
      bcf.allowedUnits = [.useMB] // optional: restricts the units to MB only 
      bcf.countStyle = .file 
      let string = bcf.string(fromByteCount: Int64(data.count)) 
      print("Data size is: \(string)") 

      if data.count > (maxFileSize * 1024 * 1024) && (compression > maxCompression) { 
       let newCompression = compression - 0.1 
       let compressedData = self.compress(image: image, maxFileSize: maxFileSize, compression: newCompression, maxCompression: maxCompression) 
       return compressedData 
      } 

      return data 
     } 

     return nil 
    } 
}