Есть ли лучший способ увеличить размер NSImage до максимального размера файла?

Вот что у меня так далеко:

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:
               [file.image TIFFRepresentation]];
// Resize image to 200x200
CGFloat maxSize = 200.0;
NSSize imageSize = imageRep.size;
if (imageSize.height>maxSize || imageSize.width>maxSize) {
    // Find the aspect ratio
    CGFloat aspectRatio = imageSize.height/imageSize.width;
    CGSize newImageSize;
    if (aspectRatio > 1.0) {
        newImageSize = CGSizeMake(maxSize / aspectRatio, maxSize);
    } else if (aspectRatio < 1.0) {
        newImageSize = CGSizeMake(maxSize, maxSize * aspectRatio);
    } else {
        newImageSize = CGSizeMake(maxSize, maxSize);
    }
    [imageRep setSize:NSSizeFromCGSize(newImageSize)];
}


NSData *imageData = [imageRep representationUsingType:NSPNGFileType properties:nil];
NSString *outputFilePath = [@"~/Desktop/output.png" stringByExpandingTildeInPath];
[imageData writeToFile:outputFilePath atomically:NO];

Код предполагает, что PNG размером 200x200 будет меньше 128K, что является моим ограничением размера. 200x200 достаточно большой, но я бы предпочел максимально увеличить размер, если это вообще возможно.

Вот две мои проблемы:

  1. Код не работает. Я проверяю размер экспортируемого файла, и он соответствует размеру оригинала.
  2. Есть ли способ предсказать размер выходного файла перед экспортом, чтобы я мог максимально увеличить размеры, но при этом получить изображение размером менее 128 КБ?

Вот рабочий код. Это довольно небрежно и, возможно, может использовать некоторые оптимизации, но на данный момент он работает достаточно быстро, и мне все равно. Он повторяется более 100 раз для большинства изображений и заканчивается за миллисекунды. Также этот метод объявлен в категории на NSImage,

- (NSData *)resizeImageWithBitSize:(NSInteger)size 
                      andImageType:(NSBitmapImageFileType)fileType {

    CGFloat maxSize = 500.0;
    NSSize originalImageSize = self.size;
    NSSize newImageSize;
    NSData *returnImageData;
    NSInteger imageIsTooBig = 1000;

    while (imageIsTooBig > 0) {
            if (originalImageSize.height>maxSize || originalImageSize.width>maxSize) {
            // Find the aspect ratio
            CGFloat aspectRatio = originalImageSize.height/originalImageSize.width;
            if (aspectRatio > 1.0) {
                newImageSize = NSMakeSize(maxSize / aspectRatio, maxSize);
            } else if (aspectRatio < 1.0) {
                newImageSize = NSMakeSize(maxSize, maxSize * aspectRatio);
            } else {
                newImageSize = NSMakeSize(maxSize, maxSize);
            }
        } else {
            newImageSize = originalImageSize;
        }

        NSImage *resizedImage = [[NSImage alloc] initWithSize:newImageSize];

        [resizedImage lockFocus];
        [self drawInRect:NSMakeRect(0, 0, newImageSize.width, newImageSize.height)
                fromRect: NSMakeRect(0, 0, originalImageSize.width, originalImageSize.height) 
               operation: NSCompositeSourceOver 
                fraction: 1.0];
        [resizedImage unlockFocus];

        NSData *tiffData = [resizedImage TIFFRepresentation];
        [resizedImage release];

        NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithData:tiffData];
        NSDictionary *imagePropDict = [NSDictionary 
                                       dictionaryWithObject:[NSNumber numberWithFloat:0.85] 
                                                     forKey:NSImageCompressionFactor];

        returnImageData = [imageRep representationUsingType:fileType properties:imagePropDict];
        [imageRep release];

        if ([returnImageData length] > size) {
            maxSize = maxSize * 0.99;
            imageIsTooBig--;
        } else {
            imageIsTooBig = 0;
        }

    }

    return returnImageData;
}

2 ответа

Решение

За 1.

Как упоминалось в другом постере, setSize изменяет только размеры отображения изображения, а не фактические данные пикселей основного файла изображения.

Чтобы изменить размер, вы можете перерисовать исходное изображение на другой NSImageRep и затем записать его в файл.

Этот блог содержит пример кода о том, как изменить размер таким способом.

Как изменить размер NSImage

За 2.

Я не думаю, что вы можете без по крайней мере создания объекта в памяти и проверки длины изображения. Фактические байты будут зависеть от типа изображения. Растровые изображения с ARGB легко предсказать их размер, но PNG и JPEG будут намного сложнее.

[imageData length] должен дать вам длину содержимого NSData, которое, как я понимаю, является окончательным размером файла при записи на диск. Это должно дать вам возможность максимизировать размер файла перед его записью.

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

Размер представления изображения в сочетании с физическими размерами данных изображения определяют разрешение изображения.

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

Другие вопросы по тегам