PageRenderTime 62ms CodeModel.GetById 13ms app.highlight 45ms RepoModel.GetById 2ms app.codeStats 0ms

/filesystems-objc/Support/NSImage+IconData.m

http://macfuse.googlecode.com/
Objective C | 120 lines | 72 code | 10 blank | 38 comment | 5 complexity | 82b267ff33570a471693e820517e2f5d MD5 | raw file
  1// ================================================================
  2// Copyright (C) 2007 Google Inc.
  3// 
  4// Licensed under the Apache License, Version 2.0 (the "License");
  5// you may not use this file except in compliance with the License.
  6// You may obtain a copy of the License at
  7// 
  8//      http://www.apache.org/licenses/LICENSE-2.0
  9// 
 10// Unless required by applicable law or agreed to in writing, software
 11// distributed under the License is distributed on an "AS IS" BASIS,
 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13// See the License for the specific language governing permissions and
 14// limitations under the License.
 15// ================================================================
 16//
 17//  NSImage+IconData.m
 18//  MacFUSE
 19//
 20//  Created by ted on 12/28/07.
 21//
 22#import <AppKit/AppKit.h>
 23#import <CoreServices/CoreServices.h>
 24#import <Accelerate/Accelerate.h>
 25#import "NSImage+IconData.h"
 26
 27@implementation NSImage (IconData)
 28
 29- (NSData *)icnsDataWithWidth:(int)width {
 30  SInt32 version;
 31  Gestalt(gestaltSystemVersionMinor, &version);
 32
 33  OSType icnsType;
 34  switch (width) {
 35    case 128:
 36      icnsType = 'ic07';  // kIconServices128PixelDataARGB
 37      break;
 38    case 256:
 39      icnsType = kIconServices256PixelDataARGB;
 40      break;
 41    case 512:
 42      icnsType = 'ic09';  // kIconServices512PixelDataARGB
 43      break;
 44      
 45    default:
 46      NSLog(@"Invalid icon width: %d", width);
 47      return nil;      
 48  }
 49  
 50  // TODO: We should probably set the image source rect to preserve the aspect
 51  // ratio of the original image by clipping part of it.  This leads to a
 52  // smaller .icns file result, which is nice. Basically clip the top and 
 53  // bottom (or left and right) of part of the source image. This might also
 54  // lead to better performance?
 55
 56  // See Cocoa Drawing Guide > Images > Creating a Bitmap
 57  // Also see IconStorage.h in OSServices.Framework in CoreServices umbrella.
 58  NSRect rect = NSMakeRect(0, 0, width, width);
 59  size_t bitmapSize = 4 * rect.size.width * rect.size.height;
 60  Handle bitmapHandle = NewHandle(bitmapSize);
 61  unsigned char* bitmapData = (unsigned char *)*bitmapHandle;
 62  NSBitmapFormat format = NSAlphaFirstBitmapFormat;
 63
 64  // TODO: The docs say that the image data should be in non-premultiplied
 65  // format, but when NSAlphaNonpremultipliedBitmapFormat is used on 10.5 we get 
 66  // an error about invalid parameters for graphics context. We should try this
 67  // again in future 10.5 releases in case it gets fixed. Until then, maybe 
 68  // we should use vImageUnpremultiplyData_ARGB8888(...) on 10.5?
 69  if (version != 5) {
 70    format |= NSAlphaNonpremultipliedBitmapFormat;
 71  }
 72  NSBitmapImageRep* rep = 
 73    [[[NSBitmapImageRep alloc] 
 74      initWithBitmapDataPlanes:&bitmapData  // Single plane; just our bitmapData
 75                    pixelsWide:rect.size.width
 76                    pixelsHigh:rect.size.height
 77                 bitsPerSample:8 
 78               samplesPerPixel:4  // ARGB
 79                      hasAlpha:YES 
 80                      isPlanar:NO 
 81                colorSpaceName:NSCalibratedRGBColorSpace 
 82                  bitmapFormat:format
 83                   bytesPerRow:0  // Let it compute bytesPerRow and bitsPerPixel
 84                  bitsPerPixel:0] autorelease];
 85  [NSGraphicsContext saveGraphicsState];
 86  NSGraphicsContext* context = 
 87    [NSGraphicsContext graphicsContextWithBitmapImageRep:rep];
 88  [NSGraphicsContext setCurrentContext:context];
 89  NSImageInterpolation interpolation = [context imageInterpolation];
 90  [context setImageInterpolation:NSImageInterpolationHigh];
 91  [self drawInRect:rect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
 92  [context setImageInterpolation:interpolation];
 93  [NSGraphicsContext restoreGraphicsState];
 94
 95  // On Tiger, the above actually returns RGBA data. Probably a bug in Tiger?
 96  // We use vImage to permute from RGBA -> ARGB in place on the data buffer.
 97  if (version == 4) {
 98    vImage_Buffer src;
 99    src.data = bitmapData;
100    src.height = rect.size.height;
101    src.width = rect.size.width;
102    src.rowBytes = [rep bytesPerRow];
103    vImage_Buffer dst = src;  // We'll just overwrite our bitmap data.
104    uint8_t permuteMap[] = { 3, 0, 1, 2 };  // Used to go from RGBA -> ARGB
105    vImagePermuteChannels_ARGB8888(&src, &dst, permuteMap, kvImageDoNotTile);
106  }
107  
108  // We need to use SetIconFamilyData here rather than just setting the raw
109  // bytes because icon family will compress the bitmap for us using RLE. This
110  // is described in http://ezix.org/project/wiki/MacOSXIcons
111  Handle familyHandle = NewHandle(0);
112  SetIconFamilyData((IconFamilyHandle)familyHandle, icnsType, bitmapHandle);
113  DisposeHandle(bitmapHandle);
114  NSData* data = 
115    [NSData dataWithBytes:*familyHandle length:GetHandleSize(familyHandle)];
116  DisposeHandle(familyHandle);
117  return data;
118}
119
120@end