web-dev-qa-db-fra.com

compression d'image par taille - SDK iPhone

Je voudrais compresser des images (photothèque/photothèque) puis les envoyer au serveur. Je sais que je peux compresser en hauteur et en largeur, mais je voudrais compresser les images en taille unique (200 Ko) uniquement et conserver la hauteur et la largeur d'origine. Le facteur d'échelle dans JPEGRepresentation ne représente pas la taille et uniquement la qualité de la compression. Comment puis-je y parvenir (compresser à une taille fixe) sans utiliser de bibliothèque tierce? Merci pour toute aide.

24
DonDyck

Voici un exemple de code qui tentera de compresser une image pour qu'elle ne dépasse pas une compression maximale ou une taille de fichier maximale

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);
}
63
kgutteridge

Une façon de le faire est de recompresser le fichier en boucle, jusqu'à ce que vous trouviez la taille souhaitée. Vous pouvez d'abord trouver la hauteur et la largeur, puis deviner le facteur de compression (plus grande image plus de compression), puis après l'avoir compressé, vérifier la taille et fractionner à nouveau la différence.

Je sais que ce n'est pas très efficace, mais je ne crois pas qu'il y ait un seul appel pour obtenir une image d'une taille spécifique.

3
nycynik

Ici, JPEGRepresentation consomme beaucoup de mémoire et si nous utilisons Loop, la consommation de mémoire est extrêmement élevée. Donc, utilisez ci-dessous le code & ImageSize ne dépassera pas 200 Ko.

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
krunal

J'ai pris la réponse de @kgutteridge et fait une solution similaire pour Swift 3.0 en utilisant récursif:

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
    }
}
0
Mindhavok

Après avoir fait quelques tests, j'ai pu trouver Une relation entre la taille de l'image et la valeur de compression . Comme cette relation est linéaire pour toutes les valeurs où la compression est inférieure à 1, j'ai créé un algorithme pour essayer de toujours compresser les images à une certaine valeur. 

//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]);
}
0
Banky Adebajo