【问题标题】:image compression by size - iPhone SDK按大小压缩图像 - iPhone SDK
【发布时间】:2012-03-19 09:30:50
【问题描述】:

我想压缩图像(相机/照片库),然后将其发送到服务器。我知道我可以按高度和宽度进行压缩,但我只想按大小将图像压缩到固定大小(200 KB)并保持原始高度和宽度。 JPEGRepresentation 中的比例因子不代表大小,只代表压缩质量。如何在不使用任何第三方库的情况下实现这一点(压缩到固定大小)? 感谢您的帮助。

【问题讨论】:

  • SDK 中没有它的 API。正如您所发现的,您可以按分辨率或质量调整大小。我们遇到了同样的问题,最终我们决定根据屏幕显示调整大小并压缩 85%,这大大减小了文件大小,但提供了非常好的图像质量。

标签: iphone ios api uiimagejpegrepresentation


【解决方案1】:

这里有一些示例代码会尝试为您压缩图像,使其不超过最大压缩或最大文件大小

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

【讨论】:

  • 上面写的代码效果很好:)。但我希望我的图像压缩到 20 kb,我尝试使用你的代码。但只能得到 200 kb 左右的大小,你能指导我如何达到 20 kb。
  • @DeepK 上述解决方案所做的是压缩原始图像。最大压缩可能无法为您提供预期的解决方案。所以从压缩数据创建图像,然后再次压缩图像,直到你得到你想要的。只是一个想法。
  • @Codetrix 感谢您提出解决方案。
  • @kgutteidge 这段代码是否可以通过转换为 swift 来工作......我在 while 条件下遇到错误......这就是我想问你的原因
【解决方案2】:

一种方法是循环重新压缩文件,直到找到所需的大小。您可以先找到高度和宽度,然后猜测压缩系数(图像越大压缩越多),然后在压缩后检查大小,然后再次拆分差异。

我知道这不是超级高效,但我不相信有一个单一的调用来实现特定大小的图像。

【讨论】:

    【解决方案3】:

    这里,JPEGRepresentation 非常消耗内存,如果我们在 Loop 中使用,那么它的内存消耗非常高。所以使用下面的代码 & ImageSize 不会超过 200KB。

    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;
    }
    

    【讨论】:

      【解决方案4】:

      我接受了@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
          }
      }
      

      【讨论】:

        【解决方案5】:

        斯威夫特 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)!
            }
        }
        

        【讨论】:

        • 如此繁重的任务使用while循环是不安全的!
        【解决方案6】:

        做了一些测试后,我能够找到 A relationship between image size and compression value。由于这种关系对于压缩小于 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]);
        }
        

        【讨论】:

        • 此答案不正确且具有误导性。请考虑删除它
        【解决方案7】:
        - (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 ;
        }
        

        【讨论】:

        • 问题是专门针对文件大小,而不是图像尺寸
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-29
        • 2013-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多