iPhone SDK ile bir görüntü boyutu / boyutlandırmak optimize etmek kolay yolu nedir?

oy
107

Benim uygulama ağdan görüntü dosyaları kümesi indirirken ve yerel iPhone diske bunları biriktiriyor. Bu görüntülerin bazıları boyutunda oldukça büyük (örneğin, daha büyük 500 piksel genişlikleri). IPhone bile orijinal boyutunda resim göstermek için yeterince büyük bir ekrana sahip olmadığından, ben uzay / performansa kaydetmek için biraz daha küçük bir şeye görüntü boyutlandırma planlıyorum.

Ayrıca, bu resimleri bazıları JPEG ve onlar her zamanki% 60 kalite ayarı olarak kaydedilmez.

Nasıl iPhone SDK ile bir resim yeniden boyutlandırabilirsiniz ve nasıl JPEG görüntünün kalitesi ayarını değiştirebilirsiniz?

Oluştur 04/03/2009 saat 20:42
kaynak kullanıcı
Diğer dillerde...                            


18 cevaplar

oy
240

Birkaç öneri yanıtları olarak verilmektedir Bu soruya . Ben açıklanan tekniği önerdi bu yazı ilgili kodla:

+ (UIImage*)imageWithImage:(UIImage*)image 
               scaledToSize:(CGSize)newSize;
{
   UIGraphicsBeginImageContext( newSize );
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
}

o biçimde için optimize edilmiş olduğundan Bildiğim kadarıyla görüntünün depolama gibi, iPhone ile kullanmak için en hızlı görüntü formatı PNG vardır. Eğer JPEG olarak bu görüntüleri depolamak istiyorsanız Ancak, sizin UIImage almak ve aşağıdakileri yapabilirsiniz:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Bu% 60 kalite ayarında bir JPEG görüntüsü için ham bayt içeren bir NSData örneğini oluşturur. Bu NSData örneğinin içerikleri daha sonra diske yazılı veya bellekte önbelleğe alınabilir.

Cevap 05/03/2009 saat 03:20
kaynak kullanıcı

oy
64

boyutlarını en kolay ve en basit yolu bu olacaktır

float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;

if(imgRatio!=maxRatio){
    if(imgRatio < maxRatio){
        imgRatio = 480.0 / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = 480.0;
    }
    else{
        imgRatio = 320.0 / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = 320.0;
    }
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Cevap 05/03/2009 saat 05:35
kaynak kullanıcı

oy
23

Yukarıdaki yöntemler küçük resimler için iyi çalışabilir, ancak çok büyük bir görüntüyü yeniden boyutlandırmak çalıştığınızda, hızlı bellek tükendi ve uygulamayı çökecek. Bir çok daha iyi bir yolu kullanmaktır CGImageSourceCreateThumbnailAtIndextamamen ilk Çözümün olmadan görüntüyü yeniden boyutlandırmak için.

Eğer yeniden boyutlandırmak istediğiniz resmin yolunu varsa, bu kullanabilirsiniz:

- (void)resizeImageAtPath:(NSString *)imagePath {
    // Create the image source (from path)
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);

    // To create image source from UIImage, use this
    // NSData* pngData =  UIImagePNGRepresentation(image);
    // CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);

    // Create thumbnail options
    CFDictionaryRef options = (__bridge CFDictionaryRef) @{
            (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
            (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
            (id) kCGImageSourceThumbnailMaxPixelSize : @(640)
    };
    // Generate the thumbnail
    CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); 
    CFRelease(src);
    // Write the thumbnail at path
    CGImageWriteToFile(thumbnail, imagePath);
}

Daha fazla detay burada .

Cevap 01/09/2014 saat 12:03
kaynak kullanıcı

oy
18

En iyi yolu bu yöntemi kullanmak (imgage zorlamadan yani) Aspect ratio kaybetmeden görüntüleri küçültmek için:

//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {

    float width = newSize.width;
    float height = newSize.height;

    UIGraphicsBeginImageContext(newSize);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = image.size.width / width;
    float heightRatio = image.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = image.size.width / divisor;
    height = image.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.origin.y = offset;
    }
    else {
        rect.origin.x = -offset;
    }

    [image drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return smallImage;

}

Eğer proje boyunca kullanabilir ve böylece gibi erişebilmesi için Utility sınıfına bu yöntemi ekleyin:

xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];

Bu yöntem, en boy oranı korunarak ölçekleme ilgilenir. Ayrıca, küçültülmüş resim yüksekliği (ya da tersi) çok daha genişliği durumunda bu görüntüye girintiler ekler.

Cevap 03/05/2013 saat 09:40
kaynak kullanıcı

oy
7

Sunucuya üzerinde kontrol varsa, şiddetle birlikte görüntüleri sunucu tarafı yeniden boyutlandırma öneriyoruz ImageMagik . Bant genişliği, pil ve bellek - büyük resimler indirilmesi ve telefonda bunları yeniden boyutlandırma birçok değerli kaynakların israfıdır. Tüm bunlar telefonlarda kıt.

Cevap 05/03/2009 saat 10:23
kaynak kullanıcı

oy
5

Ben Swift görüntü ölçeklendirme nihai çözüm geliştirdi.

Sen doldurmak için görüntüyü yeniden boyutlandırmak için kullanabilirsiniz, boy doldurmak veya boy belirtilen boyutuna uyacak.

Sen merkezi ya da dört kenarları ve dört köşesinden herhangi birinin imajını hizalayabilirsiniz.

Ve ayrıca orijinal görüntü ve hedef büyüklüğü boy oranları eşit değilse eklenir ekstra alan düzeltme yapabilirsiniz.

enum UIImageAlignment {
    case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}

enum UIImageScaleMode {
    case Fill,
    AspectFill,
    AspectFit(UIImageAlignment)
}

extension UIImage {
    func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
        let preWidthScale = width.map { $0 / size.width }
        let preHeightScale = height.map { $0 / size.height }
        var widthScale = preWidthScale ?? preHeightScale ?? 1
        var heightScale = preHeightScale ?? widthScale
        switch scaleMode {
        case .AspectFit(_):
            let scale = min(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        case .AspectFill:
            let scale = max(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        default:
            break
        }
        let newWidth = size.width * widthScale
        let newHeight = size.height * heightScale
        let canvasWidth = trim ? newWidth : (width ?? newWidth)
        let canvasHeight = trim ? newHeight : (height ?? newHeight)
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)

        var originX: CGFloat = 0
        var originY: CGFloat = 0
        switch scaleMode {
        case .AspectFit(let alignment):
            switch alignment {
            case .Center:
                originX = (canvasWidth - newWidth) / 2
                originY = (canvasHeight - newHeight) / 2
            case .Top:
                originX = (canvasWidth - newWidth) / 2
            case .Left:
                originY = (canvasHeight - newHeight) / 2
            case .Bottom:
                originX = (canvasWidth - newWidth) / 2
                originY = canvasHeight - newHeight
            case .Right:
                originX = canvasWidth - newWidth
                originY = (canvasHeight - newHeight) / 2
            case .TopLeft:
                break
            case .TopRight:
                originX = canvasWidth - newWidth
            case .BottomLeft:
                originY = canvasHeight - newHeight
            case .BottomRight:
                originX = canvasWidth - newWidth
                originY = canvasHeight - newHeight
            }
        default:
            break
        }
        self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Aşağıda bu çözümü uygulayarak örnekleri vardır.

Gri dikdörtgen hedef site görüntü olarak yeniden ayarlanacak olduğunu. Açık mavi dikdörtgen Mavi çevreler resmi (o yönü korumadan ölçeklendirildiğini görmesi kolay olduğu için çevreler kullanılır) 'dir. Işık turuncu renk geçtiğiniz takdirde kesilmiş olan alanları işaretler trim: true.

Aspect sığacak öncesi ve ölçekleme sonra:

Boy uygun 1 (önce) Boy 1 (önce), uygun

Bir başka örnek, özelliği geçme :

Boy uygun 2 (daha önce) Boy 2 (sonra) uygun

Boy uygun üst hizalama:

Boy uyum 3 (daha önce) Özellik 3 (sonra) uygun

En Boy dolgu :

Aspect dolgu (önceki) Boy dolgu (sonra)

Dolgu :

Dolgu (önceki) Dolgu (sonra)

o göstermek için basit ama çözüm de söz konusu olduğu gibi ölçek küçültme için çalışır, çünkü benim örneklerde; yukarı kullandı.

JPEG sıkıştırması için bunu kullanmalısınız:

let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
  // ...
}

Sen benim göz atabilirsiniz özünü Xcode oyun alanına sahip.

Cevap 23/03/2016 saat 13:51
kaynak kullanıcı

oy
3

Swift 3 için, aşağıdaki kod boy oranı tutmak ölçekler. İçeri ImageContext hakkında daha fazla bilgi edinebilirsiniz Apple'ın belgelerinde :

extension UIImage {
    class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
        let scale = newHeight / image.size.height
        let newWidth = image.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

Kullanmak için, çağrı resizeImage()yöntemini:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
Cevap 14/04/2017 saat 03:50
kaynak kullanıcı

oy
2

Gerekli boyutunda ölçeklemek üzere bu kodu kullanabilirsiniz.

+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
    CGSize actSize = image.size;
    float scale = actSize.width/actSize.height;

    if (scale < 1) {
        newSize.height = newSize.width/scale;
    } 
    else {
        newSize.width = newSize.height*scale;
    }

    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}
Cevap 30/09/2015 saat 10:51
kaynak kullanıcı

oy
1
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {
    let scale = newWidth / image.size.width
    let newHeight = CGFloat(200.0)
    UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
    image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}
Cevap 12/04/2018 saat 10:25
kaynak kullanıcı

oy
1

Burada cevapların takım ekleme, ama yerine boyutlardan daha, dosya boyutuna göre boyutlandırır çözüm için gitti.

sizin verilen boyuta ulaşıncaya kadar bu hem resmin boyutlarını ve kalitesini düşürecektir.

func compressTo(toSizeInMB size: Double) -> UIImage? {
    let bytes = size * 1024 * 1024
    let sizeInBytes = Int(bytes)
    var needCompress:Bool = true
    var imgData:Data?
    var compressingValue:CGFloat = 1.0

    while (needCompress) {

        if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {

            if data.count < sizeInBytes || compressingValue < 0.1 {
                needCompress = false
                imgData = data
            } else {
                compressingValue -= 0.1
            }
        }
    }

    if let data = imgData {
        print("Finished with compression value of: \(compressingValue)")
        return UIImage(data: data)
    }
    return nil
}

private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
    let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
    UIGraphicsBeginImageContext(size)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return newImage;
    }
    return nil
}

Kredi büyüklüğü cevap tarafından ölçekleme

Cevap 10/07/2017 saat 11:24
kaynak kullanıcı

oy
0

Size görüntü belge dizinde ise, bu ekleme URL uzantısı:

extension URL {
    func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
        let imageData = try Data(contentsOf: self)
        debugPrint("Image file size before compression: \(imageData.count) bytes")

        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")

        guard let actualImage = UIImage(data: imageData) else { return nil }
        guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
            return nil
        }
        debugPrint("Image file size after compression: \(compressedImageData.count) bytes")

        do {
            try compressedImageData.write(to: compressedURL)
            return compressedURL
        } catch {
            return nil
        }
    }
}

Kullanımı:

guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
    return
}

//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
    return
}

debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")

Not: - Yerel jpg resim yolu ile Değiştir <LocalImagePath.jpg>.

Cevap 18/05/2018 saat 10:02
kaynak kullanıcı

oy
0
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = image.CGImage;

    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);

    CGContextConcatCTM(context, flipVertical);
    CGContextDrawImage(context, newRect, imageRef);

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    CGImageRelease(newImageRef);
    UIGraphicsEndImageContext();

    return newImage;
}
Cevap 03/11/2016 saat 08:37
kaynak kullanıcı

oy
0

Sadece Kakao Swift programcılar için bu soruya cevap istedi. Bu işlev yeni boyutu ile NSImage döndürür. Böyle bu işlevi kullanabilirsiniz.

        let sizeChangedImage = changeImageSize(image, ratio: 2)






 // changes image size

    func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage   {

    // getting the current image size
    let w = image.size.width
    let h = image.size.height

    // calculating new size
    let w_new = w / ratio 
    let h_new = h / ratio 

    // creating size constant
    let newSize = CGSizeMake(w_new ,h_new)

    //creating rect
    let rect  = NSMakeRect(0, 0, w_new, h_new)

    // creating a image context with new size
    let newImage = NSImage.init(size:newSize)



    newImage.lockFocus()

        // drawing image with new size in context
        image.drawInRect(rect)

    newImage.unlockFocus()


    return newImage

}
Cevap 13/07/2016 saat 09:00
kaynak kullanıcı

oy
0

, Benim için çalışmak, bu deneyin

       CGRect rect =CGRectMake (0, 0,1200,900);
       UIGraphicsBeginImageContext( rect.size );
       [image drawInRect:rect];
       UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
       NSData *imageData = UIImagePNGRepresentation(picture1);
       UIImage *img=[UIImage imageWithData:imageData];
      [imageArray addObject:img];
Cevap 18/03/2016 saat 11:48
kaynak kullanıcı

oy
0

Ben oluşturmak için Brads tekniği kullanılarak sona erdi scaleToFitWidthyöntemi UIImage+Extensionso kimseye fayda varsa ...

-(UIImage *)scaleToFitWidth:(CGFloat)width
{
    CGFloat ratio = width / self.size.width;
    CGFloat height = self.size.height * ratio;

    NSLog(@"W:%f H:%f",width,height);

    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    [self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

Sonra her yerde sizin gibi

#import "UIImage+Extensions.h"

UIImage *newImage = [image scaleToFitWidth:100.0f];

Eğer bir içine daha da aşağı bu hareket olabilir belirterek Ayrıca değer UIView+Extensionsbir UIView görüntüleri işlemek istiyorsanız sınıfa

Cevap 15/03/2016 saat 14:49
kaynak kullanıcı

oy
0

Herkes hala iyi bir seçenek arıyor

-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {


    UIImage *sourceImage = image;
    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;

        // center the image


        if (widthFactor < heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        } else if (widthFactor > heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }


    // this is actually the interesting part:

    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 ;

}
Cevap 23/06/2015 saat 07:39
kaynak kullanıcı

oy
0

Retina ekranlarda oluşabilir bir problem görüntünün ölçek ImageCapture'dan tarafından ya da öylesine ayarlanmış olmasıdır. yeniden boyutlandırma fonksiyonları Yukarıdaki değiştirmeyecektir. Bu durumlarda yeniden boyutlandırma düzgün değil çalışacaktır.

Aşağıdaki kodda, ölçek 1 olarak ayarlanır (ölçekli değil) ve döndürülen görüntü beklediğiniz boyutu vardır. Bu yapılır UIGraphicsBeginImageContextWithOptionsçağrı.

-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
    UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
    [theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
Cevap 06/04/2015 saat 10:24
kaynak kullanıcı

oy
-2

Ben DrawInRect yerine bu işlevi kullanarak daha iyi (grafiksel) sonuçları bir görüntüyü yeniden boyutlandırmak için:

- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
    float lScale = pWidth / pImage.size.width;
    CGImageRef cgImage = pImage.CGImage;
    UIImage   *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
                            orientation:UIImageOrientationRight];
    return lResult;
}

En-boy oranı otomatik olarak halledilir

Cevap 01/09/2013 saat 15:46
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more