web-dev-qa-db-ja.com

サイズによる画像圧縮-iPhone SDK

画像(カメラ/写真ライブラリ)を圧縮してサーバーに送信したいのですが。高さと幅で圧縮できることはわかっていますが、画像をサイズで固定サイズ(200 KB)にのみ圧縮し、元の高さと幅を保持したいと考えています。 JPEGRepresentationの倍率は、サイズではなく圧縮品質のみを表します。サードパーティのライブラリを使用せずにこれをどのように達成できます(固定サイズに圧縮)?助けてくれてありがとう。

25
DonDyck

最大圧縮または最大ファイルサイズのいずれかを超えないように画像を圧縮しようとするいくつかのサンプルコードを以下に示します。

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

これを行う1つの方法は、目的のサイズが見つかるまで、ファイルをループで再圧縮することです。最初に高さと幅を見つけて、圧縮係数を推測し(より大きな画像のより多くの圧縮)、それを圧縮した後、サイズを確認し、違いを再度分割します。

これは非常に効率的ではないことを知っていますが、特定のサイズの画像を取得するための呼び出しが1回だけであるとは思いません。

3
nycynik

私は@kgutteridgeの答えを受け取り、再帰を使用してSwift 3.に対して同様のソリューションを作成しました:

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
Mindhavok

ここで、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;
}
1
krunal

スウィフト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
Winter

いくつかのテストを行った後、 画像サイズと圧縮値の関係 を見つけることができました。この関係は、圧縮が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
Banky Adebajo