// // NSImage+Additions.m // Perforce // // Created by Adam Czubernat on 03.06.2013. // Copyright (c) 2013 Perforce Software, Inc. All rights reserved. // #import "NSImage+Additions.h" #import <QuickLook/QuickLook.h> @interface PFImage : NSImage { NSMutableArray *images; NSEdgeInsets caps; BOOL threeParts; BOOL vertical; CGFloat startCap, endCap; BOOL flipped; } - (id)initWithImage:(NSImage *)image capInsets:(NSEdgeInsets)insets; - (id)initWithImage:(NSImage *)image startCap:(CGFloat)start endCap:(CGFloat)end vertical:(BOOL)vertical; @end @implementation PFImage - (id)initWithCoder:(NSCoder *)coder { if (self = [super initWithCoder:coder]) { images = [coder decodeObjectForKey:@"images"]; threeParts = [[coder decodeObjectForKey:@"threeParts"] boolValue]; vertical = [[coder decodeObjectForKey:@"vertical"] boolValue]; flipped = [[coder decodeObjectForKey:@"flipped"] boolValue]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeObject:images forKey:@"images"]; [coder encodeObject:@(threeParts) forKey:@"threeParts"]; [coder encodeObject:@(vertical) forKey:@"vertical"]; [coder encodeObject:@(flipped) forKey:@"flipped"]; } - (id)initWithImage:(NSImage *)image capInsets:(NSEdgeInsets)insets { if (self = [super initWithSize:image.size]) { caps = insets; flipped = [image isFlipped]; NSData *data = [image TIFFRepresentation]; CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL); CGRect rect; CGImageRef slice; CGSize size = (CGSize) { CGImageGetWidth(imageRef), CGImageGetHeight(imageRef) }; CGSize center = (CGSize) { size.width - caps.left - caps.right, size.height - caps.top - caps.bottom }; images = [NSMutableArray arrayWithCapacity:9]; rect = (NSRect) { 0.0f, 0.0f, caps.left, caps.top }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Topleft CGImageRelease(slice); rect = (NSRect) { caps.left, 0.0f, center.width, caps.top }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Top CGImageRelease(slice); rect = (NSRect) { size.width - caps.right, 0.0f, caps.right, caps.top }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Topright CGImageRelease(slice); rect = (NSRect) { 0.0f, caps.top, caps.left, center.height }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Left CGImageRelease(slice); rect = (NSRect) { caps.left, caps.top, center }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Center CGImageRelease(slice); rect = (NSRect) { size.width - caps.right, caps.top, caps.right, center.height }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Right CGImageRelease(slice); rect = (NSRect) { 0.0f, size.height - caps.bottom, caps.left, caps.bottom }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Bottomleft CGImageRelease(slice); rect = (NSRect) { caps.left, size.height - caps.bottom, center.width, caps.bottom }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Bottom CGImageRelease(slice); rect = (NSRect) { size.width - caps.right, size.height - caps.bottom, caps.right, caps.bottom }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; // Bottomright CGImageRelease(slice); CGImageRelease(imageRef); CFRelease(source); } return self; } - (id)initWithImage:(NSImage *)image startCap:(CGFloat)start endCap:(CGFloat)end vertical:(BOOL)isVertical { if (self = [super initWithSize:image.size]) { threeParts = YES; startCap = start; endCap = end; vertical = isVertical; flipped = [image isFlipped]; NSData *data = [image TIFFRepresentation]; CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL); CGRect rect; CGImageRef slice; CGSize size = (CGSize) { CGImageGetWidth(imageRef), CGImageGetHeight(imageRef) }; images = [NSMutableArray arrayWithCapacity:3]; rect = (vertical ? (NSRect) { 0.0f, 0.0f, size.width, startCap } : (NSRect) { 0.0f, 0.0f, startCap, size.height }); slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; CGImageRelease(slice); rect = (vertical ? (NSRect) { 0.0f, startCap, size.width, size.height - startCap - endCap } : (NSRect) { startCap, 0.0f, size.width - startCap - endCap, size.height }); slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; CGImageRelease(slice); rect = vertical ? (NSRect) { 0.0f, size.width - endCap, size.width, endCap } : (NSRect) { size.width - endCap, 0.0f, endCap, size.height }; slice = CGImageCreateWithImageInRect(imageRef, rect); [images addObject:[[NSImage alloc] initWithCGImage:slice size:rect.size]]; CGImageRelease(slice); CGImageRelease(imageRef); CFRelease(source); } return self; } - (void)drawInRect:(NSRect)rect fromRect:(NSRect)fromRect operation:(NSCompositingOperation)op fraction:(CGFloat)delta { if (threeParts) { NSDrawThreePartImage(rect, [images objectAtIndex:0], [images objectAtIndex:1], [images objectAtIndex:2], vertical, op, delta, flipped); } else { NSDrawNinePartImage(rect, [images objectAtIndex:0], [images objectAtIndex:1], [images objectAtIndex:2], [images objectAtIndex:3], [images objectAtIndex:4], [images objectAtIndex:5], [images objectAtIndex:6], [images objectAtIndex:7], [images objectAtIndex:8], op, delta, flipped); } } - (void)drawInRect:(NSRect)dstSpacePortionRect fromRect:(NSRect)srcSpacePortionRect operation:(NSCompositingOperation)op fraction:(CGFloat)requestedAlpha respectFlipped:(BOOL)respectContextIsFlipped hints:(NSDictionary *)hints { [self drawInRect:dstSpacePortionRect fromRect:srcSpacePortionRect operation:op fraction:requestedAlpha]; } @end @implementation NSImage (Additions) + (NSImage *)imageWithFilePreview:(NSString *)filePath size:(NSSize)size icon:(BOOL)icon { NSURL *fileURL = [NSURL fileURLWithPath:filePath]; if (!filePath || !fileURL) return nil; NSImage *image = nil; NSDictionary *dict = @{ (NSString *)kQLThumbnailOptionIconModeKey : @(icon) }; CGImageRef ref = QLThumbnailImageCreate(kCFAllocatorDefault, (__bridge CFURLRef)fileURL, CGSizeMake(size.width, size.height), (__bridge CFDictionaryRef)dict); // Get icon if quicklook preview hasn't worked if (!ref) { image = [[NSWorkspace sharedWorkspace] iconForFile:filePath]; [image setSize:size]; return image; } NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:ref]; if (bitmap) { image = [[NSImage alloc] initWithSize:[bitmap size]]; [image addRepresentation:bitmap]; } CFRelease(ref); return image; } - (NSImage *)resizableImageWithCapInsets:(NSEdgeInsets)capInsets { return [[PFImage alloc] initWithImage:self capInsets:capInsets]; } - (NSImage *)resizableImageWithLeftCap:(CGFloat)left rightCap:(CGFloat)right { return [[PFImage alloc] initWithImage:self startCap:left endCap:right vertical:NO]; } - (NSImage *)resizableImageWithTopCap:(CGFloat)top bottomCap:(CGFloat)bottom { return [[PFImage alloc] initWithImage:self startCap:top endCap:bottom vertical:YES]; } - (BOOL)isResizable { return [self isKindOfClass:[PFImage class]]; } @end