วิธีปรับขนาด / ปรับขนาดภาพอย่างง่ายดายด้วย iOS


114

แอปพลิเคชันของฉันกำลังดาวน์โหลดชุดไฟล์ภาพจากเครือข่ายและบันทึกลงในดิสก์ iPhone ในเครื่อง ภาพเหล่านั้นบางภาพมีขนาดค่อนข้างใหญ่ (เช่นความกว้างมากกว่า 500 พิกเซล) เนื่องจาก iPhone ไม่มีจอแสดงผลที่ใหญ่พอที่จะแสดงภาพในขนาดดั้งเดิมฉันจึงวางแผนที่จะปรับขนาดภาพให้เล็กลงเล็กน้อยเพื่อประหยัดพื้นที่ / ประสิทธิภาพ

นอกจากนี้ภาพเหล่านั้นบางภาพยังเป็น JPEG และจะไม่บันทึกตามการตั้งค่าคุณภาพ 60% ตามปกติ

ฉันจะปรับขนาดรูปภาพด้วย iPhone SDK ได้อย่างไรและฉันจะเปลี่ยนการตั้งค่าคุณภาพของภาพ JPEG ได้อย่างไร

คำตอบ:


246

คำแนะนำสองสามข้อเป็นคำตอบสำหรับคำถามนี้ ฉันได้แนะนำเทคนิคที่อธิบายไว้ในโพสต์นี้พร้อมรหัสที่เกี่ยวข้อง:

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

   return newImage;
}

เท่าที่จัดเก็บรูปภาพรูปแบบภาพที่เร็วที่สุดที่จะใช้กับ iPhone คือ PNG เนื่องจากมีการเพิ่มประสิทธิภาพสำหรับรูปแบบนั้น อย่างไรก็ตามหากคุณต้องการจัดเก็บภาพเหล่านี้เป็น JPEG คุณสามารถใช้ UIImage ของคุณและทำสิ่งต่อไปนี้:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

สิ่งนี้จะสร้างอินสแตนซ์ NSData ที่มีไบต์ดิบสำหรับภาพ JPEG ที่การตั้งค่าคุณภาพ 60% จากนั้นเนื้อหาของอินสแตนซ์ NSData นั้นสามารถเขียนลงในดิสก์หรือแคชในหน่วยความจำ


1
คุณชาย ... ฉันเขียนตรรกะเดียวกัน แต่เส้นตรงสีขาวหนึ่งเส้นจะปรากฏขึ้น (แนวตั้ง) ทางด้านขวาโปรดช่วยฉันแก้ปัญหา
Nag_iphone

1
สวัสดีเราจะจัดการอย่างไรกับการรักษาอัตราส่วนภาพและคลิปให้ผูกพันเมื่อปรับขนาด? ในกรณีของฉันเมื่อฉันปรับขนาดรูปภาพที่มีการปันส่วนแตกต่างกันจากนั้นจึง "ปรับขนาดข่าว" ฉันจะได้ภาพที่ปรับขนาดผิดรูป ขอบคุณ!
Van Du Tran

1
สิ่งนี้เคยใช้งานได้ในอดีต แต่ใน iOS5.0.1 ขึ้นไปสิ่งนี้ส่งผลให้หน่วยความจำรั่วไหล มีวิธีอื่นในการทำสิ่งนี้หรือไม่?
Usman Nisar

แนะนำให้ใช้ [image drawInRect: rect blendMode: kCGBlendModeCopy alpha: 1.0] เพื่อประสิทธิภาพที่ดีขึ้น (ดังนั้นการวาดจึงไม่ต้องคำนวณการผสมระหว่างการวาด
cdemiris99

คุณควรใช้ UIGraphicsBeginImageContextWithOptions (ขนาด, NO, 0.0); โดยที่ 0.0 จะใช้มาตราส่วนหน้าจอหลักเพื่อรองรับเรติน่าขึ้นไป Apple ระบุว่า "โดยทั่วไปคุณควรหลีกเลี่ยงการเรียกฟังก์ชัน UIGraphicsBeginImageContext ที่มีชื่อคล้ายกัน (ยกเว้นเป็นทางเลือกสำหรับความเข้ากันได้ย้อนหลัง)"
Brad Goss

65

วิธีที่ง่ายและตรงไปตรงมาที่สุดในการปรับขนาดรูปภาพของคุณก็คือ

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

นี่คือความสวยงาม ฉันสามารถตัดทอนรูปภาพที่ส่งไปยังเซิร์ฟเวอร์จากประมาณ 1Mb ถึง 100k ในขณะที่ยังคงรักษาความละเอียดของการแสดงผลเรติน่า (แม้ว่าฉันจะเปลี่ยนค่า 320.0 และ 480.0 เป็น 640.0 และ 1136.0) และยังทำการบีบอัด JPEG บางส่วนหลังจากการปรับขนาด: UIImageJPEGRepresentation (img, 0.7f);
Keller

2
จะเกิดอะไรขึ้นถ้าอัตราส่วนภาพและอัตราส่วนสูงสุดเท่ากัน? ตัวอย่างเช่นถ้าขนาด iamge คือ 3200x4800?
akshay1188

สิ่งนี้เคยใช้งานได้ในอดีต แต่ใน iOS5.0.1 ขึ้นไปสิ่งนี้ส่งผลให้หน่วยความจำรั่วไหล มีวิธีอื่นในการทำสิ่งนี้หรือไม่?
Usman Nisar

25

วิธีการข้างต้นใช้ได้ดีกับภาพขนาดเล็ก แต่เมื่อคุณพยายามปรับขนาดภาพขนาดใหญ่มากหน่วยความจำจะหมดอย่างรวดเร็วและทำให้แอปพัง วิธีที่ดีกว่ามากคือใช้CGImageSourceCreateThumbnailAtIndexเพื่อปรับขนาดรูปภาพโดยไม่ต้องถอดรหัสทั้งหมดก่อน

หากคุณมีเส้นทางไปยังรูปภาพที่ต้องการปรับขนาดคุณสามารถใช้สิ่งนี้:

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

รายละเอียดเพิ่มเติมที่นี่


ขอบคุณโซลูชันนี้ใช้งานได้อย่างมีเสน่ห์) คุณรู้จักรูปแบบไฟล์อื่น ๆ ที่รองรับCGImageSourceนอกเหนือจากรูปภาพและ pdf หรือไม่?
sage444

ขอบคุณ ฉันกำลังมองหาอะนาล็อกinSampleSizeที่ใช้โดยตัวถอดรหัสของ Android และนี่คือคำตอบเดียวที่ให้วิธีการย่อขนาดภาพในลักษณะหน่วยความจำที่มีประสิทธิภาพ
Stan Mots

ฉันได้ผลลัพธ์ที่ยอดเยี่ยมกับการทำงานกับไฟล์ในที่จัดเก็บโดยตรงและยังทำงานกับภาพในหน่วยความจำ แต่ไม่เร็วเท่า (เพื่อโหลดภาพขนาดใหญ่เป็น UIImage จากนั้นปรับขนาด)
Kendall Helmstetter Gelner

ไม่ทำงานในส่วนขยายการแชร์ แอปยังคงขัดข้องด้วยภาพขนาดใหญ่มาก
จอร์จ

18

วิธีที่ดีที่สุดในการปรับขนาดภาพโดยไม่สูญเสียอัตราส่วนภาพ (เช่นโดยไม่ต้องยืดภาพ) คือใช้วิธีนี้:

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

}

เพิ่มวิธีนี้ในคลาส Utility ของคุณเพื่อให้คุณสามารถใช้งานได้ตลอดทั้งโครงการและเข้าถึงได้ดังนี้:

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

วิธีนี้จะดูแลการปรับขนาดในขณะที่รักษาอัตราส่วน นอกจากนี้ยังเพิ่มการเยื้องให้กับรูปภาพในกรณีที่ภาพที่ลดขนาดมีความกว้างมากกว่าความสูง (หรือในทางกลับกัน)


8

หากคุณมีการควบคุมเซิร์ฟเวอร์ฉันจะขอแนะนำการปรับขนาดภาพด้านเซิร์ฟเวอร์กับImageMagik การดาวน์โหลดภาพขนาดใหญ่และปรับขนาดลงในโทรศัพท์เป็นการสิ้นเปลืองทรัพยากรอันมีค่ามากมายไม่ว่าจะเป็นแบนด์วิธแบตเตอรี่และหน่วยความจำ ซึ่งทั้งหมดนี้หายากในโทรศัพท์


2
FTFQ: "แอปพลิเคชันของฉันกำลังดาวน์โหลดชุดไฟล์ภาพจากเครือข่าย"
Rog

นี่อาจเป็นคำตอบที่เกี่ยวข้อง คำถามระบุว่ากำลังดาวน์โหลดรูปภาพจากเครือข่าย หาก OP สามารถทำงานกับฝั่งเซิร์ฟเวอร์รูปภาพได้เขาควร ถ้าเขาตอบไม่ได้ก็จะช่วยได้มากขึ้น
Joshua Dance

6

ฉันได้พัฒนาโซลูชันที่ดีที่สุดสำหรับการปรับขนาดภาพใน Swift

คุณสามารถใช้เพื่อปรับขนาดภาพเพื่อเติมเต็มขนาดภาพหรือขนาดพอดีกับขนาดที่ระบุ

คุณสามารถจัดแนวภาพให้อยู่ตรงกลางหรือขอบทั้งสี่ด้านและมุมทั้งสี่มุมก็ได้

และคุณยังสามารถตัดแต่งพื้นที่พิเศษซึ่งจะถูกเพิ่มเข้าไปหากอัตราส่วนของภาพต้นฉบับและขนาดเป้าหมายไม่เท่ากัน

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

มีตัวอย่างการใช้โซลูชันนี้ด้านล่าง

สี่เหลี่ยมผืนผ้าสีเทาคือรูปภาพไซต์เป้าหมายจะถูกปรับขนาดเป็น วงกลมสีน้ำเงินในสี่เหลี่ยมผืนผ้าสีฟ้าอ่อนคือรูปภาพ (ฉันใช้วงกลมเพราะมองเห็นได้ง่ายเมื่อปรับขนาดโดยไม่คงลักษณะ) สีส้มอ่อนทำเครื่องหมายบริเวณที่จะถูกตัดแต่งหากคุณผ่านtrim: trueแสงสีส้มพื้นที่เครื่องหมายที่จะถูกตัดถ้าคุณผ่าน

ความพอดีก่อนและหลังการปรับขนาด:

สัดส่วนพอดี 1 (ก่อนหน้า) สัดส่วนพอดี 1 (หลัง)

อีกตัวอย่างของความพอดี :

สัดส่วนพอดี 2 (ก่อนหน้า) สัดส่วนพอดี 2 (หลัง)

ขนาดพอดีกับการจัดตำแหน่งด้านบน:

สัดส่วนพอดี 3 (ก่อนหน้า) สัดส่วนพอดี 3 (หลัง)

เติมมุมมอง :

ด้านเติม (ก่อน) เติมสัดส่วน (หลัง)

เติม :

เติม (ก่อน) เติม (หลัง)

ฉันใช้การลดขนาดในตัวอย่างของฉันเพราะมันง่ายกว่าในการสาธิต แต่วิธีแก้ปัญหาก็ใช้สำหรับการลดขนาดได้เช่นกัน

สำหรับการบีบอัด JPEG คุณควรใช้สิ่งนี้:

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

คุณสามารถตรวจสอบส่วนสำคัญของฉันด้วย Xcode playground


3

สำหรับ Swift 3 โค้ดด้านล่างจะปรับขนาดภาพโดยรักษาอัตราส่วน คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ ImageContext ในเอกสารของ Apple :

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

หากต้องการใช้ให้โทรไปที่resizeImage()วิธีการ:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)

2

คุณสามารถใช้รหัสนี้เพื่อปรับขนาดภาพตามขนาดที่ต้องการ

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

2

ตามเซสชันนี้iOS Memory Deep Diveเราใช้ImageIOเพื่อลดขนาดภาพได้ดีขึ้น

ข้อเสียของการใช้UIImageภาพลดขนาด

  • จะขยายภาพต้นฉบับลงในหน่วยความจำ
  • การแปลงพื้นที่พิกัดภายในมีราคาแพง

ใช้ ImageIO

  • ImageIO สามารถอ่านขนาดภาพและข้อมูลเมตาดาต้าโดยไม่ทำให้หน่วยความจำสกปรก

  • ImageIO สามารถปรับขนาดภาพได้ในราคาของภาพที่ปรับขนาดเท่านั้น

เกี่ยวกับภาพในหน่วยความจำ

  • การใช้หน่วยความจำเกี่ยวข้องกับขนาดของรูปภาพไม่ใช่ขนาดไฟล์
  • UIGraphicsBeginImageContextWithOptionsใช้SRGBรูปแบบการแสดงผลซึ่งใช้ 4 ไบต์ต่อพิกเซลเสมอ
  • รูปภาพมีload -> decode -> render3 เฟส
  • UIImage มีราคาแพงสำหรับการปรับขนาดและการปรับขนาด

สำหรับภาพต่อไปนี้หากคุณใช้UIGraphicsBeginImageContextWithOptions เราต้องการเพียง 590KB ในการโหลดภาพในขณะที่เราต้องการ 2048 pixels x 1536 pixels x 4 bytes per pixel= 10MB เมื่อทำการถอดรหัส ใส่คำอธิบายภาพที่นี่

ในขณะที่UIGraphicsImageRendererเปิดตัวใน iOS 10 จะเลือกรูปแบบกราฟิกที่ดีที่สุดใน iOS12 โดยอัตโนมัติ หมายความว่าคุณสามารถประหยัดหน่วยความจำได้ 75% โดยแทนที่UIGraphicsBeginImageContextWithOptionsด้วยUIGraphicsImageRendererถ้าคุณไม่ต้องการ SRGB

นี่คือบทความของฉันเกี่ยวกับรูปภาพ iOS ในหน่วยความจำ

func resize(url: NSURL, maxPixelSize: Int) -> CGImage? {
    let imgSource = CGImageSourceCreateWithURL(url, nil)
    guard let imageSource = imgSource else {
        return nil
    }

    var scaledImage: CGImage?
    let options: [NSString: Any] = [
            // The maximum width and height in pixels of a thumbnail.
            kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
            kCGImageSourceCreateThumbnailWithTransform: true
    ]
    scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)

    return scaledImage
}


let filePath = Bundle.main.path(forResource:"large_leaves_70mp", ofType: "jpg")

let url = NSURL(fileURLWithPath: filePath ?? "")

let image = resize(url: url, maxPixelSize: 600)

หรือ

// Downsampling large images for display at smaller size
func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    let downsampleOptions =
        [kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
    let downsampledImage =
        CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
    return UIImage(cgImage: downsampledImage)
}

1

ปัญหาที่อาจเกิดขึ้นบนจอแสดงผลเรตินาคือขนาดของภาพถูกกำหนดโดย ImageCapture หรือมากกว่านั้น ฟังก์ชันปรับขนาดด้านบนจะไม่เปลี่ยนแปลง ในกรณีเหล่านี้การปรับขนาดจะทำงานไม่ถูกต้อง

ในโค้ดด้านล่างมาตราส่วนถูกตั้งค่าเป็น 1 (ไม่ได้ปรับขนาด) และรูปภาพที่ส่งคืนมีขนาดที่คุณคาดหวัง สิ่งนี้ทำได้ในการUIGraphicsBeginImageContextWithOptionsโทร

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

1

การเพิ่มคำตอบมากมายที่นี่ แต่ฉันได้ไปหาโซลูชันที่ปรับขนาดตามขนาดไฟล์แทนที่จะเป็นมิติข้อมูล

ซึ่งจะลดขนาดและคุณภาพของภาพลงจนกว่าจะถึงขนาดที่คุณกำหนด

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
}

เครดิตสำหรับการปรับขนาดตามคำตอบ


1

เวอร์ชัน Swift

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
}

0

ฉันลงเอยด้วยการใช้เทคนิค Brads เพื่อสร้างscaleToFitWidthวิธีการUIImage+Extensionsหากมีประโยชน์กับทุกคน ...

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

แล้วทุกที่ที่คุณต้องการ

#import "UIImage+Extensions.h"

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

นอกจากนี้ที่น่าสังเกตว่าคุณสามารถย้ายสิ่งนี้ลงไปในUIView+Extensionsชั้นเรียนได้อีกถ้าคุณต้องการแสดงภาพจาก UIView


0

ฉันแค่อยากจะตอบคำถามนั้นสำหรับโปรแกรมเมอร์ Cocoa Swift ฟังก์ชันนี้ส่งคืน NSImage ด้วยขนาดใหม่ คุณสามารถใช้ฟังก์ชันแบบนี้ได้

        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

}

0

หากรูปภาพของคุณอยู่ในไดเร็กทอรีเอกสารให้เพิ่มส่วนขยายURLนี้:

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

การใช้งาน:

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)")

หมายเหตุ: - เปลี่ยน <LocalImagePath.jpg> ด้วยพา ธ รูปภาพ jpg ในเครื่องของคุณ


-1

หากใครยังมองหาตัวเลือกที่ดีกว่า

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

}

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

โปรดระบุคำอธิบายรหัสในคำตอบของคุณเป็นอย่างน้อย และยังจัดรูปแบบโค้ดโดยใช้ตัวแก้ไขคำตอบเพื่อให้อ่านได้
xpereta

-2

ในการปรับขนาดรูปภาพฉันมีผลลัพธ์ที่ดีกว่า (กราฟิก) โดยใช้ฟังก์ชันนี้แทน DrawInRect:

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

อัตราส่วนภาพจะได้รับการดูแลโดยอัตโนมัติ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.