iphone - Отображение большого изображения в маленьком кадре UIImageView по-прежнему стоит много памяти? - PullRequest
3 голосов
/ 21 июля 2011

У меня есть несколько больших изображений размером около 1,5 МБ.Я отображаю каждый из них в UIImageView с UIViewContentModeScaleFit.

Размер кадра UIImageViews составляет всего 150 * 150.

У меня вопрос

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

Но если они находятся в маленьком UIImageView, они все равно будут стоить памяти?

Спасибо

Ответы [ 4 ]

3 голосов
/ 21 июля 2011

UIImage с и UIImageView с - это разные вещи. Каждый UIImageView знает размер, при котором отображается его связанный UIImage. UIImage не имеет понятия, как отображать себя или как оно будет использоваться для отображения, поэтому простое изменение размера UIImageView не влияет на UIImage. Следовательно, это не влияет на общее использование памяти.

То, что вы, вероятно, хотите сделать, это использовать Core Graphics, чтобы взять UIImage и создать его версию 150x150 как новый UIImage, а затем вставить это в UIImageView.

Чтобы выполнить масштабирование, запишите что-то вроде следующего (написанного по мере ввода, поэтому не полностью проверенного):

#include <math.h>

- (UIImage *)scaledImageForImage:(UIImage *)srcImage toSize:(CGSize)maxSize
{
    // pick the target dimensions, as though applying
    // UIViewContentModeScaleAspectFit; seed some values first
    CGSize sizeOfImage = [srcImage size];
    CGSize targetSize; // to store the output size

    // logic here: we're going to scale so as to apply some multiplier
    // to both the width and height of the input image. That multiplier
    // is either going to make the source width fill the output width or
    // it's going to make the source height fill the output height. Of the
    // two possibilities, we want the smaller one, since the larger will
    // make the other axis too large
    if(maxSize.width / sizeOfImage.width < maxSize.height / sizeOfImage.height)
    {
        // we'll letter box then; scaling width to fill width, since
        // that's the smaller scale of the two possibilities
        targetSize.width = maxSize.width;

        // height is the original height adjusted proportionally
        // to match the proportional adjustment in width
        targetSize.height = 
                      (maxSize.width / sizeOfImage.width) * sizeOfImage.height;
    }
    else
    {
        // basically the same as the above, except that we pillar box
        targetSize.height = maxSize.height;
        targetSize.width = 
                     (maxSize.height / sizeOfImage.height) * sizeOfImage.width;
    }

    // images can be integral sizes only, so round up
    // the target size and width, then construct a target
    // rect that centres the output image within that size;
    // this all ensures sub-pixel accuracy
    CGRect targetRect;

    // store the original target size and round up the original
    targetRect.size = targetSize;
    targetSize.width = ceilf(targetSize.width);
    targetSize.height = ceilf(targetSize.height);

    // work out how to centre the source image within the integral-sized
    // output image
    targetRect.origin.x = (targetSize.width - targetRect.size.height) * 0.5f;
    targetRect.origin.y = (targetSize.height - targetRect.size.width) * 0.5f;

    // now create a CGContext to draw to, draw the image to it suitably
    // scaled and positioned, and turn the thing into a UIImage

    // get a suitable CoreGraphics context to draw to, in RGBA;
    // I'm assuming iOS 4 or later here, to save some manual memory
    // management.
    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context  = CGBitmapContextCreate(
           NULL,
           targetSize.width, targetSize.height,
           8, targetSize.width * 4,
           colourSpace, 
           kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colourSpace);

    // clear the context, since it may currently contain anything.
    CGContextClearRect(context, 
                  CGRectMake(0.0f, 0.0f, targetSize.width, targetSize.height));

    // draw the given image to the newly created context
    CGContextDrawImage(context, targetRect, [srcImage CGImage]);

    // get an image from the CG context, wrapping it as a UIImage
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    UIImage *returnImage = [UIImage imageWithCGImage:cgImage];

    // clean up
    CGContextRelease(context);
    CGImageRelease(cgImage);

    return returnImage;
}

Очевидно, я сделал это сложным, комментируя его очень сильно, но на самом деле это всего 23 строки.

1 голос
/ 04 августа 2015
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

+ (UIImage *)resizeImage:(UIImage *)image toResolution:(int)resolution {
  NSData *imageData = UIImagePNGRepresentation(image);
  CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
  CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                   (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                   (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                   (id) kCGImageSourceThumbnailMaxPixelSize : @(resolution)
                                                   };
  CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
  CFRelease(src);
  UIImage *img = [[UIImage alloc]initWithCGImage:thumbnail];
  return img;
}
1 голос
/ 21 июля 2011

Они не будут стоить столько же с точки зрения памяти кадрового буфера (т. Е. Памяти, содержащей пиксели для отображения), но хранение немасштабированных изображений в памяти все равно будет стоить немалых затрат.Если 1.5MB - сжатый размер.вероятно, это будет high (iOS использует приблизительно 4 байта * Width * Height на изображение для хранения несжатого UIImage s).Такие образы также плохо взаимодействуют с автоматическим управлением памятью, которое ядро ​​будет выполнять, когда ваше приложение переходит в фоновый режим - резервные хранилища освобождаются, когда возникает нехватка памяти, но резервное изображение - нет.

Лучший способ работатьЕсли это проблема (и если вам нужно изменить их размер самостоятельно, сохранить меньшие версии и выпустить большие), это запустить приложение через Instruments с помощью VM Tracker.Если области, в которых хранятся изображения, являются чрезмерными, вы сможете их диагностировать и выбрать подходящее решение.Возможно, вы захотите посмотреть сеанс WWDC 2011 по управлению памятью iOS, в котором подробно рассматривается использование памяти изображения, в том числе использование инструментов для поиска проблем.

Как всегда, профиль (или, как Apple может сказать, инструмент) прежде чем оптимизировать!

0 голосов
/ 21 июля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...