aboutsummaryrefslogtreecommitdiff
path: root/AppKit/GTMNSImage+Scaling.m
diff options
context:
space:
mode:
Diffstat (limited to 'AppKit/GTMNSImage+Scaling.m')
-rw-r--r--AppKit/GTMNSImage+Scaling.m168
1 files changed, 168 insertions, 0 deletions
diff --git a/AppKit/GTMNSImage+Scaling.m b/AppKit/GTMNSImage+Scaling.m
new file mode 100644
index 0000000..57687fd
--- /dev/null
+++ b/AppKit/GTMNSImage+Scaling.m
@@ -0,0 +1,168 @@
+//
+// GTMNSImage+Scaling.m
+//
+// Scales NSImages to a variety of sizes for drawing
+//
+// Copyright 2006-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMNSImage+Scaling.h"
+#import "GTMGeometryUtils.h"
+
+@implementation NSImage (GTMNSImageScaling)
+
+- (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size {
+ NSImageRep *bestRep = [self gtm_representationOfSize:size];
+ if (bestRep) {
+ return bestRep;
+ }
+ NSArray *reps = [self representations];
+
+ CGFloat repDistance = CGFLOAT_MAX;
+
+ NSImageRep *thisRep;
+ NSEnumerator *repEnum = [reps objectEnumerator];
+ while ((thisRep = [repEnum nextObject])) {
+ CGFloat thisDistance;
+ thisDistance = MIN(size.width - [thisRep size].width,
+ size.height-[thisRep size].height);
+
+ if (repDistance < 0 && thisDistance > 0) continue;
+ if (ABS(thisDistance) < ABS(repDistance)
+ || (thisDistance < 0 && repDistance > 0)) {
+ repDistance = thisDistance;
+ bestRep = thisRep;
+ }
+ }
+
+ if (!bestRep) {
+ bestRep = [self bestRepresentationForDevice:nil];
+ }
+
+ return bestRep;
+}
+
+- (NSImageRep *)gtm_representationOfSize:(NSSize)size {
+ NSArray *reps = [self representations];
+
+ NSImageRep *thisRep;
+ NSEnumerator *repEnum = [reps objectEnumerator];
+ while ((thisRep = [repEnum nextObject])) {
+ if (NSEqualSizes([thisRep size], size)) {
+ return thisRep;
+ }
+ }
+ return nil;
+}
+
+- (BOOL)gtm_createIconRepresentations {
+ [self setFlipped:NO];
+ [self gtm_createRepresentationOfSize:NSMakeSize(16, 16)];
+ [self gtm_createRepresentationOfSize:NSMakeSize(32, 32)];
+ [self setScalesWhenResized:NO];
+ return YES;
+}
+
+- (BOOL)gtm_createRepresentationOfSize:(NSSize)size {
+ if ([self gtm_representationOfSize:size]) {
+ return NO;
+ }
+
+ NSBitmapImageRep *bestRep =
+ (NSBitmapImageRep *)[self gtm_bestRepresentationForSize:size];
+
+ NSRect drawRect = GTMNSScaleRectToRect(GTMNSRectOfSize([bestRep size]),
+ GTMNSRectOfSize(size),
+ GTMScaleProportionally,
+ GTMRectAlignCenter);
+
+ if ([bestRep respondsToSelector:@selector(CGImage)]) {
+ CGImageRef imageRef = (CGImageRef)[bestRep performSelector:@selector(CGImage)];
+
+ CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
+ if (!cspace) return NO;
+
+ CGContextRef smallContext =
+ CGBitmapContextCreate(NULL,
+ size.width,
+ size.height,
+ 8, // bits per component
+ size.width * 4, // bytes per pixel
+ cspace,
+ kCGBitmapByteOrder32Host
+ | kCGImageAlphaPremultipliedLast);
+ CFRelease(cspace);
+
+ if (!smallContext) return NO;
+
+
+ CGContextDrawImage(smallContext, GTMNSRectToCGRect(drawRect), imageRef);
+
+ CGImageRef smallImage = CGBitmapContextCreateImage(smallContext);
+
+ if (smallImage) {
+ NSBitmapImageRep *cgRep =
+ [[[NSBitmapImageRep alloc] initWithCGImage:smallImage] autorelease];
+ [self addRepresentation:cgRep];
+ CGImageRelease(smallImage);
+ } else {
+ CGContextRelease(smallContext);
+ return NO;
+ }
+ CGContextRelease(smallContext);
+ return YES;
+ } else {
+ // This functionality is here to allow it to work under Tiger
+ // It can probably only be called safely from the main thread
+ NSImage* scaledImage = [[NSImage alloc] initWithSize:size];
+ [scaledImage lockFocus];
+ NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
+ [graphicsContext setImageInterpolation:NSImageInterpolationHigh];
+ [graphicsContext setShouldAntialias:YES];
+ [bestRep drawInRect:drawRect];
+ NSBitmapImageRep* iconRep =
+ [[[NSBitmapImageRep alloc] initWithFocusedViewRect:
+ NSMakeRect(0, 0, size.width, size.height)] autorelease];
+ [scaledImage unlockFocus];
+ [scaledImage release];
+ [self addRepresentation:iconRep];
+ return YES;
+ }
+ return NO;
+}
+
+- (void)gtm_removeRepresentationsLargerThanSize:(NSSize)size {
+ NSEnumerator *e = [[self representations] reverseObjectEnumerator];
+ NSImageRep *thisRep;
+ while((thisRep = [e nextObject]) ) {
+ if ([thisRep size].width > size.width
+ && [thisRep size].height > size.height)
+ [self removeRepresentation:thisRep];
+ }
+}
+
+- (NSImage *)gtm_duplicateOfSize:(NSSize)size {
+ NSImage *duplicate = [[self copy] autorelease];
+ [duplicate gtm_shrinkToSize:size];
+ [duplicate setFlipped:NO];
+ return duplicate;
+}
+
+- (void)gtm_shrinkToSize:(NSSize)size {
+ [self gtm_createRepresentationOfSize:size];
+ [self setSize:size];
+ [self gtm_removeRepresentationsLargerThanSize:size];
+}
+@end