Что это самый простой способ, чтобы изменить размер / оптимизировать размер изображения с помощью iPhone SDK?

голоса
107

Мое приложение загружает набор графических файлов из сети, и сохранять их на локальный диск iPhone. Некоторые из этих изображений довольно большие по размеру (ширина больше, чем 500 пикселей, например). Так как iPhone даже не имеет достаточно большой дисплей, чтобы показать изображение в его оригинальном размере, я планирую на изменение размера изображения на что-то немного меньше, чтобы сэкономить на пространстве / производительность.

Кроме того, некоторые из этих изображений являются JPEGs, и они не будут сохранены в качестве обычного параметра качества 60%.

Как я могу изменить размер изображения с iPhone SDK, и как я могу изменить настройки качества изображения в формате JPEG?

Задан 04/03/2009 в 20:42
источник пользователем
На других языках...                            


18 ответов

голоса
240

Несколько предложений предоставляются в качестве ответов на этот вопрос . Я предложил метод , описанный в этом сообщении , с соответствующим кодом:

+ (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 затем могут быть записаны на диск или кэшируются в памяти.

Ответил 05/03/2009 в 03:20
источник пользователем

голоса
64

Самый простой и самый простой способ изменить размер изображения будет таким

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();
Ответил 05/03/2009 в 05:35
источник пользователем

голоса
23

Вышеупомянутые методы работают хорошо для небольших изображений, но при попытке изменить размер очень большое изображение, вы быстро запустить из памяти и сбою приложения. Гораздо лучше всего использовать , 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);
}

Подробнее здесь .

Ответил 01/09/2014 в 12:03
источник пользователем

голоса
18

Лучший способ масштабирования изображения без потери пропорций (т.е. без растяжения imgage) заключается в использовании этого метода:

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

}

Добавьте этот метод к классу утилит, так что вы можете использовать его на протяжении всего проекта, и доступ к нему так:

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

Этот метод заботится о масштабировании, сохраняя при этом соотношение сторон. Он также добавляет отступы к изображению в случае уменьшенное изображение имеет больше ширины, чем высота (или наоборот).

Ответил 03/05/2013 в 09:40
источник пользователем

голоса
7

Если у вас есть контроль над сервером, я бы настоятельно рекомендовал изменение размера изображения стороны сервера с ImageMagik . Загрузка больших изображений и изменение размеров их по телефону является тратой многих драгоценных ресурсов - пропускная способность, батарея и память. Все это не хватает на телефонах.

Ответил 05/03/2009 в 10:23
источник пользователем

голоса
5

Я разработал окончательное решение для масштабирования изображения в 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 (после)

Заливка аспект :

Аспект заполнения (до) Формат заполнения (после)

Наполните :

Fill (раньше) Fill (после)

Я использовал апскейлинг в моих примерах, потому что это проще продемонстрировать, но решение также работает на разукрупнение, как и в вопросе.

Для сжатия JPEG вы должны использовать это:

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

Вы можете проверить свою суть с Xcode площадкой.

Ответил 23/03/2016 в 13:51
источник пользователем

голоса
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)
Ответил 14/04/2017 в 03:50
источник пользователем

голоса
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;
}
Ответил 30/09/2015 в 10:51
источник пользователем

голоса
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
}
Ответил 12/04/2018 в 10:25
источник пользователем

голоса
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
}

Кредит для масштабирования по размеру ответ

Ответил 10/07/2017 в 11:24
источник пользователем

голоса
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 изображения.

Ответил 18/05/2018 в 10:02
источник пользователем

голоса
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;
}
Ответил 03/11/2016 в 08:37
источник пользователем

голоса
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

}
Ответил 13/07/2016 в 09:00
источник пользователем

голоса
0

Попробуйте, это работает для меня,

       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];
Ответил 18/03/2016 в 11:48
источник пользователем

голоса
0

Я закончил с использованием шпилек техники , чтобы создать 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

Ответил 15/03/2016 в 14:49
источник пользователем

голоса
0

Если кто-то до сих пор ищет лучший вариант

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

}
Ответил 23/06/2015 в 07:39
источник пользователем

голоса
0

Проблема, которая может возникнуть на сетчатке дисплеев является то, что масштаб изображения устанавливается 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;
}
Ответил 06/04/2015 в 10:24
источник пользователем

голоса
-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;
}

Соотношение сторон заботится для автоматического

Ответил 01/09/2013 в 15:46
источник пользователем

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