web-dev-qa-db-ja.com

iPhoneのObjective-Cでプログラムで画像のサイズを変更する方法

小さなスペースに大きな画像を表示するアプリケーションがあります。画像は非常に大きいですが、私はそれらを100x100ピクセルのフレームでのみ表示しています。使用している画像のサイズが大きいため、アプリの応答が遅くなります。

パフォーマンスを向上させるために、Objective-Cを使用してプログラムで画像のサイズを変更するにはどうすればよいですか?

43
Madan Mohan

次のコードを見つけてください。

- (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size {
    UIGraphicsBeginImageContext(size);
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *destImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return destImage;
}
96
Satya

このコードは、画像サイズを変更するためのもので、サイズ変更するためのものではありません。画像の幅と高さとしてCGSizeを設定して、画像が伸縮せず、中央に配置されるようにする必要があります。

- (UIImage *)imageWithImage:(UIImage *)image scaledToFillSize:(CGSize)size
{
    CGFloat scale = MAX(size.width/image.size.width, size.height/image.size.height);
    CGFloat width = image.size.width * scale;
    CGFloat height = image.size.height * scale;
    CGRect imageRect = CGRectMake((size.width - width)/2.0f,
                                  (size.height - height)/2.0f,
                                  width,
                                  height);

    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    [image drawInRect:imageRect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
11

これを行うための私のお気に入りの方法は、CGImageSourceCreateThumbnailAtIndex(ImageIOフレームワーク内)を使用することです。名前は少し紛らわしいです。

これが私の最近のアプリからのコードの抜粋です。

CGFloat maxw = // whatever;
CGFloat maxh = // whatever;

CGImageSourceRef src = NULL;
if ([imageSource isKindOfClass:[NSURL class]])
    src = CGImageSourceCreateWithURL((__bridge CFURLRef)imageSource, nil);
else if ([imageSource isKindOfClass:[NSData class]])
    src = CGImageSourceCreateWithData((__bridge CFDataRef)imageSource, nil);

// if at double resolution, double the thumbnail size and use double-resolution image
CGFloat scale = 1;
if ([[UIScreen mainScreen] scale] > 1.0) {
    scale = 2;
    maxw *= 2;
    maxh *= 2;
}

// load the image at the desired size
NSDictionary* d = @{
                    (id)kCGImageSourceShouldAllowFloat: (id)kCFBooleanTrue,
                    (id)kCGImageSourceCreateThumbnailWithTransform: (id)kCFBooleanTrue,
                    (id)kCGImageSourceCreateThumbnailFromImageAlways: (id)kCFBooleanTrue,
                    (id)kCGImageSourceThumbnailMaxPixelSize: @((int)(maxw > maxh ? maxw : maxh))
                    };
CGImageRef imref = CGImageSourceCreateThumbnailAtIndex(src, 0, (__bridge CFDictionaryRef)d);
if (NULL != src)
    CFRelease(src);
UIImage* im = [UIImage imageWithCGImage:imref scale:scale orientation:UIImageOrientationUp];
if (NULL != imref)
    CFRelease(imref);
4
matt

異なるサイズの画像を使用し、毎回サイズを変更すると、アプリのパフォーマンスが低下します。解決策は、imageviewの代わりにボタンを使用するだけで、サイズを変更しないことです。ボタンに画像を設定するだけで自動的にサイズが変更され、優れたパフォーマンスが得られます。

私はセルに設定しながら画像のサイズを変更していましたが、アプリが遅くなりましたので、imageviewの代わりにButtonを使用しました(プログラム的にボタンのサイズを変更しないとボタンがこの仕事をしています)。

2
Vijay Sharma
   -(UIImage *)scaleImage:(UIImage *)image toSize:.     (CGSize)targetSize
   {
//If scaleFactor is not touched, no scaling will occur
   CGFloat scaleFactor = 1.0;

//Deciding which factor to use to scale the image (factor = targetSize / imageSize)
if (image.size.width > targetSize.width || 
   image.size.height > targetSize.height || image.size.width == image.size.height)
    if (!((scaleFactor = (targetSize.width / 
    image.size.width)) > (targetSize.height / 
      image.size.height))) //scale to fit width, or
        scaleFactor = targetSize.height / image.size.height; // scale to fit heigth.
1
user8115970

これを使用できます。

[m_Image.layer setMinificationFilter:kCAFilterTrilinear];

0
Yusuf terzi

IOS 4ではコードが完全に正常に実行されたため、後方互換性のためにOSバージョンのチェックを追加し、5.0未満の場合は古いコードが機能するようにしました。

- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
    BOOL drawTransposed;
    CGAffineTransform transform = CGAffineTransformIdentity;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
        // Apprently in iOS 5 the image is already correctly rotated, so we don't need to rotate it manually
        drawTransposed = NO;  
    } else {    
        switch (self.imageOrientation) {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                drawTransposed = YES;
                break;

            default:
                drawTransposed = NO;
        }

        transform = [self transformForOrientation:newSize];
    } 

    return [self resizedImage:newSize
                    transform:transform
               drawTransposed:drawTransposed
         interpolationQuality:quality];
}
0
iAndroid

2018年末からこんにちは。次の解決策で解決しました(最後の行だけが必要です。最初と2番目は説明のためだけです)。

NSURL *url = [NSURL URLWithString:response.json[0][@"photo_50"]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data scale:customScale];

'customScale'は必要なスケールです(イメージを小さくする必要がある場合は> 1、イメージを大きくする必要がある場合は<1)。

0
sergeyokay

このスレッドは古いですが、この問題を解決しようとしたときに私が取り上げたものです。イメージをスケーリングすると、自動レイアウトをオフにしたにもかかわらず、コンテナーでうまく表示されませんでした。テーブル行で表示するためにこれを解決する最も簡単な方法は、固定サイズの白い背景に画像をペイントすることでした。

ヘルパー機能

+(UIImage*)scaleMaintainAspectRatio:(UIImage*)sourceImage :(float)i_width :(float)i_height
{
float newHeight = 0.0;
float newWidth = 0.0;

float oldWidth = sourceImage.size.width;
float widthScaleFactor = i_width / oldWidth;

float oldHeight = sourceImage.size.height;
float heightScaleFactor = i_height / oldHeight;
if (heightScaleFactor > widthScaleFactor) {
    newHeight = oldHeight * widthScaleFactor;
    newWidth = sourceImage.size.width * widthScaleFactor;
} else {
    newHeight = sourceImage.size.height * heightScaleFactor;
    newWidth = oldWidth * heightScaleFactor;
}

// return image in white rect
float cxPad = i_width - newWidth;
float cyPad = i_height - newHeight;
if (cyPad > 0) {
    cyPad = cyPad / 2.0;
}
if (cxPad > 0) {
    cxPad = cxPad / 2.0;
}

CGSize size = CGSizeMake(i_width, i_height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
[sourceImage drawInRect:CGRectMake((int)cxPad, (int)cyPad, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;

// will return scaled image at actual size, not in white rect
// UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
// [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
// UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// UIGraphicsEndImageContext();
// return newImage;
}

テーブルビューcellForRowAtIndexPathからこのように呼び出しました

    PFFile *childsPicture = [object objectForKey:@"picture"];
[childsPicture getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    if (!error) {
        UIImage *largePicture = [UIImage imageWithData:imageData];
        UIImage *scaledPicture = [Utility scaleMaintainAspectRatio:largePicture :70.0 :70.0 ];
        PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
        thumbnailImageView.image = scaledPicture;
        [self.tableView reloadData];
    }
}];
0