views:

105

answers:

2

Here's what I've got 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 a 200x200 PNG will be less than 128K, which is my size limit. 200x200 is big enough, but I'd prefer to max out the size if at all possible.

Here are my two problems:

  1. The code doesn't work. I check the size of the exported file and it's the same size as the original.
  2. Is there a way to predict the size of the output file before I export, so I can max out the dimensions but still get an image that's less than 128K?


Here's the working code. It's pretty sloppy and could probably use some optimizations, but at this point it runs fast enough that I don't care. It iterates over 100x for most pictures, and it's over in milliseconds. Also, this method is declared in a 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;
}
A: 

[imageData length] should give you the length of the NSData's contents, which I understand to be the final file size when written to disk. That should give you a chance to maximize the size of the file before actually writing it.

As to why the image is not shrinking or growing, according to the docs for setSize:

The size of an image representation combined with the physical dimensions of the image data determine the resolution of the image.

So it may be that by setting the size and not altering the resolution you're not modifying any pixels, just the way in which the pixels should be interpreted.

fbrereto
I don't do Cocoa development, but if you've gotten this far, then a binary search starting with an educated guess should get you an answer quickly.
Lee B
A: 

For 1.

As another poster mentioned, setSize only alters display sizes of the image, and not the actual pixel data of the underlying image file.

To resize, you may want to redraw the source image onto another NSImageRep and then write that to file.

This blog post contains some sample code on how to do the resize in this manner.

How to Resize an NSImage

For 2.

I don't think you can without at least creating the object in memory and checking the length of the image. The actual bytes used will be dependent on the image type. Bitmaps with ARGB will be easy to predict their size, but PNG and JPEG would be much harder.

Brandon Bodnár
That link worked like a charm. Thanks!
kubi