PageRenderTime 79ms CodeModel.GetById 15ms app.highlight 61ms 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
  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
 21#import "GTMNSImage+Scaling.h"
 22#import "GTMGeometryUtils.h"
 23
 24@implementation NSImage (GTMNSImageScaling)
 25
 26#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
 27// If you are on SnowLeopard use 
 28// -[NSImage bestRepresentationForRect:context:hints:] 
 29- (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size {
 30  NSImageRep *bestRep = [self gtm_representationOfSize:size];
 31  if (bestRep) {
 32    return bestRep;
 33  } 
 34  NSArray *reps = [self representations];
 35  
 36  CGFloat repDistance = CGFLOAT_MAX;
 37  
 38  NSImageRep *thisRep;
 39  GTM_FOREACH_OBJECT(thisRep, reps) {
 40    CGFloat thisDistance;
 41    thisDistance = MIN(size.width - [thisRep size].width,
 42                       size.height - [thisRep size].height);  
 43    
 44    if (repDistance < 0 && thisDistance > 0) continue;
 45    if (ABS(thisDistance) < ABS(repDistance)
 46        || (thisDistance < 0 && repDistance > 0)) {
 47      repDistance = thisDistance;
 48      bestRep = thisRep;
 49    }
 50  }
 51  
 52  if (!bestRep) {
 53    bestRep = [self bestRepresentationForDevice:nil];
 54  }
 55  
 56  return bestRep;
 57}
 58#endif  // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
 59
 60- (NSImageRep *)gtm_representationOfSize:(NSSize)size {
 61  NSArray *reps = [self representations];
 62  
 63  NSImageRep *thisRep;
 64  GTM_FOREACH_OBJECT(thisRep, reps) {
 65    if (NSEqualSizes([thisRep size], size)) {
 66      return thisRep;
 67    }
 68  }
 69  return nil;
 70}
 71
 72- (BOOL)gtm_createIconRepresentations {
 73  [self setFlipped:NO];
 74  [self gtm_createRepresentationOfSize:NSMakeSize(16, 16)];  
 75  [self gtm_createRepresentationOfSize:NSMakeSize(32, 32)];
 76  [self setScalesWhenResized:NO];
 77  return YES;
 78}
 79
 80- (BOOL)gtm_createRepresentationOfSize:(NSSize)size { 
 81  if ([self gtm_representationOfSize:size]) {
 82    return NO;
 83  }
 84
 85  NSBitmapImageRep *bestRep;
 86#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
 87  bestRep = (NSBitmapImageRep *)[self gtm_bestRepresentationForSize:size];
 88#else
 89  bestRep 
 90    = (NSBitmapImageRep *)[self bestRepresentationForRect:GTMNSRectOfSize(size)
 91                                                  context:nil
 92                                                    hints:nil];
 93#endif  // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
 94  
 95  NSRect drawRect = GTMNSScaleRectToRect(GTMNSRectOfSize([bestRep size]), 
 96                                       GTMNSRectOfSize(size),
 97                                       GTMScaleProportionally,
 98                                       GTMRectAlignCenter);
 99  // Using NSSelectorFromString because CGImage isn't a declared selector
100  // on Tiger, and just using straight @selector(CGImage) will cause compile
101  // errors on a 10.4 SDK.
102  SEL cgImageSel = NSSelectorFromString(@"CGImage");
103  if ([bestRep respondsToSelector:cgImageSel]) {
104    CGImageRef imageRef = (CGImageRef)[bestRep performSelector:cgImageSel];
105    
106    CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();   
107    if (!cspace) return NO;
108    
109    CGContextRef smallContext = 
110      CGBitmapContextCreate(NULL,
111                            size.width,
112                            size.height,
113                            8,            // bits per component
114                            size.width * 4, // bytes per pixel
115                            cspace,
116                            kCGBitmapByteOrder32Host
117                            | kCGImageAlphaPremultipliedLast);
118    CFRelease(cspace);
119    
120    if (!smallContext) return NO;
121 
122    
123    CGContextDrawImage(smallContext, GTMNSRectToCGRect(drawRect), imageRef);
124    
125    CGImageRef smallImage = CGBitmapContextCreateImage(smallContext);
126   
127    if (smallImage) {
128      NSBitmapImageRep *cgRep = 
129       [[[NSBitmapImageRep alloc] initWithCGImage:smallImage] autorelease];
130      [self addRepresentation:cgRep];   
131      CGImageRelease(smallImage);
132    } else {
133      CGContextRelease(smallContext);
134      return NO;
135    }
136    CGContextRelease(smallContext);
137    return YES;
138  } else {
139    // This functionality is here to allow it to work under Tiger
140    // It can probably only be called safely from the main thread
141    NSImage* scaledImage = [[NSImage alloc] initWithSize:size];
142    [scaledImage lockFocus];
143    NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
144    [graphicsContext setImageInterpolation:NSImageInterpolationHigh];
145    [graphicsContext setShouldAntialias:YES];
146    [bestRep drawInRect:drawRect];
147    NSBitmapImageRep* iconRep = 
148    [[[NSBitmapImageRep alloc] initWithFocusedViewRect:
149      NSMakeRect(0, 0, size.width, size.height)] autorelease];
150    [scaledImage unlockFocus];
151    [scaledImage release];
152    [self addRepresentation:iconRep];
153    return YES; 
154  }
155  return NO;
156}
157
158- (void)gtm_removeRepresentationsLargerThanSize:(NSSize)size {
159  NSMutableArray *repsToRemove = [NSMutableArray array];
160  NSImageRep *thisRep;
161  // Remove them in a second loop so we don't change things will doing the
162  // initial loop.
163  GTM_FOREACH_OBJECT(thisRep, [self representations]) {
164    if ([thisRep size].width > size.width
165        && [thisRep size].height > size.height) {
166      [repsToRemove addObject:thisRep];
167    }
168  }
169  GTM_FOREACH_OBJECT(thisRep, repsToRemove) {
170    [self removeRepresentation:thisRep];
171  }
172}
173
174- (NSImage *)gtm_duplicateOfSize:(NSSize)size {
175  NSImage *duplicate = [[self copy] autorelease];
176  [duplicate gtm_shrinkToSize:size];
177  [duplicate setFlipped:NO];
178  return duplicate;
179}
180
181- (void)gtm_shrinkToSize:(NSSize)size {
182  [self gtm_createRepresentationOfSize:size];
183  [self setSize:size];
184  [self gtm_removeRepresentationsLargerThanSize:size];
185}
186@end