adium 3785:974e73ff45bb: Merged 10.6+ into default. (Goodbye Leo...
commits at adium.im
commits at adium.im
Mon Mar 28 00:29:41 UTC 2011
details: http://hg.adium.im/adium/rev/974e73ff45bb
revision: 3785:974e73ff45bb
branch: (none)
author: Adrian Godoroja <robotive at me.com>
date: Mon Mar 28 03:28:39 2011 +0300
Merged 10.6+ into default. (Goodbye Leopard, we will miss you ;), will we? :D)
"Innovation distinguishes between a leader and a follower." Steve Jobs
Let's innovate and move forward. Me.
diffs (truncated from 3994 to 1000 lines):
diff -r 6433a4fcfe52 -r 974e73ff45bb Adium.xcodeproj/project.pbxproj
--- a/Adium.xcodeproj/project.pbxproj Mon Mar 28 02:24:35 2011 +0300
+++ b/Adium.xcodeproj/project.pbxproj Mon Mar 28 03:28:39 2011 +0300
@@ -1468,7 +1468,6 @@
811036260CDE8C2100EC6038 /* adiumPurpleCertificateTrustWarning.m in Sources */ = {isa = PBXBuildFile; fileRef = 811036240CDE8C2100EC6038 /* adiumPurpleCertificateTrustWarning.m */; };
8110362C0CDE8F5800EC6038 /* AIPurpleCertificateTrustWarningAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = 8110362A0CDE8F5800EC6038 /* AIPurpleCertificateTrustWarningAlert.h */; };
8110362D0CDE8F5800EC6038 /* AIPurpleCertificateTrustWarningAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 8110362B0CDE8F5800EC6038 /* AIPurpleCertificateTrustWarningAlert.m */; };
- 8163F99C0B318824002005EE /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 638392F609D4D67A0067B9B7 /* Sparkle.framework */; };
8173C5760C4C3DB800C9E64E /* downloadprogress.png in Resources */ = {isa = PBXBuildFile; fileRef = 8173C5750C4C3DB800C9E64E /* downloadprogress.png */; };
8181EEBE0C30673E00E802F7 /* AMPurpleSearchResultsWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 8181EEBD0C30673E00E802F7 /* AMPurpleSearchResultsWindow.nib */; };
8181EEC30C3067B500E802F7 /* AMPurpleSearchResultsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8181EEC10C3067B500E802F7 /* AMPurpleSearchResultsController.h */; };
@@ -1489,7 +1488,6 @@
81DAED520C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.h in Headers */ = {isa = PBXBuildFile; fileRef = 81DAED500C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.h */; };
81DAED530C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.m in Sources */ = {isa = PBXBuildFile; fileRef = 81DAED510C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.m */; };
81E45D760C15BFF800B7381B /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34E839050583207E00F2AADB /* SystemConfiguration.framework */; };
- 9722ABC613257D5800CAB486 /* ContactListWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9722ABC513257D5800CAB486 /* ContactListWindow.xib */; };
9722ABC813257D7F00CAB486 /* ContactListWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9722ABC713257D7F00CAB486 /* ContactListWindow.xib */; };
97AF5CDB13191DE200550C41 /* AIContactListUserPictureMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97AF5CDA13191DE200550C41 /* AIContactListUserPictureMenuController.m */; };
97AF5CE713191E4800550C41 /* AIImageCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AF5CE213191E2800550C41 /* AIImageCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -4734,7 +4732,6 @@
81DAE8710C261E8A00780E4C /* AMPurpleTuneTooltip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AMPurpleTuneTooltip.m; path = "Plugins/Purple Service/AMPurpleTuneTooltip.m"; sourceTree = "<group>"; };
81DAED500C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AMPurpleJabberServiceDiscoveryBrowsing.h; path = "Plugins/Purple Service/AMPurpleJabberServiceDiscoveryBrowsing.h"; sourceTree = "<group>"; };
81DAED510C26F4F700780E4C /* AMPurpleJabberServiceDiscoveryBrowsing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AMPurpleJabberServiceDiscoveryBrowsing.m; path = "Plugins/Purple Service/AMPurpleJabberServiceDiscoveryBrowsing.m"; sourceTree = "<group>"; };
- 9722ABC513257D5800CAB486 /* ContactListWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ContactListWindow.xib; path = Resources/ContactListWindow.xib; sourceTree = "<group>"; };
9722ABC713257D7F00CAB486 /* ContactListWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ContactListWindow.xib; path = Resources/ContactListWindow.xib; sourceTree = "<group>"; };
97AF5CD913191DE200550C41 /* AIContactListUserPictureMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIContactListUserPictureMenuController.h; path = Source/AIContactListUserPictureMenuController.h; sourceTree = "<group>"; };
97AF5CDA13191DE200550C41 /* AIContactListUserPictureMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIContactListUserPictureMenuController.m; path = Source/AIContactListUserPictureMenuController.m; sourceTree = "<group>"; };
@@ -4950,7 +4947,6 @@
638392F809D4D67A0067B9B7 /* Sparkle.framework in Frameworks */,
9E1E1DFD0A96741500E16DFC /* LMX.framework in Frameworks */,
377EC8940AE9525B00CB7BDF /* PSMTabBarControl.framework in Frameworks */,
- 8163F99C0B318824002005EE /* Sparkle.framework in Frameworks */,
11AA1EFA0BCAE9C3003DDA66 /* Quartz.framework in Frameworks */,
340C1ABF0BD58FAB00D09235 /* Security.framework in Frameworks */,
31E0CD810C5EEF5200271DB1 /* CoreAudio.framework in Frameworks */,
@@ -5267,7 +5263,6 @@
29B97323FDCFA39411CA2CEA /* Linked Frameworks */,
63C7E0280FAF9B7D00B310AC /* xcconfigs */,
19C28FACFE9D520D11CA2CBB /* Products */,
- 9722ABC513257D5800CAB486 /* ContactListWindow.xib */,
);
name = CocAIMe2;
sourceTree = "<group>";
@@ -10022,7 +10017,6 @@
76889DEF12D3CA40007AEF00 /* Personal.png in Resources */,
1154F50A12E1476900B8CA27 /* AILogByAccountWindow.nib in Resources */,
97AF5CF413191E9A00550C41 /* ContactListChangeUserPictureMenu.xib in Resources */,
- 9722ABC613257D5800CAB486 /* ContactListWindow.xib in Resources */,
9722ABC813257D7F00CAB486 /* ContactListWindow.xib in Resources */,
5ADFFE5D133846C300069C1B /* keys.png in Resources */,
);
diff -r 6433a4fcfe52 -r 974e73ff45bb ChangeLogs/Changes.txt
--- a/ChangeLogs/Changes.txt Mon Mar 28 02:24:35 2011 +0300
+++ b/ChangeLogs/Changes.txt Mon Mar 28 03:28:39 2011 +0300
@@ -37,12 +37,18 @@
* Fixed link insertion for NetNewsWire. (#11389)
* Added Google Chrome support for link insertion.
+ Chat Window
+ * Rounded user icon in the chat window toolbar. (#3757)
+
Message View
* Added the "lastFocus" class for message styles to the latest message received while the chat didn't have focus.
Transcript Viewer
* Added next/previous buttons for highlighted search terms within a transcript (similar to Safari).
+ User Picture (Buddy Icons)
+ * Ability to resize animated gifs that are too large (#9885)
+
AIM
* Added a preference for AIM: "allow multiple sign in locations" defaulting to true. (Josh Perry) (#5790)
diff -r 6433a4fcfe52 -r 974e73ff45bb Frameworks/AIUtilities Framework/Source/AIImageAdditions.h
--- a/Frameworks/AIUtilities Framework/Source/AIImageAdditions.h Mon Mar 28 02:24:35 2011 +0300
+++ b/Frameworks/AIUtilities Framework/Source/AIImageAdditions.h Mon Mar 28 03:28:39 2011 +0300
@@ -32,6 +32,7 @@
AIJPEG2000FileType = NSJPEG2000FileType
} AIBitmapImageFileType;
+
@interface NSImage (AIImageAdditions)
+ (NSImage *)imageNamed:(NSString *)name forClass:(Class)inClass;
@@ -59,10 +60,21 @@
- (NSData *)PNGRepresentation;
- (NSData *)GIFRepresentation;
- (NSData *)BMPRepresentation;
+- (NSData *)bestRepresentationByType;
- (NSBitmapImageRep *)largestBitmapImageRep;
- (NSData *)representationWithFileType:(NSBitmapImageFileType)fileType
maximumFileSize:(NSUInteger)maximumSize;
+/*
+ * Writes Application Extension Block and modifies Graphic Control Block for a GIF image
+ */
+- (void)writeGIFExtensionBlocksInData:(NSMutableData *)data forRepresenation:(NSBitmapImageRep *)bitmap;
+
+/*
+ * Properties for a GIF image
+ */
+- (NSDictionary *)GIFPropertiesForRepresentation:(NSBitmapImageRep *)bitmap;
+
@end
//Defined in AppKit.framework
diff -r 6433a4fcfe52 -r 974e73ff45bb Frameworks/AIUtilities Framework/Source/AIImageAdditions.m
--- a/Frameworks/AIUtilities Framework/Source/AIImageAdditions.m Mon Mar 28 02:24:35 2011 +0300
+++ b/Frameworks/AIUtilities Framework/Source/AIImageAdditions.m Mon Mar 28 03:28:39 2011 +0300
@@ -17,27 +17,31 @@
#import "AIImageAdditions.h"
@interface NSImage (AIImageAdditions_PRIVATE)
+
- (NSBitmapImageRep *)bitmapRep;
+
@end
@implementation NSImage (AIImageAdditions)
+ (NSImage *)imageNamed:(NSString *)name forClass:(Class)inClass loadLazily:(BOOL)flag
{
- NSBundle *ownerBundle;
- NSString *imagePath;
- NSImage *image;
+ NSBundle *ownerBundle;
+ NSString *imagePath;
+ NSImage *image;
- //Get the bundle
+ // Get the bundle
ownerBundle = [NSBundle bundleForClass:inClass];
- //Open the image
+ // Open the image
imagePath = [ownerBundle pathForImageResource:name];
- if(flag)
+
+ if(flag) {
image = [[NSImage alloc] initByReferencingFile:imagePath];
- else
+ } else {
image = [[NSImage alloc] initWithContentsOfFile:imagePath];
-
+ }
+
return [image autorelease];
}
@@ -50,201 +54,26 @@
+ (NSImage *)imageForSSL
{
static NSImage *SSLIcon = nil;
+
if (!SSLIcon) {
NSBundle *securityInterfaceFramework = [NSBundle bundleWithIdentifier:@"com.apple.securityinterface"];
- if (!securityInterfaceFramework) securityInterfaceFramework = [NSBundle bundleWithPath:@"/System/Library/Frameworks/SecurityInterface.framework"];
+
+ if (!securityInterfaceFramework) {
+ securityInterfaceFramework = [NSBundle bundleWithPath:@"/System/Library/Frameworks/SecurityInterface.framework"];
+ }
SSLIcon = [[NSImage alloc] initByReferencingFile:[securityInterfaceFramework pathForImageResource:@"CertSmallStd"]];
}
+
return SSLIcon;
}
-//Create and return an opaque bitmap image rep, replacing transparency with [NSColor whiteColor]
-- (NSBitmapImageRep *)opaqueBitmapImageRep
-{
- NSImage *tempImage = nil;
- NSBitmapImageRep *imageRep = nil;
- NSSize size = [self size];
-
- //Work with a temporary image so we don't modify self
- tempImage = [[[NSImage allocWithZone:[self zone]] initWithSize:size] autorelease];
-
- //Lock before drawing to the temporary image
- [tempImage lockFocus];
-
- //Fill with a white background
- [[NSColor whiteColor] set];
- NSRectFill(NSMakeRect(0, 0, size.width, size.height));
-
- //Draw the image
- [self compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
-
- //We're done drawing
- [tempImage unlockFocus];
-
- //Find an NSBitmapImageRep from the temporary image
- for (NSImageRep *rep in tempImage.representations) {
- if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
- imageRep = (NSBitmapImageRep *)rep;
- }
- }
-
- //Make one if necessary
- if (!imageRep) {
- imageRep = [NSBitmapImageRep imageRepWithData:[tempImage TIFFRepresentation]];
- }
-
- // 10.6 behavior: Drawing into a new image copies the display's color profile in.
- // Remove the color profile so we don't bloat the image size.
- [imageRep setProperty:NSImageColorSyncProfileData withValue:nil];
-
- return imageRep;
-}
-
-- (NSBitmapImageRep *)largestBitmapImageRep
-{
- //Find the biggest image
- NSEnumerator *repsEnum = [[self representations] objectEnumerator];
- NSBitmapImageRep *bestRep = nil;
- NSImageRep *rep;
- Class NSBitmapImageRepClass = [NSBitmapImageRep class];
- CGFloat maxWidth = 0;
- while ((rep = [repsEnum nextObject])) {
- if ([rep isKindOfClass:NSBitmapImageRepClass]) {
- CGFloat thisWidth = [rep size].width;
- if (thisWidth >= maxWidth) {
- //Cast explanation: GCC warns about us returning an NSImageRep here, presumably because it could be some other kind of NSImageRep if we don't check the class. Fortunately, we have such a check. This cast silences the warning.
- bestRep = (NSBitmapImageRep *)rep;
- maxWidth = thisWidth;
- }
- }
- }
-
- //We don't already have one, so forge one from our TIFF representation.
- if (!bestRep)
- bestRep = [NSBitmapImageRep imageRepWithData:[self TIFFRepresentation]];
-
- return bestRep;
-}
-
-- (NSData *)JPEGRepresentation
-{
- return [self JPEGRepresentationWithCompressionFactor:1.0f];
-}
-
-- (NSData *)JPEGRepresentationWithCompressionFactor:(float)compressionFactor
-{
- /* JPEG does not support transparency, but NSImage does. We need to create a non-transparent NSImage
- * before creating our representation or transparent parts will become black. White is preferable.
- */
- return ([[self opaqueBitmapImageRep] representationUsingType:NSJPEGFileType
- properties:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:(float)compressionFactor]
- forKey:NSImageCompressionFactor]]);
-}
-- (NSData *)JPEGRepresentationWithMaximumByteSize:(NSUInteger)maxByteSize
-{
- /* JPEG does not support transparency, but NSImage does. We need to create a non-transparent NSImage
- * before creating our representation or transparent parts will become black. White is preferable.
- */
- NSBitmapImageRep *opaqueBitmapImageRep = [self opaqueBitmapImageRep];
- NSData *data = nil;
- for (float compressionFactor = 0.99f; compressionFactor > 0.4f; compressionFactor -= 0.01f) {
- data = [opaqueBitmapImageRep representationUsingType:NSJPEGFileType
- properties:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:compressionFactor]
- forKey:NSImageCompressionFactor]];
- if (data && ([data length] <= maxByteSize)) {
- break;
- } else {
- data = nil;
- }
- }
-
- return data;
-}
-
-- (NSData *)PNGRepresentation
-{
- /* PNG is easy; it supports everything TIFF does, and NSImage's PNG support is great. */
- NSBitmapImageRep *bitmapRep = [self largestBitmapImageRep];
-
- return ([bitmapRep representationUsingType:NSPNGFileType properties:nil]);
-}
-
-- (NSData *)BMPRepresentation
-{
- /* BMP does not support transparency, but NSImage does. We need to create a non-transparent NSImage
- * before creating our representation or transparent parts will become black. White is preferable.
- */
-
- return ([[self opaqueBitmapImageRep] representationUsingType:NSBMPFileType properties:nil]);
-}
-
-- (NSBitmapImageRep *)getBitmap
-{
- [self lockFocus];
-
- NSSize size = [self size];
- NSRect rect = NSMakeRect(0.0f, 0.0f, size.width, size.height);
- NSBitmapImageRep *bm = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:rect] autorelease];
-
- [self unlockFocus];
-
- return bm;
-}
-
-//
-// NOTE: Black & White images fail miserably
-// So we must get their data and blast that into a deeper cache
-// Yucky, so we wrap this all up inside this object...
-- (NSBitmapImageRep *)bitmapRepForGIFRepresentation
-{
- NSArray *reps = [self representations];
- NSUInteger i = [reps count];
- while (i--) {
- NSBitmapImageRep *rep = (NSBitmapImageRep *)[reps objectAtIndex:i];
- if ([rep isKindOfClass:[NSBitmapImageRep class]] &&
- ([rep bitsPerPixel] > 2))
- return rep;
- }
- return [self getBitmap];
-}
-
-- (NSData *)GIFRepresentation
-{
- //This produces ugly output. Very ugly.
-
- NSData *GIFRepresentation = nil;
-
- NSBitmapImageRep *bm = [self bitmapRepForGIFRepresentation];
-
- if (bm) {
- NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES], NSImageDitherTransparency,
- nil];
-
- NSSize size = [self size];
-
- if (size.width > 0 && size.height > 0) {
-
- @try {
- GIFRepresentation = [bm representationUsingType:NSGIFFileType
- properties:properties];
- }
- @catch(id exc) {
- GIFRepresentation = nil; // must have failed
- }
- }
- }
-
- return GIFRepresentation;
-}
-
+ (AIBitmapImageFileType)fileTypeOfData:(NSData *)inData
{
const char *data = [inData bytes];
NSUInteger len = [inData length];
AIBitmapImageFileType fileType = AIUnknownFileType;
-
+
if (len >= 4) {
if (!strncmp((char *)data, "GIF8", 4))
fileType = AIGIFFileType;
@@ -265,6 +94,7 @@
+ (NSString *)extensionForBitmapImageFileType:(AIBitmapImageFileType)inFileType
{
NSString *extension = nil;
+
switch (inFileType) {
case AIUnknownFileType:
break;
@@ -291,6 +121,198 @@
return extension;
}
+// Create and return an opaque bitmap image rep, replacing transparency with [NSColor whiteColor]
+- (NSBitmapImageRep *)opaqueBitmapImageRep
+{
+ NSImage *tempImage = nil;
+ NSBitmapImageRep *imageRep = nil;
+ NSSize size = [self size];
+
+ // Work with a temporary image so we don't modify self
+ tempImage = [[[NSImage allocWithZone:[self zone]] initWithSize:size] autorelease];
+
+ // Lock before drawing to the temporary image
+ [tempImage lockFocus];
+
+ // Fill with a white background
+ [[NSColor whiteColor] set];
+ NSRectFill(NSMakeRect(0, 0, size.width, size.height));
+
+ // Draw the image
+ [self compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
+
+ // We're done drawing
+ [tempImage unlockFocus];
+
+ // Find an NSBitmapImageRep from the temporary image
+ for (NSImageRep *rep in tempImage.representations) {
+ if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
+ imageRep = (NSBitmapImageRep *)rep;
+ }
+ }
+
+ // Make one if necessary
+ if (!imageRep) {
+ imageRep = [NSBitmapImageRep imageRepWithData:[tempImage TIFFRepresentation]];
+ }
+
+ // 10.6 behavior: Drawing into a new image copies the display's color profile in.
+ // Remove the color profile so we don't bloat the image size.
+ [imageRep setProperty:NSImageColorSyncProfileData withValue:nil];
+
+ return imageRep;
+}
+
+- (NSBitmapImageRep *)largestBitmapImageRep
+{
+ // Find the biggest image
+ NSBitmapImageRep *bestRep = nil;
+ Class NSBitmapImageRepClass = [NSBitmapImageRep class];
+ CGFloat maxWidth = 0.0f;
+
+ for (NSImageRep *rep in [self representations]) {
+ if ([rep isKindOfClass:NSBitmapImageRepClass]) {
+ CGFloat thisWidth = [rep size].width;
+
+ if (thisWidth >= maxWidth) {
+ // Cast explanation: GCC warns about us returning an NSImageRep here, presumably because it could be some other kind of NSImageRep if we don't check the class.
+ // Fortunately, we have such a check. This cast silences the warning.
+ bestRep = (NSBitmapImageRep *)rep;
+ maxWidth = thisWidth;
+ }
+ }
+ }
+
+ // We don't already have one, so forge one from our TIFF representation.
+ if (!bestRep) {
+ bestRep = [NSBitmapImageRep imageRepWithData:[self TIFFRepresentation]];
+ }
+
+ return bestRep;
+}
+
+- (NSData *)JPEGRepresentation
+{
+ return [self JPEGRepresentationWithCompressionFactor:1.0f];
+}
+
+- (NSData *)JPEGRepresentationWithCompressionFactor:(float)compressionFactor
+{
+ /* JPEG does not support transparency, but NSImage does. We need to create a non-transparent NSImage
+ * before creating our representation or transparent parts will become black. White is preferable.
+ */
+ return ([[self opaqueBitmapImageRep] representationUsingType:NSJPEGFileType
+ properties:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:(float)compressionFactor]
+ forKey:NSImageCompressionFactor]]);
+}
+- (NSData *)JPEGRepresentationWithMaximumByteSize:(NSUInteger)maxByteSize
+{
+ /* JPEG does not support transparency, but NSImage does. We need to create a non-transparent NSImage
+ * before creating our representation or transparent parts will become black. White is preferable.
+ */
+ NSBitmapImageRep *opaqueBitmapImageRep = [self opaqueBitmapImageRep];
+ NSData *data = nil;
+
+ for (float compressionFactor = 0.99f; compressionFactor > 0.4f; compressionFactor -= 0.01f) {
+ data = [opaqueBitmapImageRep representationUsingType:NSJPEGFileType
+ properties:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:compressionFactor]
+ forKey:NSImageCompressionFactor]];
+ if (data && ([data length] <= maxByteSize)) {
+ break;
+ } else {
+ data = nil;
+ }
+ }
+
+ return data;
+}
+
+- (NSData *)PNGRepresentation
+{
+ /* PNG is easy; it supports everything TIFF does, and NSImage's PNG support is great. */
+ NSBitmapImageRep *bitmapRep = [self largestBitmapImageRep];
+
+ return ([bitmapRep representationUsingType:NSPNGFileType properties:nil]);
+}
+
+- (NSData *)GIFRepresentation
+{
+ // GIF requires special treatment, as Apple doesn't allow you to save animations.
+
+ NSMutableData *GIFRepresentation = nil;
+ NSBitmapImageRep *bitmap = [[self representations] objectAtIndex:0];
+
+ if (bitmap && [bitmap isKindOfClass:[NSBitmapImageRep class]]) {
+ unsigned frameCount = [[bitmap valueForProperty:NSImageFrameCount] intValue];
+
+ if (!frameCount) {
+ frameCount = 1;
+ }
+
+ NSSize size = [self size];
+
+ if (size.width > 0 && size.height > 0) {
+ NSMutableArray *images = [NSMutableArray array];
+
+ for (unsigned i = 0; i < frameCount; i++) {
+ // Set current frame
+ [bitmap setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithUnsignedInt:i]];
+ // Add frame representation
+ [images addObject:[NSBitmapImageRep imageRepWithData:[bitmap representationUsingType:NSGIFFileType properties:nil]]];
+ }
+
+ GIFRepresentation = [NSMutableData dataWithData:[NSBitmapImageRep representationOfImageRepsInArray:images
+ usingType:NSGIFFileType
+ properties:[self GIFPropertiesForRepresentation:bitmap]]];
+
+ // Write GIF Extension Blocks
+ [self writeGIFExtensionBlocksInData:GIFRepresentation forRepresenation:bitmap];
+ }
+ }
+
+ return GIFRepresentation;
+}
+
+- (NSData *)BMPRepresentation
+{
+ /* BMP does not support transparency, but NSImage does. We need to create a non-transparent NSImage
+ * before creating our representation or transparent parts will become black. White is preferable.
+ */
+
+ return ([[self opaqueBitmapImageRep] representationUsingType:NSBMPFileType properties:nil]);
+}
+
+/*!
+ * @brief Returns a GIF representation for GIFs, and PNG represenation for all other types
+ */
+- (NSData *)bestRepresentationByType
+{
+ NSData *data = nil;
+ NSBitmapImageRep *bitmap = nil;
+
+ if ((bitmap = [[self representations] objectAtIndex:0]) &&
+ [bitmap isKindOfClass:[NSBitmapImageRep class]] &&
+ ([[bitmap valueForProperty:NSImageFrameCount] intValue] > 1)) {
+ data = [self GIFRepresentation];
+ } else {
+ data = [self PNGRepresentation];
+ }
+
+ return data;
+}
+
+- (NSBitmapImageRep *)getBitmap
+{
+ [self lockFocus];
+
+ NSSize size = [self size];
+ NSRect rect = NSMakeRect(0.0f, 0.0f, size.width, size.height);
+ NSBitmapImageRep *bm = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:rect] autorelease];
+
+ [self unlockFocus];
+
+ return bm;
+}
/*!
* @brief Retrieve an image rep with a maximum size
@@ -302,8 +324,7 @@
*
* @return the NSData representation using fileType
*/
-- (NSData *)representationWithFileType:(NSBitmapImageFileType)fileType
- maximumFileSize:(NSUInteger)maximumSize
+- (NSData *)representationWithFileType:(NSBitmapImageFileType)fileType maximumFileSize:(NSUInteger)maximumSize
{
NSBitmapImageRep *imageRep = [self largestBitmapImageRep];
@@ -354,4 +375,56 @@
return data;
}
+- (void)writeGIFExtensionBlocksInData:(NSMutableData *)data forRepresenation:(NSBitmapImageRep *)bitmap
+{
+ // GIF Application Extension Block - 0x21FF0B
+ const char *GIFApplicationExtensionBlock = "\x21\xFF\x0B\x4E\x45\x54\x53\x43\x41\x50\x45\x32\x2E\x30\x03\x01\x00\x00\x00";
+ // GIF Graphic Control Extension Block - 0x21F904
+ NSData *GIFGraphicControlExtensionBlock = [NSData dataWithBytes:"\x00\x21\xF9\x04" length:4];
+
+ NSRange blockRange;
+ NSUInteger blockLocation = [data length];
+
+ unsigned frameCount = [[bitmap valueForProperty:NSImageFrameCount] intValue];
+ unsigned frameDuration;
+ unsigned i = 0;
+
+ while (!NSEqualRanges(blockRange = [data rangeOfData:GIFGraphicControlExtensionBlock options:NSDataSearchBackwards range:NSMakeRange(0, blockLocation)], NSMakeRange(NSNotFound, 0))) {
+ // Set current frame
+ [bitmap setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithUnsignedInt:i++]];
+
+ // Frame Duration flag, 1/100 sec
+ frameDuration = [[bitmap valueForProperty:NSImageCurrentFrameDuration] floatValue] * 100;
+
+ blockLocation = blockRange.location;
+
+ // Replace bytes in Graphic Extension Block
+ [data replaceBytesInRange:NSMakeRange(NSMaxRange(blockRange) + 1, 2) withBytes:&frameDuration length:2];
+
+ // Write Application Extension Block
+ if (i == frameCount) {
+ [data replaceBytesInRange:NSMakeRange(blockRange.location + 1, 0) withBytes:GIFApplicationExtensionBlock length:strlen(GIFApplicationExtensionBlock) + 3];
+ }
+
+ frameDuration = 0;
+ }
+}
+
+- (NSDictionary *)GIFPropertiesForRepresentation:(NSBitmapImageRep *)bitmap
+{
+ NSNumber *frameCount = [bitmap valueForProperty:NSImageFrameCount];
+
+ if (!frameCount) {
+ frameCount = [NSNumber numberWithUnsignedInt:1];
+ }
+
+ // Setting NSImageLoopCount & NSImageCurrentFrameDuration through - NSDictionary *properties - is not allowed!
+ return [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:frameCount,
+ [NSNumber numberWithUnsignedInt:0],
+ nil]
+ forKeys:[NSArray arrayWithObjects:NSImageFrameCount,
+ NSImageCurrentFrame,
+ nil]];
+}
+
@end
diff -r 6433a4fcfe52 -r 974e73ff45bb Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.h
--- a/Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.h Mon Mar 28 02:24:35 2011 +0300
+++ b/Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.h Mon Mar 28 03:28:39 2011 +0300
@@ -30,7 +30,8 @@
- (NSImage *)imageByScalingToSize:(NSSize)size fraction:(CGFloat)delta;
- (NSImage *)imageByScalingForMenuItem;
- (NSImage *)imageByScalingToSize:(NSSize)size fraction:(CGFloat)delta flipImage:(BOOL)flipImage proportionally:(BOOL)proportionally allowAnimation:(BOOL)allowAnimation;
-//+ (NSImage *)imageFromGWorld:(GWorldPtr)gWorldPtr;
+- (NSImage *)imageByFittingInSize:(NSSize)size;
+- (NSImage *)imageByFittingInSize:(NSSize)size fraction:(CGFloat)delta flipImage:(BOOL)flipImage proportionally:(BOOL)proportionally allowAnimation:(BOOL)allowAnimation;
- (NSRect)drawRoundedInRect:(NSRect)rect radius:(CGFloat)radius;
- (NSRect)drawRoundedInRect:(NSRect)rect fraction:(CGFloat)inFraction radius:(CGFloat)radius;
- (NSRect)drawRoundedInRect:(NSRect)rect atSize:(NSSize)size position:(IMAGE_POSITION)position fraction:(CGFloat)inFraction radius:(CGFloat)radius;
diff -r 6433a4fcfe52 -r 974e73ff45bb Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.m
--- a/Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.m Mon Mar 28 02:24:35 2011 +0300
+++ b/Frameworks/AIUtilities Framework/Source/AIImageDrawingAdditions.m Mon Mar 28 03:28:39 2011 +0300
@@ -15,11 +15,14 @@
*/
#import "AIImageDrawingAdditions.h"
+#import "AIImageAdditions.h"
#import "AIBezierPathAdditions.h"
+
@implementation NSImage (AIImageDrawingAdditions)
-//Draw this image in a rect, tiling if the rect is larger than the image
+
+// Draw this image in a rect, tiling if the rect is larger than the image
- (void)tileInRect:(NSRect)rect
{
NSSize size = [self size];
@@ -27,24 +30,26 @@
CGFloat top = rect.origin.y + rect.size.height;
CGFloat right = rect.origin.x + rect.size.width;
- //Tile vertically
+ // Tile vertically
while (destRect.origin.y < top) {
- //Tile horizontally
+ // Tile horizontally
while (destRect.origin.x < right) {
NSRect sourceRect = NSMakeRect(0, 0, size.width, size.height);
- //Crop as necessary
+ // Crop as necessary
if ((destRect.origin.x + destRect.size.width) > right) {
sourceRect.size.width -= (destRect.origin.x + destRect.size.width) - right;
}
+
if ((destRect.origin.y + destRect.size.height) > top) {
sourceRect.size.height -= (destRect.origin.y + destRect.size.height) - top;
}
- //Draw and shift
+ // Draw and shift
[self compositeToPoint:destRect.origin fromRect:sourceRect operation:NSCompositeSourceOver];
destRect.origin.x += destRect.size.width;
}
+
destRect.origin.y += destRect.size.height;
}
}
@@ -75,9 +80,9 @@
- (NSImage *)imageByScalingToSize:(NSSize)size fraction:(CGFloat)delta flipImage:(BOOL)flipImage proportionally:(BOOL)proportionally allowAnimation:(BOOL)allowAnimation
{
- NSSize originalSize = [self size];
+ NSSize originalSize = [self size];
- //Proceed only if size or delta are changing
+ // Proceed only if size or delta are changing
if ((NSEqualSizes(originalSize, size)) && (delta == 1.0) && !flipImage) {
return [[self copy] autorelease];
@@ -85,37 +90,75 @@
NSImage *newImage;
NSRect newRect;
- //Scale proportionally (rather than stretching to fit) if requested and needed
+ // Scale proportionally (rather than stretching to fit) if requested and needed
if (proportionally && (originalSize.width != originalSize.height)) {
if (originalSize.width > originalSize.height) {
- //Give width priority: Make the height change by the same proportion as the width will change
+ // Give width priority: Make the height change by the same proportion as the width will change
size.height = originalSize.height * (size.width / originalSize.width);
} else {
- //Give height priority: Make the width change by the same proportion as the height will change
+ // Give height priority: Make the width change by the same proportion as the height will change
size.width = originalSize.width * (size.height / originalSize.height);
}
}
- newRect = NSMakeRect(0,0,size.width,size.height);
+ newRect = NSMakeRect(0.0f, 0.0f, size.width, size.height);
newImage = [[NSImage alloc] initWithSize:size];
- if (flipImage) [newImage setFlipped:YES];
+ if (flipImage) {
+ [newImage setFlipped:YES];
+ }
- NSImageRep *bestRep;
+ NSImageRep *bestRep;
+
if (allowAnimation &&
- (bestRep = [self bestRepresentationForDevice:nil]) &&
+ (bestRep = [self bestRepresentationForRect:NSMakeRect(0, 0, self.size.width, self.size.height) context:nil hints:nil]) &&
[bestRep isKindOfClass:[NSBitmapImageRep class]] &&
(delta == 1.0) &&
([[(NSBitmapImageRep *)bestRep valueForProperty:NSImageFrameCount] intValue] > 1) ) {
- //We've got an animating file, and the current alpha is fine. Just copy the representation.
- [newImage addRepresentation:[[bestRep copy] autorelease]];
+ // We've got an animating file, and the current alpha is fine. Just copy the representation.
+ NSMutableData *GIFRepresentationData = nil;
+
+ unsigned frameCount = [[(NSBitmapImageRep *)bestRep valueForProperty:NSImageFrameCount] intValue];
+
+ if (!frameCount) {
+ frameCount = 1;
+ }
+
+ NSMutableArray *images = [NSMutableArray array];
+
+ for (unsigned i = 0; i < frameCount; i++) {
+ // Set current frame
+ [(NSBitmapImageRep *)bestRep setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithUnsignedInt:i]];
+
+ [newImage lockFocus];
+
+ [self drawInRect:newRect
+ fromRect:NSMakeRect(0.0f, 0.0f, originalSize.width, originalSize.height)
+ operation:NSCompositeCopy
+ fraction:delta];
+
+ [newImage unlockFocus];
+
+ // Add frame representation
+ [images addObject:[NSBitmapImageRep imageRepWithData:[newImage TIFFRepresentation]]];
+ }
+
+ GIFRepresentationData = [NSMutableData dataWithData:[NSBitmapImageRep representationOfImageRepsInArray:images
+ usingType:NSGIFFileType
+ properties:[self GIFPropertiesForRepresentation:(NSBitmapImageRep *)bestRep]]];
+
+ // Write GIF Extension Blocks
+ [self writeGIFExtensionBlocksInData:GIFRepresentationData forRepresenation:(NSBitmapImageRep *)bestRep];
+
+ newImage = [[NSImage alloc] initWithData:GIFRepresentationData];
} else {
[newImage lockFocus];
- //Highest quality interpolation
+ // Highest quality interpolation
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
+
[self drawInRect:newRect
- fromRect:NSMakeRect(0,0,originalSize.width,originalSize.height)
+ fromRect:NSMakeRect(0.0f, 0.0f, originalSize.width, originalSize.height)
operation:NSCompositeCopy
fraction:delta];
@@ -126,119 +169,176 @@
}
}
-/*+ (NSImage *)imageFromGWorld:(GWorldPtr)gworld
- {
- NSParameterAssert(gworld != NULL);
-
- PixMapHandle pixMapHandle = GetGWorldPixMap( gworld );
- if (LockPixels(pixMapHandle)) {
- Rect portRect;
-
- GetPortBounds( gworld, &portRect );
-
- int pixels_wide = (portRect.right - portRect.left);
- int pixels_high = (portRect.bottom - portRect.top);
- int bps = 8;
- int spp = 4;
- BOOL has_alpha = YES;
-
- NSBitmapImageRep *bitmap_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:pixels_wide
- pixelsHigh:pixels_high
- bitsPerSample:bps
- samplesPerPixel:spp
- hasAlpha:has_alpha
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:0
- bitsPerPixel:0] autorelease];
- CGColorSpaceRef dst_colorspaceref = CGColorSpaceCreateDeviceRGB();
- CGImageAlphaInfo dst_alphainfo = has_alpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone;
- CGContextRef dst_contextref = CGBitmapContextCreate([bitmap_rep bitmapData],
- pixels_wide,
- pixels_high,
- bps,
- [bitmap_rep bytesPerRow],
- dst_colorspaceref,
- dst_alphainfo);
- void *pixBaseAddr = GetPixBaseAddr(pixMapHandle);
- long pixmapRowBytes = GetPixRowBytes(pixMapHandle);
-
- CGDataProviderRef dataproviderref = CGDataProviderCreateWithData(NULL, pixBaseAddr, pixmapRowBytes * pixels_high, NULL);
-
- int src_bps = 8;
- int src_spp = 4;
- BOOL src_has_alpha = YES;
-
- CGColorSpaceRef src_colorspaceref = CGColorSpaceCreateDeviceRGB();
-
- CGImageAlphaInfo src_alphainfo = src_has_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNone;
-
- CGImageRef src_imageref = CGImageCreate(pixels_wide,
- pixels_high,
- src_bps,
- src_bps * src_spp,
- pixmapRowBytes,
- src_colorspaceref,
- src_alphainfo,
- dataproviderref,
- NULL,
- NO, // shouldInterpolate
- kCGRenderingIntentDefault);
-
- CGRect rect = CGRectMake(0, 0, pixels_wide, pixels_high);
-
- CGContextDrawImage(dst_contextref, rect, src_imageref);
-
- CGImageRelease(src_imageref);
- CGColorSpaceRelease(src_colorspaceref);
- CGDataProviderRelease(dataproviderref);
- CGContextRelease(dst_contextref);
- CGColorSpaceRelease(dst_colorspaceref);
-
- UnlockPixels(pixMapHandle);
-
- NSImage *image = [[[NSImage alloc] initWithSize:NSMakeSize(pixels_wide, pixels_high)] autorelease];
- [image addRepresentation:bitmap_rep];
- return image;
- }
- return nil;
- }*/
+- (NSImage *)imageByFittingInSize:(NSSize)size
+{
+ return ([self imageByFittingInSize:size fraction:1.0f flipImage:NO proportionally:YES allowAnimation:YES]);
+}
-//Fun drawing toys
-//Draw an image, altering and returning the available destination rect
+- (NSImage *)imageByFittingInSize:(NSSize)size fraction:(CGFloat)delta flipImage:(BOOL)flipImage proportionally:(BOOL)proportionally allowAnimation:(BOOL)allowAnimation
+{
+ NSSize originalSize = [self size];
+ NSSize scaleSize = size;
+ NSSize fitSize = size;
+
+ // Proceed only if size or delta are changing
+ if ((NSEqualSizes(originalSize, size)) && (delta == 1.0) && !flipImage) {
+ return [[self copy] autorelease];
+
+ } else {
+ // Scale proportionally (rather than stretching to fit) if requested and needed
+ if (proportionally && (originalSize.width != originalSize.height)) {
+ if (originalSize.width > originalSize.height) {
+ // Give width priority: Make the height change by the same proportion as the width will change
+ scaleSize.height = originalSize.height * (size.width / originalSize.width);
+ } else {
+ // Give height priority: Make the width change by the same proportion as the height will change
+ scaleSize.width = originalSize.width * (size.height / originalSize.height);
+ }
+ }
+
+ // Fit
+ if (proportionally && (originalSize.width != originalSize.height)) {
+ if (originalSize.width > originalSize.height) {
+ // Give width priority: Make the height change by the same proportion as the width will change
+ fitSize.height = originalSize.height * (size.width / originalSize.width);
+ } else {
+ // Give height priority: Make the width change by the same proportion as the height will change
+ fitSize.width = originalSize.width * (size.height / originalSize.height);
+ }
+ }
+
+ NSRect scaleRect = NSMakeRect(0.0f, 0.0f, scaleSize.width, scaleSize.height);
+ NSPoint fitFromPoint = NSMakePoint((size.width - scaleSize.width) / 2.0f, (size.height - scaleSize.height) / 2.0f);
+
+ NSImage *newImage = [[NSImage alloc] initWithSize:size];
+ NSImage *scaledImage = [[NSImage alloc] initWithSize:scaleSize];
+
+ if (flipImage) {
+ [newImage setFlipped:YES];
+ }
+
+ NSImageRep *bestRep;
+
+ if (allowAnimation &&
+ (bestRep = [self bestRepresentationForRect:NSMakeRect(0, 0, self.size.width, self.size.height) context:nil hints:nil]) &&
+ [bestRep isKindOfClass:[NSBitmapImageRep class]] &&
+ (delta == 1.0) &&
+ ([[(NSBitmapImageRep *)bestRep valueForProperty:NSImageFrameCount] intValue] > 1) ) {
+
+ // We've got an animating file, and the current alpha is fine. Just copy the representation.
+ NSMutableData *GIFRepresentationData = nil;
+
+ unsigned frameCount = [[(NSBitmapImageRep *)bestRep valueForProperty:NSImageFrameCount] intValue];
+
+ if (!frameCount) {
+ frameCount = 1;
+ }
+
+ NSMutableArray *images = [NSMutableArray array];
+
+ for (unsigned i = 0; i < frameCount; i++) {
+ // Set current frame
+ [(NSBitmapImageRep *)bestRep setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithUnsignedInt:i]];
+
+ [scaledImage lockFocus];
+
+ // Scale
+ [self drawInRect:scaleRect
+ fromRect:NSMakeRect(0.0f, 0.0f, originalSize.width, originalSize.height)
+ operation:NSCompositeCopy
+ fraction:delta];
+
+ [scaledImage unlockFocus];
+ [newImage lockFocus];
+
+ // Fit
+ [scaledImage drawAtPoint:fitFromPoint
+ fromRect:NSMakeRect(0.0f, 0.0f, newImage.size.width, newImage.size.height)
+ operation:NSCompositeCopy
+ fraction:delta];
+
+ [newImage unlockFocus];
+
+ // Add frame representation
+ [images addObject:[NSBitmapImageRep imageRepWithData:[newImage TIFFRepresentation]]];
+ }
+
+ GIFRepresentationData = [NSMutableData dataWithData:[NSBitmapImageRep representationOfImageRepsInArray:images
+ usingType:NSGIFFileType
+ properties:[self GIFPropertiesForRepresentation:(NSBitmapImageRep *)bestRep]]];
+
+ // Write GIF Extension Blocks
+ [self writeGIFExtensionBlocksInData:GIFRepresentationData forRepresenation:(NSBitmapImageRep *)bestRep];
+
+ newImage = [[NSImage alloc] initWithData:GIFRepresentationData];
+ } else {
+ [scaledImage lockFocus];
+ // Highest quality interpolation
+ [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
+
+ // Scale
+ [self drawInRect:scaleRect
+ fromRect:NSMakeRect(0.0f, 0.0f, originalSize.width, originalSize.height)
+ operation:NSCompositeCopy
+ fraction:delta];
+
+ [scaledImage unlockFocus];
+ [newImage lockFocus];
+
+ // Fit
+ [scaledImage drawAtPoint:fitFromPoint
+ fromRect:NSMakeRect(0.0f, 0.0f, newImage.size.width, newImage.size.height)
+ operation:NSCompositeCopy
+ fraction:delta];
+
More information about the commits
mailing list