/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. @implementation NSImage (IconData)
  27. - (NSData *)icnsDataWithWidth:(int)width {
  28. SInt32 version;
  29. Gestalt(gestaltSystemVersionMinor, &version);
  30. OSType icnsType;
  31. switch (width) {
  32. case 128:
  33. icnsType = 'ic07'; // kIconServices128PixelDataARGB
  34. break;
  35. case 256:
  36. icnsType = kIconServices256PixelDataARGB;
  37. break;
  38. case 512:
  39. icnsType = 'ic09'; // kIconServices512PixelDataARGB
  40. break;
  41. default:
  42. NSLog(@"Invalid icon width: %d", width);
  43. return nil;
  44. }
  45. // TODO: We should probably set the image source rect to preserve the aspect
  46. // ratio of the original image by clipping part of it. This leads to a
  47. // smaller .icns file result, which is nice. Basically clip the top and
  48. // bottom (or left and right) of part of the source image. This might also
  49. // lead to better performance?
  50. // See Cocoa Drawing Guide > Images > Creating a Bitmap
  51. // Also see IconStorage.h in OSServices.Framework in CoreServices umbrella.
  52. NSRect rect = NSMakeRect(0, 0, width, width);
  53. size_t bitmapSize = 4 * rect.size.width * rect.size.height;
  54. Handle bitmapHandle = NewHandle(bitmapSize);
  55. unsigned char* bitmapData = (unsigned char *)*bitmapHandle;
  56. NSBitmapFormat format = NSAlphaFirstBitmapFormat;
  57. // TODO: The docs say that the image data should be in non-premultiplied
  58. // format, but when NSAlphaNonpremultipliedBitmapFormat is used on 10.5 we get
  59. // an error about invalid parameters for graphics context. We should try this
  60. // again in future 10.5 releases in case it gets fixed. Until then, maybe
  61. // we should use vImageUnpremultiplyData_ARGB8888(...) on 10.5?
  62. if (version != 5) {
  63. format |= NSAlphaNonpremultipliedBitmapFormat;
  64. }
  65. NSBitmapImageRep* rep =
  66. [[[NSBitmapImageRep alloc]
  67. initWithBitmapDataPlanes:&bitmapData // Single plane; just our bitmapData
  68. pixelsWide:rect.size.width
  69. pixelsHigh:rect.size.height
  70. bitsPerSample:8
  71. samplesPerPixel:4 // ARGB
  72. hasAlpha:YES
  73. isPlanar:NO
  74. colorSpaceName:NSCalibratedRGBColorSpace
  75. bitmapFormat:format
  76. bytesPerRow:0 // Let it compute bytesPerRow and bitsPerPixel
  77. bitsPerPixel:0] autorelease];
  78. [NSGraphicsContext saveGraphicsState];
  79. NSGraphicsContext* context =
  80. [NSGraphicsContext graphicsContextWithBitmapImageRep:rep];
  81. [NSGraphicsContext setCurrentContext:context];
  82. NSImageInterpolation interpolation = [context imageInterpolation];
  83. [context setImageInterpolation:NSImageInterpolationHigh];
  84. [self drawInRect:rect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
  85. [context setImageInterpolation:interpolation];
  86. [NSGraphicsContext restoreGraphicsState];
  87. // On Tiger, the above actually returns RGBA data. Probably a bug in Tiger?
  88. // We use vImage to permute from RGBA -> ARGB in place on the data buffer.
  89. if (version == 4) {
  90. vImage_Buffer src;
  91. src.data = bitmapData;
  92. src.height = rect.size.height;
  93. src.width = rect.size.width;
  94. src.rowBytes = [rep bytesPerRow];
  95. vImage_Buffer dst = src; // We'll just overwrite our bitmap data.
  96. uint8_t permuteMap[] = { 3, 0, 1, 2 }; // Used to go from RGBA -> ARGB
  97. vImagePermuteChannels_ARGB8888(&src, &dst, permuteMap, kvImageDoNotTile);
  98. }
  99. // We need to use SetIconFamilyData here rather than just setting the raw
  100. // bytes because icon family will compress the bitmap for us using RLE. This
  101. // is described in http://ezix.org/project/wiki/MacOSXIcons
  102. Handle familyHandle = NewHandle(0);
  103. SetIconFamilyData((IconFamilyHandle)familyHandle, icnsType, bitmapHandle);
  104. DisposeHandle(bitmapHandle);
  105. NSData* data =
  106. [NSData dataWithBytes:*familyHandle length:GetHandleSize(familyHandle)];
  107. DisposeHandle(familyHandle);
  108. return data;
  109. }
  110. @end