сжатие изображения по размеру - iPhone SDK - PullRequest
24 голосов
/ 01 марта 2012

Я хочу сжать изображения (камера / библиотека фотографий) и затем отправить их на сервер. Я знаю, что могу сжимать по высоте и ширине, но я бы хотел сжать изображения по размеру только до фиксированного размера (200 КБ) и сохранить исходные высоту и ширину. Масштабный коэффициент в JPEGRepresentation представляет не размер, а только качество сжатия. Как я могу достичь этого (сжать до фиксированного размера) без использования сторонней библиотеки? Спасибо за любую помощь.

Ответы [ 7 ]

63 голосов
/ 01 марта 2012

Вот пример кода, который попытается сжать изображение для вас, чтобы оно не превышало ни максимальное сжатие, ни максимальный размер файла

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);
}
3 голосов
/ 01 марта 2012

Один из способов сделать это - повторно сжать файл в цикле, пока вы не найдете нужный размер.Сначала вы можете найти высоту и ширину и угадать коэффициент сжатия (большее изображение - большее сжатие), а затем после его сжатия проверить размер и снова разделить разницу.

Я знаю, что это не очень эффективно, ноЯ не верю, что для получения изображения определенного размера требуется один вызов.

1 голос
/ 12 апреля 2017

Я взял ответ @kgutteridge и сделал аналогичное решение для Swift 3.0 , используя рекурсив:

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
    }
}
1 голос
/ 12 декабря 2012

Здесь JPEGRepresentation довольно потребляет память, и если мы используем ее в цикле, то она чрезвычайно потребляет память. Поэтому используйте приведенный ниже код и размер изображения не будет превышать 200 КБ.

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;
}
0 голосов
/ 26 апреля 2019

Swift 4:

extension UIImage {
    func compressTo(bytes: Int) -> UIImage {
        var compression: CGFloat = 0.9
        let maxCompression: CGFloat = 0.1
        let maxSize: Int = bytes * 1024

        var imageData = jpegData(compressionQuality: compression)!
        while imageData.count > maxSize && compression > maxCompression {
            compression -= 0.1
            imageData = jpegData(compressionQuality: compression)!
        }

        return UIImage(data: imageData)!
    }
}
0 голосов
/ 22 октября 2015

Проведя несколько тестов, я смог найти Соотношение между размером изображения и значением сжатия . Поскольку это соотношение является линейным для всех значений, где сжатие меньше 1, я создал алгоритм, чтобы всегда пытаться сжать изображения до определенного значения.

//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 голосов
/ 22 ноября 2013
- (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 ;
}
...