PageRenderTime 23ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/google-toolbox-for-mac/AppKit/GTMNSImage+Scaling.m

http://macfuse.googlecode.com/
Objective C | 186 lines | 134 code | 24 blank | 28 comment | 17 complexity | 0d10881cb67755c66e6297240919e119 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. //
  2. // GTMNSImage+Scaling.m
  3. //
  4. // Scales NSImages to a variety of sizes for drawing
  5. //
  6. // Copyright 2006-2008 Google Inc.
  7. //
  8. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  9. // use this file except in compliance with the License. You may obtain a copy
  10. // of the License at
  11. //
  12. // http://www.apache.org/licenses/LICENSE-2.0
  13. //
  14. // Unless required by applicable law or agreed to in writing, software
  15. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  16. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  17. // License for the specific language governing permissions and limitations under
  18. // the License.
  19. //
  20. #import "GTMNSImage+Scaling.h"
  21. #import "GTMGeometryUtils.h"
  22. @implementation NSImage (GTMNSImageScaling)
  23. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
  24. // If you are on SnowLeopard use
  25. // -[NSImage bestRepresentationForRect:context:hints:]
  26. - (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size {
  27. NSImageRep *bestRep = [self gtm_representationOfSize:size];
  28. if (bestRep) {
  29. return bestRep;
  30. }
  31. NSArray *reps = [self representations];
  32. CGFloat repDistance = CGFLOAT_MAX;
  33. NSImageRep *thisRep;
  34. GTM_FOREACH_OBJECT(thisRep, reps) {
  35. CGFloat thisDistance;
  36. thisDistance = MIN(size.width - [thisRep size].width,
  37. size.height - [thisRep size].height);
  38. if (repDistance < 0 && thisDistance > 0) continue;
  39. if (ABS(thisDistance) < ABS(repDistance)
  40. || (thisDistance < 0 && repDistance > 0)) {
  41. repDistance = thisDistance;
  42. bestRep = thisRep;
  43. }
  44. }
  45. if (!bestRep) {
  46. bestRep = [self bestRepresentationForDevice:nil];
  47. }
  48. return bestRep;
  49. }
  50. #endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
  51. - (NSImageRep *)gtm_representationOfSize:(NSSize)size {
  52. NSArray *reps = [self representations];
  53. NSImageRep *thisRep;
  54. GTM_FOREACH_OBJECT(thisRep, reps) {
  55. if (NSEqualSizes([thisRep size], size)) {
  56. return thisRep;
  57. }
  58. }
  59. return nil;
  60. }
  61. - (BOOL)gtm_createIconRepresentations {
  62. [self setFlipped:NO];
  63. [self gtm_createRepresentationOfSize:NSMakeSize(16, 16)];
  64. [self gtm_createRepresentationOfSize:NSMakeSize(32, 32)];
  65. [self setScalesWhenResized:NO];
  66. return YES;
  67. }
  68. - (BOOL)gtm_createRepresentationOfSize:(NSSize)size {
  69. if ([self gtm_representationOfSize:size]) {
  70. return NO;
  71. }
  72. NSBitmapImageRep *bestRep;
  73. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
  74. bestRep = (NSBitmapImageRep *)[self gtm_bestRepresentationForSize:size];
  75. #else
  76. bestRep
  77. = (NSBitmapImageRep *)[self bestRepresentationForRect:GTMNSRectOfSize(size)
  78. context:nil
  79. hints:nil];
  80. #endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
  81. NSRect drawRect = GTMNSScaleRectToRect(GTMNSRectOfSize([bestRep size]),
  82. GTMNSRectOfSize(size),
  83. GTMScaleProportionally,
  84. GTMRectAlignCenter);
  85. // Using NSSelectorFromString because CGImage isn't a declared selector
  86. // on Tiger, and just using straight @selector(CGImage) will cause compile
  87. // errors on a 10.4 SDK.
  88. SEL cgImageSel = NSSelectorFromString(@"CGImage");
  89. if ([bestRep respondsToSelector:cgImageSel]) {
  90. CGImageRef imageRef = (CGImageRef)[bestRep performSelector:cgImageSel];
  91. CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
  92. if (!cspace) return NO;
  93. CGContextRef smallContext =
  94. CGBitmapContextCreate(NULL,
  95. size.width,
  96. size.height,
  97. 8, // bits per component
  98. size.width * 4, // bytes per pixel
  99. cspace,
  100. kCGBitmapByteOrder32Host
  101. | kCGImageAlphaPremultipliedLast);
  102. CFRelease(cspace);
  103. if (!smallContext) return NO;
  104. CGContextDrawImage(smallContext, GTMNSRectToCGRect(drawRect), imageRef);
  105. CGImageRef smallImage = CGBitmapContextCreateImage(smallContext);
  106. if (smallImage) {
  107. NSBitmapImageRep *cgRep =
  108. [[[NSBitmapImageRep alloc] initWithCGImage:smallImage] autorelease];
  109. [self addRepresentation:cgRep];
  110. CGImageRelease(smallImage);
  111. } else {
  112. CGContextRelease(smallContext);
  113. return NO;
  114. }
  115. CGContextRelease(smallContext);
  116. return YES;
  117. } else {
  118. // This functionality is here to allow it to work under Tiger
  119. // It can probably only be called safely from the main thread
  120. NSImage* scaledImage = [[NSImage alloc] initWithSize:size];
  121. [scaledImage lockFocus];
  122. NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
  123. [graphicsContext setImageInterpolation:NSImageInterpolationHigh];
  124. [graphicsContext setShouldAntialias:YES];
  125. [bestRep drawInRect:drawRect];
  126. NSBitmapImageRep* iconRep =
  127. [[[NSBitmapImageRep alloc] initWithFocusedViewRect:
  128. NSMakeRect(0, 0, size.width, size.height)] autorelease];
  129. [scaledImage unlockFocus];
  130. [scaledImage release];
  131. [self addRepresentation:iconRep];
  132. return YES;
  133. }
  134. return NO;
  135. }
  136. - (void)gtm_removeRepresentationsLargerThanSize:(NSSize)size {
  137. NSMutableArray *repsToRemove = [NSMutableArray array];
  138. NSImageRep *thisRep;
  139. // Remove them in a second loop so we don't change things will doing the
  140. // initial loop.
  141. GTM_FOREACH_OBJECT(thisRep, [self representations]) {
  142. if ([thisRep size].width > size.width
  143. && [thisRep size].height > size.height) {
  144. [repsToRemove addObject:thisRep];
  145. }
  146. }
  147. GTM_FOREACH_OBJECT(thisRep, repsToRemove) {
  148. [self removeRepresentation:thisRep];
  149. }
  150. }
  151. - (NSImage *)gtm_duplicateOfSize:(NSSize)size {
  152. NSImage *duplicate = [[self copy] autorelease];
  153. [duplicate gtm_shrinkToSize:size];
  154. [duplicate setFlipped:NO];
  155. return duplicate;
  156. }
  157. - (void)gtm_shrinkToSize:(NSSize)size {
  158. [self gtm_createRepresentationOfSize:size];
  159. [self setSize:size];
  160. [self gtm_removeRepresentationsLargerThanSize:size];
  161. }
  162. @end