Is there a better way to determine the size of the NSImage for the maximum file size?

Here's what I have so far:

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

      

The code assumes that the 200x200 PNG will be less than 128KB, which is my size limit. 200x200 is large enough, but I would rather increase the size as much as possible if at all possible.

Here are my two problems:

  • The code doesn't work. I check the size of the exported file and the same size as the original.
  • Is there a way to predict the size of the output file before exporting, so I can maximize the sizes but still get an image less than 128KB in size?

Here's the working code. It's pretty sloppy and can probably use some optimizations, but it's fast enough at the moment and I don't care. It iterates over 100 times for most of the images, and this happens in milliseconds. In addition, this method is advertised in the category on 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


source to share


2 answers


For 1.

As another poster mentioned, setSize only resizes the image, not the actual pixel data of the main image file.

To resize, you can redraw the original image to another NSImageRep and then write that to a file.

This blog post contains sample code on how to size this way.



How to resize NSImage

For 2.

I don't think you can at least create an object in memory and check the length of the image. The actual bytes used will depend on the type of image. ARGB bitmaps will be easy to predict their size, but PNG and JPEG will be much more difficult.

0


source


[imageData length]

should give you the length of the NSData content, which I understand is the final file size when written to disk. This should give you the ability to maximize the file size before writing it.

As for why the image doesn't shrink or grow, according to the docs for setSize :



The size of the image representation, combined with the physical dimensions of the image data, determines the image resolution.

So, perhaps by setting the size and not changing the resolution that you don't change in any pixel, just a way of interpreting the pixels.

0


source







All Articles