ios compresses pictures

Keywords: less

https://segmentfault.com/q/1010000000701850


I use this function to compress pictures.

NSData *fData = UIImageJPEGRepresentation(self.photo, 1.0);

So, the picture is 7MB. If the compression level is 0.5, for example:

NSData *fData = UIImageJPEGRepresentation(self.photo, 0.5);

After image compression, the size is about 1MB. Now the problem arises.

If the compression level of a picture is 0.5, it will not be 0.5 times the original size. I figured it out, it's about 0.14. So the compression level doesn't seem to be related to this size.

For example, I have a 500KB picture, 0.5 compression level. The size may be just over 100 KB. It's just right for me. But if the size of 7MB is the same as above, according to the compression rate, it's 1MB. So when the picture is big, it's small. For users, the experience must be poor.

I want to compress the image dynamically, so that no matter how big the image is without wifi, the maximum size after compression is 200 KB. With wifi, the maximum compression size is 700KB.

Are there any better algorithms? Or open source functions.

--------------------------

Stick a correlation function

//Pictures are compressed to a specified size
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
    UIImage *sourceImage = self;
    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; // scale to fit height
        else
        scaleFactor = heightFactor; // scale to fit width
        scaledWidth= width * scaleFactor;
        scaledHeight = height * scaleFactor;
        
        // center the image
        if (widthFactor > heightFactor)
        {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        }
        else if (widthFactor < heightFactor)
        {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }
    
    UIGraphicsBeginImageContext(targetSize); // this will crop
    
    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width= scaledWidth;
    thumbnailRect.size.height = scaledHeight;
    
    [sourceImage drawInRect:thumbnailRect];
    
    newImage = UIGraphicsGetImageFromCurrentImageContext();
    if(newImage == nil)
    NSLog(@"could not scale image");
    
    //pop the context to get back to the default
    UIGraphicsEndImageContext();
    return newImage;
}

The answer is helpful and valuable to people. 1 The answer is not helpful. It's the wrong answer.


The second parameter is the compression coefficient. Its setting does not guarantee the size of the image, because the size of the compressed image is also related to the content of the image. For example, if the color of your image is similar, the size of the compressed image will be smaller. Do you care about WiFi compression? If you need to upload, you can compress two formats of pictures, high quality and low quality pictures, upload high quality pictures with wifi, upload low quality pictures without wifi?


The answer is helpful and valuable to people. 1 The answer is not helpful. It's the wrong answer.

UIImageJPEGRepresentation(self.photo, 0.5);
For each image compression, in fact, there is a minimum value, and no matter how small the compression coefficient is, it will not help.
If it's still too big, you can only cut the picture.

- (NSData *)imageWithImage:(UIImage*)image
          scaledToSize:(CGSize)newSize;
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return UIImageJPEGRepresentation(newImage, 0.8);
}

You can make a for loop and keep approaching the size you want.


The answer is helpful and valuable to people. 1 The answer is not helpful. It's the wrong answer.
- (UIImage *)compressImage:(UIImage *)image toMaxFileSize:(NSInteger)maxFileSize {
    CGFloat compression = 0.9f;
    CGFloat maxCompression = 0.1f;
    NSData *imageData = UIImageJPEGRepresentation(image, compression);
    while ([imageData length] > maxFileSize && compression > maxCompression) {
        compression -= 0.1;
        imageData = UIImageJPEGRepresentation(image, compression);
    }
    
    UIImage *compressedImage = [UIImage imageWithData:imageData];
    return compressedImage;
}

Picture compression is actually two concepts.
1. If the volume of the "pressed" file becomes smaller, but the number of pixels remains unchanged and the length and width of the file remain unchanged, the quality may decrease.
2. The size of the "shrink" file decreases, that is, the number of pixels decreases. As the length and width of the file become smaller, the volume of the file will also decrease.

This UI Image JPEG Representation (image, 0.0) is a function of 1. This [sourceImage drawInRect:CGRectMake(0,0,targetWidth, targetHeight)] is a function of 2.

So, you have to use the two together to meet the needs, or you blindly use 1, resulting in blurred pictures, but the size is still very large.



The answer is helpful and valuable to people. 0 The answer is not helpful. It's the wrong answer.

I have a picture, maybe 14M or more, I want to compress it to less than 500K, UI Image JPEG Representation (image, 0.0), even if the compression coefficient is set to the minimum, it is still larger than 500K after compression; then what method can compress any size of picture to the specified byte size, ignoring the requirement of image clarity? The landlord did not solve this problem, solve it!



// Pictures are compressed to a specified size

  • (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
    {
    UIImage *sourceImage = self;
    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; // scale to fit height
       else
       scaleFactor = heightFactor; // scale to fit width
       scaledWidth= width * scaleFactor;
       scaledHeight = height * scaleFactor;
       
       // center the image
       if (widthFactor > heightFactor)
       {
           thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
       }
       else if (widthFactor < heightFactor)
       {
           thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
       }

    }

    UIGraphicsBeginImageContext(targetSize); // this will crop

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width= scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

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

    //pop the context to get back to the default
    UIGraphicsEndImageContext();
    return newImage;
    }

— Milu · 25 December 2015

Comments
The answer is helpful and valuable to people. 0 The answer is not helpful. It's the wrong answer.
-(UIImage *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth
{
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = defineWidth;
    CGFloat targetHeight = (targetWidth / width) * height;
    UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight));
    [sourceImage drawInRect:CGRectMake(0,0,targetWidth,  targetHeight)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}


The answer is helpful and valuable to people. 0 The answer is not helpful. It's the wrong answer.

Combine image quality with image size reduction:


/**
 Press picture quality

 @param image image
 @return Data
 */
+ (NSData *)zipImageWithImage:(UIImage *)image
{
    if (!image) {
        return nil;
    }
    CGFloat maxFileSize = 32*1024;
    CGFloat compression = 0.9f;
    NSData *compressedData = UIImageJPEGRepresentation(image, compression);
    while ([compressedData length] > maxFileSize) {
        compression *= 0.9;
        compressedData = UIImageJPEGRepresentation([[self class] compressImage:image newWidth:image.size.width*compression], compression);
    }
    return compressedData;
}

/**
 *  Scale this picture in equal proportion
 *
 *  @param newImageWidth The width of the zoomed image in pixels
 *
 *  @return self-->(image)
 */
+ (UIImage *)compressImage:(UIImage *)image newWidth:(CGFloat)newImageWidth
{
    if (!image) return nil;
    float imageWidth = image.size.width;
    float imageHeight = image.size.height;
    float width = newImageWidth;
    float height = image.size.height/(image.size.width/width);
    
    float widthScale = imageWidth /width;
    float heightScale = imageHeight /height;
    
    // Create a bitmap context
    // And set it to the context currently in use
    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    
    if (widthScale > heightScale) {
        [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)];
    }
    else {
        [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)];
    }
    
    // Create a resized image from the current context
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    // Get the current context out of the stack
    UIGraphicsEndImageContext();
    
    return newImage;
    
}

Posted by stenk on Sun, 23 Jun 2019 15:28:15 -0700