2001-12-17 16:51:51 +00:00
|
|
|
/** <title>NSImage</title>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
<abstract>Load, manipulate and display images</abstract>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
Copyright (C) 1996, 2005 Free Software Foundation, Inc.
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
Author: Adam Fedor <fedor@colorado.edu>
|
1996-08-22 18:51:08 +00:00
|
|
|
Date: Feb 1996
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
You should have received a copy of the GNU Library General Public
|
1996-10-18 17:14:13 +00:00
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, write to the Free Software Foundation,
|
2005-05-26 02:52:46 +00:00
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1996-08-22 18:51:08 +00:00
|
|
|
*/
|
2003-07-31 23:52:10 +00:00
|
|
|
#include "config.h"
|
1997-02-18 00:29:25 +00:00
|
|
|
#include <string.h>
|
2005-01-24 23:28:07 +00:00
|
|
|
#include <math.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
|
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSBundle.h>
|
2001-07-30 21:30:51 +00:00
|
|
|
#include <Foundation/NSDebug.h>
|
2004-10-10 22:36:02 +00:00
|
|
|
#include <Foundation/NSDictionary.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSFileManager.h>
|
|
|
|
#include <Foundation/NSKeyedArchiver.h>
|
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSValue.h>
|
1997-08-27 21:20:19 +00:00
|
|
|
|
2003-06-13 15:01:12 +00:00
|
|
|
#include "AppKit/NSImage.h"
|
2005-01-24 23:28:07 +00:00
|
|
|
|
2003-06-13 15:01:12 +00:00
|
|
|
#include "AppKit/AppKitExceptions.h"
|
2005-01-24 23:28:07 +00:00
|
|
|
#include "AppKit/NSAffineTransform.h"
|
2003-06-13 15:01:12 +00:00
|
|
|
#include "AppKit/NSBitmapImageRep.h"
|
|
|
|
#include "AppKit/NSCachedImageRep.h"
|
|
|
|
#include "AppKit/NSColor.h"
|
|
|
|
#include "AppKit/NSPasteboard.h"
|
|
|
|
#include "AppKit/NSPrintOperation.h"
|
2005-01-24 23:28:07 +00:00
|
|
|
#include "AppKit/NSScreen.h"
|
|
|
|
#include "AppKit/NSView.h"
|
|
|
|
#include "AppKit/NSWindow.h"
|
2003-06-13 15:01:12 +00:00
|
|
|
#include "AppKit/PSOperators.h"
|
2003-07-31 23:52:10 +00:00
|
|
|
#include "GNUstepGUI/GSDisplayServer.h"
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
/* Helpers. Would be nicer to use the C99 fmin/fmax functions, but that
|
|
|
|
isn't currently possible. */
|
2005-02-03 09:47:38 +00:00
|
|
|
static double gs_min(double x, double y)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
|
|
|
if (x > y)
|
|
|
|
return y;
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
2005-02-03 09:47:38 +00:00
|
|
|
static double gs_max(double x, double y)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
|
|
|
if (x < y)
|
|
|
|
return y;
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-12-02 10:38:18 +00:00
|
|
|
BOOL NSImageForceCaching = NO; /* use on missmatch */
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2002-09-25 22:55:44 +00:00
|
|
|
@implementation NSBundle (NSImageAdditions)
|
|
|
|
|
|
|
|
- (NSString*) pathForImageResource: (NSString*)name
|
|
|
|
{
|
|
|
|
NSString *ext = [name pathExtension];
|
|
|
|
NSString *path = nil;
|
|
|
|
|
|
|
|
if ((ext == nil) || [ext isEqualToString:@""])
|
|
|
|
{
|
|
|
|
NSArray *types = [NSImage imageUnfilteredFileTypes];
|
|
|
|
unsigned c = [types count];
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; path == nil && i < c; i++)
|
|
|
|
{
|
|
|
|
ext = [types objectAtIndex: i];
|
|
|
|
path = [self pathForResource: name ofType: ext];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = [name stringByDeletingPathExtension];
|
|
|
|
path = [self pathForResource: name ofType: ext];
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
@interface GSRepData : NSObject
|
|
|
|
{
|
|
|
|
@public
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSImageRep *original;
|
|
|
|
NSColor *bg;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation GSRepData
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
GSRepData *c = (GSRepData*)NSCopyObject(self, 0, z);
|
|
|
|
|
|
|
|
if (c->rep)
|
2000-12-23 14:19:23 +00:00
|
|
|
c->rep = [c->rep copyWithZone: z];
|
1999-04-28 11:16:26 +00:00
|
|
|
if (c->bg)
|
2000-12-23 14:19:23 +00:00
|
|
|
c->bg = [c->bg copyWithZone: z];
|
1999-04-28 11:16:26 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
TEST_RELEASE(rep);
|
|
|
|
TEST_RELEASE(bg);
|
1999-04-28 11:16:26 +00:00
|
|
|
NSDeallocateObject(self);
|
2006-09-03 16:41:10 +00:00
|
|
|
GSNOSUPERDEALLOC;
|
1999-04-28 11:16:26 +00:00
|
|
|
}
|
|
|
|
@end
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
/* Class variables and functions for class methods */
|
|
|
|
static NSMutableDictionary *nameDict = nil;
|
|
|
|
static NSDictionary *nsmapping = nil;
|
|
|
|
static NSColor *clearColor = nil;
|
|
|
|
static Class cachedClass = 0;
|
|
|
|
static Class bitmapClass = 0;
|
|
|
|
|
2003-10-30 00:23:23 +00:00
|
|
|
static NSArray *iterate_reps_for_types(NSArray *imageReps, SEL method);
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
/* Find the GSRepData object holding a representation */
|
2003-10-30 00:23:23 +00:00
|
|
|
static GSRepData*
|
1996-08-22 18:51:08 +00:00
|
|
|
repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|
|
|
{
|
1999-12-02 10:35:07 +00:00
|
|
|
NSEnumerator *enumerator = [_reps objectEnumerator];
|
|
|
|
IMP nextImp = [enumerator methodForSelector: @selector(nextObject)];
|
1999-04-28 11:16:26 +00:00
|
|
|
GSRepData *repd;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1999-12-02 10:35:07 +00:00
|
|
|
while ((repd = (*nextImp)(enumerator, @selector(nextObject))) != nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
if (repd->rep == rep)
|
1999-12-02 10:35:07 +00:00
|
|
|
{
|
|
|
|
return repd;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
1999-12-02 10:35:07 +00:00
|
|
|
format: @"Cannot find stored representation"];
|
1996-08-22 18:51:08 +00:00
|
|
|
/* NOT REACHED */
|
1999-04-28 11:16:26 +00:00
|
|
|
return nil;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@interface NSImage (Private)
|
2000-12-23 14:19:23 +00:00
|
|
|
- (BOOL) _useFromFile: (NSString *)fileName;
|
|
|
|
- (BOOL) _loadFromData: (NSData *)data;
|
|
|
|
- (BOOL) _loadFromFile: (NSString *)fileName;
|
|
|
|
- (NSImageRep*) _cacheForRep: (NSImageRep*)rep;
|
|
|
|
- (NSImageRep*) _doImageCache;
|
1996-08-22 18:51:08 +00:00
|
|
|
@end
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
@implementation NSImage
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
+ (void) initialize
|
1997-03-05 01:11:17 +00:00
|
|
|
{
|
|
|
|
if (self == [NSImage class])
|
|
|
|
{
|
2003-04-28 02:33:10 +00:00
|
|
|
NSString *path = [NSBundle pathForLibraryResource: @"nsmapping"
|
|
|
|
ofType: @"strings"
|
|
|
|
inDirectory: @"Images"];
|
2001-12-02 11:45:01 +00:00
|
|
|
|
1997-03-05 01:11:17 +00:00
|
|
|
// Initial version
|
1999-03-30 13:59:35 +00:00
|
|
|
[self setVersion: 1];
|
1997-03-05 01:11:17 +00:00
|
|
|
|
|
|
|
// initialize the class variables
|
|
|
|
nameDict = [[NSMutableDictionary alloc] initWithCapacity: 10];
|
1997-12-04 01:58:57 +00:00
|
|
|
if (path)
|
1999-12-01 13:49:47 +00:00
|
|
|
nsmapping = RETAIN([[NSString stringWithContentsOfFile: path]
|
|
|
|
propertyListFromStringsFileFormat]);
|
|
|
|
clearColor = RETAIN([NSColor clearColor]);
|
2000-12-23 14:19:23 +00:00
|
|
|
cachedClass = [NSCachedImageRep class];
|
|
|
|
bitmapClass = [NSBitmapImageRep class];
|
1997-03-05 01:11:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Returns the NSImage named aName. The search is done in the main bundle
|
|
|
|
first and then in the usual images directories</p>
|
|
|
|
*/
|
1999-12-01 13:49:47 +00:00
|
|
|
+ (id) imageNamed: (NSString *)aName
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
NSString *realName = [nsmapping objectForKey: aName];
|
2000-12-23 14:19:23 +00:00
|
|
|
NSImage *image;
|
1997-12-04 01:58:57 +00:00
|
|
|
|
|
|
|
if (realName)
|
|
|
|
aName = realName;
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
image = (NSImage*)[nameDict objectForKey: aName];
|
|
|
|
|
|
|
|
if (image == nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-10-20 04:19:22 +00:00
|
|
|
NSString *ext;
|
|
|
|
NSString *path = nil;
|
|
|
|
NSBundle *main_bundle;
|
|
|
|
NSArray *array;
|
|
|
|
NSString *the_name = aName;
|
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
// FIXME: This should use [NSBundle pathForImageResource], but this will
|
|
|
|
// only allow imageUnfilteredFileTypes.
|
2000-12-23 14:19:23 +00:00
|
|
|
/* If there is no image with that name, search in the main bundle */
|
1999-10-29 18:43:48 +00:00
|
|
|
main_bundle = [NSBundle mainBundle];
|
2000-10-20 04:19:22 +00:00
|
|
|
ext = [aName pathExtension];
|
|
|
|
if (ext != nil && [ext length] == 0)
|
|
|
|
{
|
|
|
|
ext = nil;
|
|
|
|
}
|
1997-03-20 19:23:21 +00:00
|
|
|
|
|
|
|
/* Check if extension is one of the image types */
|
|
|
|
array = [self imageFileTypes];
|
|
|
|
if ([array indexOfObject: ext] != NSNotFound)
|
|
|
|
{
|
|
|
|
/* Extension is one of the image types
|
|
|
|
So remove from the name */
|
|
|
|
the_name = [aName stringByDeletingPathExtension];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise extension is not an image type
|
|
|
|
So leave it alone */
|
|
|
|
the_name = aName;
|
|
|
|
ext = nil;
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
|
|
|
|
/* First search locally */
|
1996-08-22 18:51:08 +00:00
|
|
|
if (ext)
|
1999-10-29 18:43:48 +00:00
|
|
|
path = [main_bundle pathForResource: the_name ofType: ext];
|
1996-08-22 18:51:08 +00:00
|
|
|
else
|
|
|
|
{
|
1997-01-31 13:40:15 +00:00
|
|
|
id o, e;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1997-01-31 13:40:15 +00:00
|
|
|
e = [array objectEnumerator];
|
|
|
|
while ((o = [e nextObject]))
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-10-29 18:43:48 +00:00
|
|
|
path = [main_bundle pathForResource: the_name
|
1997-01-31 13:40:15 +00:00
|
|
|
ofType: o];
|
1999-05-06 19:36:54 +00:00
|
|
|
if (path != nil && [path length] != 0)
|
1996-08-22 18:51:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
|
|
|
|
/* If not found then search in system */
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
if (ext)
|
2001-12-02 11:45:01 +00:00
|
|
|
{
|
2003-04-28 02:33:10 +00:00
|
|
|
path = [NSBundle pathForLibraryResource: the_name
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"Images"];
|
2001-12-02 11:45:01 +00:00
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
else
|
|
|
|
{
|
2001-12-02 11:45:01 +00:00
|
|
|
id o, e;
|
|
|
|
|
|
|
|
e = [array objectEnumerator];
|
|
|
|
while ((o = [e nextObject]))
|
|
|
|
{
|
2003-04-28 02:33:10 +00:00
|
|
|
path = [NSBundle pathForLibraryResource: the_name
|
|
|
|
ofType: o
|
|
|
|
inDirectory: @"Images"];
|
2001-12-02 11:45:01 +00:00
|
|
|
if (path != nil && [path length] != 0)
|
|
|
|
break;
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
if ([path length] != 0)
|
|
|
|
{
|
1999-03-22 13:46:09 +00:00
|
|
|
image = [[self allocWithZone: NSDefaultMallocZone()]
|
1999-04-28 11:16:26 +00:00
|
|
|
initByReferencingFile: path];
|
1999-12-28 16:02:01 +00:00
|
|
|
if (image != nil)
|
1999-03-22 13:46:09 +00:00
|
|
|
{
|
|
|
|
[image setName: aName];
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(image); // Retained in dictionary.
|
1999-12-28 16:02:01 +00:00
|
|
|
image->_flags.archiveByName = YES;
|
1999-03-22 13:46:09 +00:00
|
|
|
}
|
|
|
|
return image;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
return image;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2004-10-30 11:19:07 +00:00
|
|
|
+ (NSImage *) _standardImageWithName: (NSString *)name
|
|
|
|
{
|
|
|
|
NSImage *image = nil;
|
|
|
|
|
|
|
|
image = [NSImage imageNamed: name];
|
|
|
|
if (image == nil)
|
|
|
|
image = [NSImage imageNamed: [@"common_" stringByAppendingString: name]];
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
return [self initWithSize: NSMakeSize(0, 0)];
|
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Initialize and returns a new NSImage with <var>aSize</var> as specified
|
|
|
|
size.</p><p>See Also: -setSize: -size </p>
|
|
|
|
*/
|
1999-12-01 13:49:47 +00:00
|
|
|
- (id) initWithSize: (NSSize)aSize
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
|
|
|
[super init];
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
//_flags.archiveByName = NO;
|
|
|
|
//_flags.scalable = NO;
|
|
|
|
//_flags.dataRetained = NO;
|
|
|
|
//_flags.flipDraw = NO;
|
1996-08-22 18:51:08 +00:00
|
|
|
if (aSize.width && aSize.height)
|
|
|
|
{
|
2002-02-25 17:39:11 +00:00
|
|
|
_size = aSize;
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.sizeWasExplicitlySet = YES;
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
//_flags.usesEPSOnResolutionMismatch = NO;
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.colorMatchPreferred = YES;
|
|
|
|
_flags.multipleResolutionMatching = YES;
|
2001-08-11 18:34:22 +00:00
|
|
|
//_flags.cacheSeparately = NO;
|
|
|
|
//_flags.unboundedCacheDepth = NO;
|
|
|
|
//_flags.syncLoad = NO;
|
|
|
|
_reps = [[NSMutableArray alloc] initWithCapacity: 2];
|
|
|
|
ASSIGN(_color, clearColor);
|
2003-01-21 05:08:26 +00:00
|
|
|
_cacheMode = NSImageCacheDefault;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-03-26 15:59:01 +00:00
|
|
|
- (id) initByReferencingFile: (NSString *)fileName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
self = [self init];
|
2001-08-11 18:34:22 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _useFromFile: fileName])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2001-09-16 19:44:11 +00:00
|
|
|
_flags.archiveByName = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
|
|
|
|
/** <p>Initializes and returns a new NSImage from the file
|
|
|
|
<var>fileName</var>. <var>fileName</var> should be an absolute path.</p>
|
|
|
|
<p>See Also: [NSImageRep+imageRepsWithContentsOfFile:]</p>
|
|
|
|
*/
|
1999-03-26 15:59:01 +00:00
|
|
|
- (id) initWithContentsOfFile: (NSString *)fileName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-11-24 13:48:41 +00:00
|
|
|
if ( ! ( self = [self init] ) )
|
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _loadFromFile: fileName])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2006-11-17 11:07:43 +00:00
|
|
|
/**
|
|
|
|
* <p>Initializes and returns a new NSImage from the NSData data.</p>
|
|
|
|
* <p>See Also: [NSBitmapImageRep+imageRepWithData:] or
|
|
|
|
* [NSEPSImageRep+imageRepWithData:]</p>
|
2005-11-24 13:48:41 +00:00
|
|
|
*/
|
2001-12-17 16:51:51 +00:00
|
|
|
- (id) initWithData: (NSData *)data
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-11-24 13:48:41 +00:00
|
|
|
if (! ( self = [self init] ) )
|
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _loadFromData: data])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id)initWithBitmapHandle:(void *)bitmap
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2000-12-24 14:05:12 +00:00
|
|
|
NSImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapHandle: bitmap];
|
|
|
|
|
|
|
|
if (rep == nil)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
self = [self init];
|
|
|
|
[self addRepresentation: rep];
|
2003-07-25 22:14:40 +00:00
|
|
|
RELEASE(rep);
|
2000-12-24 14:05:12 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id)initWithIconHandle:(void *)icon
|
|
|
|
{
|
|
|
|
// Only needed on MS Windows
|
2000-12-24 14:05:12 +00:00
|
|
|
NSImageRep *rep = [[NSBitmapImageRep alloc] initWithIconHandle: icon];
|
|
|
|
|
|
|
|
if (rep == nil)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
self = [self init];
|
|
|
|
[self addRepresentation: rep];
|
2003-07-25 22:14:40 +00:00
|
|
|
RELEASE(rep);
|
2000-12-24 14:05:12 +00:00
|
|
|
return self;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithContentsOfURL:(NSURL *)anURL
|
|
|
|
{
|
2000-12-24 14:05:12 +00:00
|
|
|
NSArray *array = [NSImageRep imageRepsWithContentsOfURL: anURL];
|
|
|
|
|
|
|
|
if (!array)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
self = [self init];
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.dataRetained = YES;
|
2000-12-24 14:05:12 +00:00
|
|
|
[self addRepresentations: array];
|
|
|
|
return self;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Initializes and returns a new NSImage from the data in pasteboard.
|
|
|
|
the pasteboard types can be whose defined in
|
|
|
|
[NSImageRep+imagePasteboardTypes] or NSFilenamesPboardType</p>
|
|
|
|
<p>See Also: [NSImageRep+imageRepsWithPasteboard:</p>
|
|
|
|
*/
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id) initWithPasteboard: (NSPasteboard *)pasteboard
|
|
|
|
{
|
2005-11-24 13:48:41 +00:00
|
|
|
NSArray *reps;
|
|
|
|
|
|
|
|
if ( ! ( self = [self init] ) )
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
reps = [NSImageRep imageRepsWithPasteboard: pasteboard];
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
if (reps != nil)
|
|
|
|
[self addRepresentations: reps];
|
|
|
|
else
|
|
|
|
{
|
2003-06-24 22:57:12 +00:00
|
|
|
NSArray *array = [pasteboard propertyListForType: NSFilenamesPboardType];
|
|
|
|
NSString* file;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2003-06-24 22:57:12 +00:00
|
|
|
if ((array == nil) || ([array count] == 0) ||
|
|
|
|
(file = [array objectAtIndex: 0]) == nil ||
|
|
|
|
![self _loadFromFile: file])
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) dealloc
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(_reps);
|
1996-08-22 18:51:08 +00:00
|
|
|
/* Make sure we don't remove name from the nameDict if we are just a copy
|
|
|
|
of the named image, not the original image */
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_name && self == [nameDict objectForKey: _name])
|
|
|
|
[nameDict removeObjectForKey: _name];
|
|
|
|
RELEASE(_name);
|
|
|
|
TEST_RELEASE(_fileName);
|
|
|
|
RELEASE(_color);
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
[super dealloc];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (id) copyWithZone: (NSZone *)zone
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
NSImage *copy;
|
2000-12-24 14:05:12 +00:00
|
|
|
NSArray *reps = [self representations];
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
NSImageRep *rep;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1997-07-07 16:56:52 +00:00
|
|
|
copy = (NSImage*)NSCopyObject (self, 0, zone);
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
RETAIN(_name);
|
|
|
|
RETAIN(_fileName);
|
1999-12-01 13:49:47 +00:00
|
|
|
RETAIN(_color);
|
2000-12-23 14:19:23 +00:00
|
|
|
copy->_lockedView = nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
// FIXME: maybe we should retain if _flags.dataRetained = NO
|
2000-12-24 14:05:12 +00:00
|
|
|
copy->_reps = [[NSMutableArray alloc] initWithCapacity: [_reps count]];
|
|
|
|
|
|
|
|
// Only copy non-cached reps.
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if (![rep isKindOfClass: cachedClass])
|
|
|
|
{
|
|
|
|
[copy addRepresentation: rep];
|
|
|
|
}
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2002-04-03 16:59:43 +00:00
|
|
|
- (BOOL) setName: (NSString *)aName
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2001-08-13 11:07:39 +00:00
|
|
|
BOOL retained = NO;
|
|
|
|
|
2002-04-03 16:59:43 +00:00
|
|
|
if (!aName || [nameDict objectForKey: aName])
|
1996-08-22 18:51:08 +00:00
|
|
|
return NO;
|
1997-02-18 00:29:25 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
if (_name && self == [nameDict objectForKey: _name])
|
2001-08-13 11:07:39 +00:00
|
|
|
{
|
|
|
|
/* We retain self in case removing from the dictionary releases
|
|
|
|
us */
|
|
|
|
RETAIN (self);
|
|
|
|
retained = YES;
|
|
|
|
[nameDict removeObjectForKey: _name];
|
|
|
|
}
|
|
|
|
|
2002-04-03 16:59:43 +00:00
|
|
|
ASSIGN(_name, aName);
|
2001-08-13 11:07:39 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
[nameDict setObject: self forKey: _name];
|
2001-08-13 11:07:39 +00:00
|
|
|
if (retained)
|
|
|
|
{
|
|
|
|
RELEASE (self);
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return YES;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (NSString *) name
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
return _name;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Sets the NSImage size to aSize. Changing the size recreate
|
|
|
|
the cache</p>
|
|
|
|
<p>See Also: -size -initWithSize:</p>
|
|
|
|
*/
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) setSize: (NSSize)aSize
|
|
|
|
{
|
2002-02-26 14:37:55 +00:00
|
|
|
// Optimized as this is called very often from NSImageCell
|
|
|
|
if (NSEqualSizes(_size, aSize))
|
|
|
|
return;
|
|
|
|
|
2002-02-25 17:39:11 +00:00
|
|
|
_size = aSize;
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.sizeWasExplicitlySet = YES;
|
2002-02-26 14:37:55 +00:00
|
|
|
|
|
|
|
[self recache];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/**<p> Returns NSImage size if the size have been set. Returns the
|
|
|
|
size of the best representation otherwise.</p>
|
|
|
|
<p>See Also: -setSize: -initWithSize:</p>
|
|
|
|
*/
|
2001-08-11 18:34:22 +00:00
|
|
|
- (NSSize) size
|
|
|
|
{
|
|
|
|
if (_size.width == 0)
|
|
|
|
{
|
|
|
|
NSImageRep *rep = [self bestRepresentationForDevice: nil];
|
|
|
|
|
2004-05-26 23:42:48 +00:00
|
|
|
if (rep)
|
|
|
|
_size = [rep size];
|
|
|
|
else
|
|
|
|
_size = NSZeroSize;
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
return _size;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isFlipped
|
|
|
|
{
|
|
|
|
return _flags.flipDraw;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setFlipped: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.flipDraw = flag;
|
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
// Choosing Which Image Representation to Use
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setUsesEPSOnResolutionMismatch: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.useEPSOnResolutionMismatch = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) usesEPSOnResolutionMismatch
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.useEPSOnResolutionMismatch;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setPrefersColorMatch: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.colorMatchPreferred = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) prefersColorMatch
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.colorMatchPreferred;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setMatchesOnMultipleResolution: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.multipleResolutionMatching = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) matchesOnMultipleResolution
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
|
|
|
return _flags.multipleResolutionMatching;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
// Determining How the Image is Stored
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setCachedSeparately: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.cacheSeparately = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isCachedSeparately
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.cacheSeparately;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setDataRetained: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.dataRetained = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isDataRetained
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.dataRetained;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setCacheDepthMatchesImageDepth: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.unboundedCacheDepth = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) cacheDepthMatchesImageDepth
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.unboundedCacheDepth;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (void) setCacheMode: (NSImageCacheMode)mode
|
|
|
|
{
|
|
|
|
_cacheMode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSImageCacheMode) cacheMode
|
|
|
|
{
|
|
|
|
return _cacheMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
// Determining How the Image is Drawn
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isValid
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
BOOL valid = NO;
|
|
|
|
unsigned i, count;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
/* Go through all our representations and determine if at least one
|
|
|
|
is a valid cache */
|
|
|
|
// FIXME: Not sure if this is correct
|
|
|
|
count = [_reps count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
GSRepData *repd = (GSRepData*)[_reps objectAtIndex: i];
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (repd->bg != nil || [repd->rep isKindOfClass: cachedClass] == NO)
|
1999-12-01 13:49:47 +00:00
|
|
|
{
|
|
|
|
valid = YES;
|
|
|
|
break;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) recache
|
|
|
|
{
|
2002-03-28 03:53:18 +00:00
|
|
|
unsigned i;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2002-02-26 14:37:55 +00:00
|
|
|
i = [_reps count];
|
2005-11-16 11:34:25 +00:00
|
|
|
while (i--)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
GSRepData *repd;
|
|
|
|
|
|
|
|
repd = (GSRepData*)[_reps objectAtIndex: i];
|
2002-02-26 14:37:55 +00:00
|
|
|
if (repd->original != nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
{
|
2002-02-26 14:37:55 +00:00
|
|
|
[_reps removeObjectAtIndex: i];
|
1999-04-28 11:16:26 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setScalesWhenResized: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.scalable = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
- (BOOL) scalesWhenResized
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.scalable;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/**<p>Sets the color of the NSImage's background to <var>aColor</var></p>
|
|
|
|
<p>See Also: -backgroundColor</p>
|
|
|
|
*/
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setBackgroundColor: (NSColor *)aColor
|
|
|
|
{
|
1999-12-02 10:35:07 +00:00
|
|
|
if (aColor == nil)
|
|
|
|
{
|
|
|
|
aColor = clearColor;
|
|
|
|
}
|
1999-12-01 13:49:47 +00:00
|
|
|
ASSIGN(_color, aColor);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/**<p>Returns the color of the NSImage's background</p>
|
|
|
|
<p>See Also: -setBackgroundColor:</p>
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
- (NSColor *) backgroundColor
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _color;
|
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
// Using the Image
|
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2001-12-17 16:51:51 +00:00
|
|
|
operation: (NSCompositingOperation)op
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
NSRect rect;
|
2000-12-23 14:19:23 +00:00
|
|
|
// Might not be computed up to now
|
|
|
|
NSSize size = [self size];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
rect = NSMakeRect(0, 0, size.width, size.height);
|
1999-03-30 13:59:35 +00:00
|
|
|
[self compositeToPoint: aPoint fromRect: rect operation: op];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
|
|
|
fromRect: (NSRect)aRect
|
2001-12-17 16:51:51 +00:00
|
|
|
operation: (NSCompositingOperation)op
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
#if 0
|
|
|
|
[self compositeToPoint: aPoint
|
|
|
|
fromRect: aRect
|
|
|
|
operation: op
|
|
|
|
fraction: 1.0];
|
|
|
|
#else
|
2003-01-21 05:08:26 +00:00
|
|
|
NSImageRep *rep = nil;
|
1997-01-31 20:14:40 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
NS_DURING
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == YES)
|
|
|
|
rep = [self _doImageCache];
|
|
|
|
if (rep
|
|
|
|
&&_cacheMode != NSImageCacheNever
|
|
|
|
&& [rep isKindOfClass: cachedClass])
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
NSRect rect;
|
2000-12-23 14:19:23 +00:00
|
|
|
float y = aPoint.y;
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
rect = [(NSCachedImageRep *)rep rect];
|
2002-02-26 14:37:55 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"composite rect %@ in %@",
|
|
|
|
NSStringFromRect(rect), NSStringFromRect(aRect));
|
2001-07-09 02:49:03 +00:00
|
|
|
// Move the drawing rectangle to the origin of the image rep
|
|
|
|
// and intersect the two rects.
|
|
|
|
aRect.origin.x += rect.origin.x;
|
|
|
|
aRect.origin.y += rect.origin.y;
|
2001-04-14 20:06:13 +00:00
|
|
|
rect = NSIntersectionRect(aRect, rect);
|
2002-01-29 15:23:17 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
PScomposite(NSMinX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect),
|
2001-02-19 20:50:49 +00:00
|
|
|
[[(NSCachedImageRep *)rep window] gState], aPoint.x, y, op);
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-19 20:50:49 +00:00
|
|
|
NSRect rect;
|
2003-01-21 05:08:26 +00:00
|
|
|
rep = [self bestRepresentationForDevice: nil];
|
2001-02-19 20:50:49 +00:00
|
|
|
rect = NSMakeRect(aPoint.x, aPoint.y, _size.width, _size.height);
|
2000-12-23 14:19:23 +00:00
|
|
|
[self drawRepresentation: rep inRect: rect];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
NSLog(@"NSImage: compositeToPoint:fromRect:operation: failed due to %@: %@",
|
2002-07-06 03:18:14 +00:00
|
|
|
[localException name], [localException reason]);
|
2000-12-23 14:19:23 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(imageDidNotDraw:inRect:)])
|
|
|
|
{
|
|
|
|
NSImage *image = [_delegate imageDidNotDraw: self inRect: aRect];
|
1997-01-31 20:14:40 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (image != nil)
|
|
|
|
[image compositeToPoint: aPoint
|
|
|
|
fromRect: aRect
|
|
|
|
operation: op];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2005-07-08 23:51:49 +00:00
|
|
|
#endif
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
|
|
|
{
|
|
|
|
NSRect rect;
|
|
|
|
NSSize size = [self size];
|
|
|
|
|
|
|
|
rect = NSMakeRect(0, 0, size.width, size.height);
|
|
|
|
[self compositeToPoint: aPoint fromRect: rect
|
|
|
|
operation: op fraction: delta];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2006-11-17 11:07:43 +00:00
|
|
|
fromRect: (NSRect)srcRect
|
2001-08-11 18:34:22 +00:00
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
NSImageRep *rep = nil;
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == YES)
|
2006-11-17 11:07:43 +00:00
|
|
|
rep = [self _doImageCache];
|
2005-07-08 23:51:49 +00:00
|
|
|
if (rep
|
2006-11-17 11:07:43 +00:00
|
|
|
&&_cacheMode != NSImageCacheNever
|
|
|
|
&& [rep isKindOfClass: cachedClass])
|
2005-07-08 23:51:49 +00:00
|
|
|
{
|
|
|
|
NSRect rect;
|
|
|
|
|
|
|
|
rect = [(NSCachedImageRep *)rep rect];
|
|
|
|
NSDebugLLog(@"NSImage", @"composite rect %@ in %@",
|
2006-11-17 11:07:43 +00:00
|
|
|
NSStringFromRect(rect), NSStringFromRect(srcRect));
|
2005-07-08 23:51:49 +00:00
|
|
|
// Move the drawing rectangle to the origin of the image rep
|
|
|
|
// and intersect the two rects.
|
2006-11-17 11:07:43 +00:00
|
|
|
srcRect.origin.x += rect.origin.x;
|
|
|
|
srcRect.origin.y += rect.origin.y;
|
|
|
|
rect = NSIntersectionRect(srcRect, rect);
|
|
|
|
|
|
|
|
[GSCurrentContext() GScomposite:
|
|
|
|
[[(NSCachedImageRep *)rep window] gState]
|
|
|
|
toPoint: aPoint
|
|
|
|
fromRect: rect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2005-07-08 23:51:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSRect rect;
|
|
|
|
rep = [self bestRepresentationForDevice: nil];
|
|
|
|
rect = NSMakeRect(aPoint.x, aPoint.y, _size.width, _size.height);
|
|
|
|
[self drawRepresentation: rep inRect: rect];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
2006-11-17 11:07:43 +00:00
|
|
|
NSLog(@"NSImage: compositeToPoint:fromRect:operation:fraction:"
|
|
|
|
@"failed due to %@: %@",
|
|
|
|
[localException name], [localException reason]);
|
2005-07-08 23:51:49 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(imageDidNotDraw:inRect:)])
|
|
|
|
{
|
2006-11-17 11:07:43 +00:00
|
|
|
NSImage *image = [_delegate imageDidNotDraw: self inRect: srcRect];
|
2005-07-08 23:51:49 +00:00
|
|
|
|
|
|
|
if (image != nil)
|
|
|
|
[image compositeToPoint: aPoint
|
2006-11-17 11:07:43 +00:00
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2005-07-08 23:51:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
- (void) dissolveToPoint: (NSPoint)aPoint fraction: (float)aFloat
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
|
|
|
NSRect rect;
|
2000-12-23 14:19:23 +00:00
|
|
|
NSSize size = [self size];
|
|
|
|
|
|
|
|
rect = NSMakeRect(0, 0, size.width, size.height);
|
1996-08-22 18:51:08 +00:00
|
|
|
[self dissolveToPoint: aPoint fromRect: rect fraction: aFloat];
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (void) dissolveToPoint: (NSPoint)aPoint
|
|
|
|
fromRect: (NSRect)aRect
|
2001-12-17 16:51:51 +00:00
|
|
|
fraction: (float)aFloat
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
#if 0
|
|
|
|
[self compositeToPoint: aPoint
|
|
|
|
fromRect: aRect
|
|
|
|
operation: NSCompositeSourceOver
|
|
|
|
fraction: aFloat];
|
|
|
|
#else
|
2003-01-30 04:29:00 +00:00
|
|
|
NSImageRep *rep = nil;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
NS_DURING
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == YES)
|
|
|
|
rep = [self _doImageCache];
|
|
|
|
if (rep
|
|
|
|
&&_cacheMode != NSImageCacheNever
|
|
|
|
&& [rep isKindOfClass: cachedClass])
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
NSRect rect;
|
2000-12-23 14:19:23 +00:00
|
|
|
float y = aPoint.y;
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
rect = [(NSCachedImageRep *)rep rect];
|
2001-08-11 18:34:22 +00:00
|
|
|
// Move the drawing rectangle to the origin of the image rep
|
|
|
|
// and intersect the two rects.
|
|
|
|
aRect.origin.x += rect.origin.x;
|
|
|
|
aRect.origin.y += rect.origin.y;
|
|
|
|
rect = NSIntersectionRect(aRect, rect);
|
2000-12-23 14:19:23 +00:00
|
|
|
PSdissolve(NSMinX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect),
|
2001-02-19 20:50:49 +00:00
|
|
|
[[(NSCachedImageRep *)rep window] gState], aPoint.x, y, aFloat);
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-19 20:50:49 +00:00
|
|
|
NSRect rect;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
/* FIXME: Here we are supposed to composite directly from the source
|
|
|
|
but how do you do that? */
|
|
|
|
rep = [self bestRepresentationForDevice: nil];
|
2001-02-19 20:50:49 +00:00
|
|
|
rect = NSMakeRect(aPoint.x, aPoint.y, _size.width, _size.height);
|
2000-12-23 14:19:23 +00:00
|
|
|
[self drawRepresentation: rep inRect: rect];
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
NS_HANDLER
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2002-07-06 02:54:36 +00:00
|
|
|
NSLog(@"NSImage: dissolve failed due to %@: %@",
|
2002-07-06 03:18:14 +00:00
|
|
|
[localException name], [localException reason]);
|
2000-12-23 14:19:23 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(imageDidNotDraw:inRect:)])
|
|
|
|
{
|
|
|
|
NSImage *image = [_delegate imageDidNotDraw: self inRect: aRect];
|
|
|
|
|
|
|
|
if (image != nil)
|
|
|
|
[image dissolveToPoint: aPoint
|
|
|
|
fromRect: aRect
|
|
|
|
fraction: aFloat];
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
NS_ENDHANDLER
|
2005-07-08 23:51:49 +00:00
|
|
|
#endif
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2001-02-19 20:50:49 +00:00
|
|
|
- (BOOL) drawRepresentation: (NSImageRep *)imageRep inRect: (NSRect)aRect
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
BOOL r;
|
|
|
|
|
|
|
|
PSgsave();
|
|
|
|
|
2001-12-07 22:52:42 +00:00
|
|
|
if (_color != nil)
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
NSRect fillrect = aRect;
|
2001-08-11 18:34:22 +00:00
|
|
|
[_color set];
|
2003-01-21 05:08:26 +00:00
|
|
|
if ([[NSView focusView] isFlipped])
|
|
|
|
fillrect.origin.y -= _size.height;
|
|
|
|
NSRectFill(fillrect);
|
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == NO)
|
|
|
|
{
|
|
|
|
/* Reset alpha for image drawing. */
|
2006-10-20 13:08:20 +00:00
|
|
|
[[NSColor colorWithCalibratedWhite: 1.0 alpha: 1.0] set];
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
if (!_flags.scalable)
|
|
|
|
r = [imageRep drawAtPoint: aRect.origin];
|
|
|
|
else
|
|
|
|
r = [imageRep drawInRect: aRect];
|
|
|
|
|
|
|
|
PSgrestore();
|
|
|
|
|
|
|
|
return r;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) drawAtPoint: (NSPoint)point
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
[self drawInRect: NSMakeRect(point.x, point.y, srcRect.size.width,
|
|
|
|
srcRect.size.height)
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) drawInRect: (NSRect)dstRect
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
2006-11-17 11:07:43 +00:00
|
|
|
fraction: (float)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
|
|
|
NSAffineTransform *transform;
|
|
|
|
|
|
|
|
if (!dstRect.size.width || !dstRect.size.height
|
2006-11-19 11:39:27 +00:00
|
|
|
|| !srcRect.size.width || !srcRect.size.height)
|
2005-01-24 23:28:07 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (![ctxt isDrawingToScreen])
|
|
|
|
{
|
|
|
|
/* We can't composite or dissolve if we aren't drawing to a screen,
|
|
|
|
so we'll just draw the right part of the image in the right
|
|
|
|
place. */
|
|
|
|
NSSize s;
|
|
|
|
NSPoint p;
|
|
|
|
double fx, fy;
|
|
|
|
|
|
|
|
s = [self size];
|
|
|
|
|
|
|
|
fx = dstRect.size.width / srcRect.size.width;
|
|
|
|
fy = dstRect.size.height / srcRect.size.height;
|
|
|
|
|
|
|
|
p.x = dstRect.origin.x / fx - srcRect.origin.x;
|
|
|
|
p.y = dstRect.origin.y / fy - srcRect.origin.y;
|
|
|
|
|
|
|
|
DPSgsave(ctxt);
|
|
|
|
DPSrectclip(ctxt, dstRect.origin.x, dstRect.origin.y,
|
|
|
|
dstRect.size.width, dstRect.size.height);
|
|
|
|
DPSscale(ctxt, fx, fy);
|
|
|
|
[self drawRepresentation: [self bestRepresentationForDevice: nil]
|
|
|
|
inRect: NSMakeRect(p.x, p.y, s.width, s.height)];
|
|
|
|
DPSgrestore(ctxt);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out what the effective transform from image space to
|
|
|
|
'window space' is. */
|
|
|
|
transform = [ctxt GSCurrentCTM];
|
|
|
|
|
|
|
|
[transform scaleXBy: dstRect.size.width / srcRect.size.width
|
|
|
|
yBy: dstRect.size.height / srcRect.size.height];
|
|
|
|
|
|
|
|
|
|
|
|
/* If the effective transform is the identity transform and there's
|
|
|
|
no dissolve, we can composite from our cache. */
|
2006-11-19 11:39:27 +00:00
|
|
|
|
|
|
|
if (delta == 1.0)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
2006-11-19 11:39:27 +00:00
|
|
|
NSAffineTransformStruct ts = [transform transformStruct];
|
|
|
|
|
|
|
|
if (fabs(ts.m11 - 1.0) < 0.01 && fabs(ts.m12) < 0.01
|
|
|
|
&& fabs(ts.m21) < 0.01 && fabs(ts.m22 - 1.0) < 0.01)
|
|
|
|
{
|
|
|
|
[self compositeToPoint: dstRect.origin
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op];
|
|
|
|
return;
|
|
|
|
}
|
2005-01-24 23:28:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We can't composite or dissolve directly from the image reps, so we
|
|
|
|
create a temporary off-screen window large enough to hold the
|
|
|
|
transformed image, draw the image rep there, and composite from there
|
|
|
|
to the destination.
|
|
|
|
|
|
|
|
Optimization: Since we do the entire image at once, we might need a
|
|
|
|
huge buffer. If this starts hurting too much, there are a couple of
|
|
|
|
things we could do to:
|
|
|
|
|
|
|
|
1. Take srcRect into account and only process the parts of the image
|
|
|
|
we really need.
|
|
|
|
2. Take the clipping path into account. Desirable, especially if we're
|
|
|
|
being drawn as lots of small strips in a scrollview. We don't have
|
|
|
|
the clipping path here, though.
|
|
|
|
3. Allocate a permanent but small buffer and process the image
|
|
|
|
piecewise.
|
|
|
|
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
NSCachedImageRep *cache;
|
2006-11-19 11:39:27 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2005-01-24 23:28:07 +00:00
|
|
|
NSSize s;
|
|
|
|
NSPoint p;
|
|
|
|
double x0, y0, x1, y1, w, h;
|
|
|
|
int gState;
|
|
|
|
|
|
|
|
s = [self size];
|
|
|
|
|
|
|
|
/* Figure out how big we need to make the window that'll hold the
|
|
|
|
transformed image. */
|
|
|
|
p = [transform transformPoint: NSMakePoint(0, s.height)];
|
|
|
|
x0 = x1 = p.x;
|
|
|
|
y0 = y1 = p.y;
|
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(s.width, 0)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(s.width, s.height)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(0, 0)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
x0 = floor(x0);
|
|
|
|
y0 = floor(y0);
|
|
|
|
x1 = ceil(x1);
|
|
|
|
y1 = ceil(y1);
|
|
|
|
|
|
|
|
w = x1 - x0;
|
|
|
|
h = y1 - y0;
|
|
|
|
|
|
|
|
/* This is where we want the origin of image space to be in our
|
|
|
|
window. */
|
|
|
|
p.x -= x0;
|
|
|
|
p.y -= y0;
|
|
|
|
|
|
|
|
cache = [[NSCachedImageRep alloc]
|
|
|
|
initWithSize: NSMakeSize(w, h)
|
|
|
|
depth: [[NSScreen mainScreen] depth]
|
|
|
|
separate: YES
|
|
|
|
alpha: YES];
|
|
|
|
|
|
|
|
[[[cache window] contentView] lockFocus];
|
|
|
|
|
|
|
|
DPScompositerect(ctxt, 0, 0, w, h, NSCompositeClear);
|
|
|
|
|
|
|
|
/* Set up the effective transform. We also save a gState with this
|
|
|
|
transform to make it easier to do the final composite. */
|
2006-11-19 11:39:27 +00:00
|
|
|
ts = [transform transformStruct];
|
|
|
|
ts.tX = p.x;
|
|
|
|
ts.tY = p.y;
|
|
|
|
[transform setTransformStruct: ts];
|
2005-01-24 23:28:07 +00:00
|
|
|
[ctxt GSSetCTM: transform];
|
|
|
|
|
|
|
|
gState = [ctxt GSDefineGState];
|
|
|
|
|
|
|
|
[self drawRepresentation: [self bestRepresentationForDevice: nil]
|
|
|
|
inRect: NSMakeRect(0, 0, s.width, s.height)];
|
|
|
|
|
|
|
|
/* If we're doing a dissolve, use a DestinationIn composite to lower
|
|
|
|
the alpha of the pixels. */
|
2006-11-17 11:07:43 +00:00
|
|
|
if (delta != 1.0)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
2006-11-17 11:07:43 +00:00
|
|
|
DPSsetalpha(ctxt, delta);
|
2005-01-24 23:28:07 +00:00
|
|
|
DPScompositerect(ctxt, 0, 0, s.width, s.height,
|
|
|
|
NSCompositeDestinationIn);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[[cache window] contentView] unlockFocus];
|
|
|
|
|
|
|
|
|
|
|
|
DPScomposite(ctxt, srcRect.origin.x, srcRect.origin.y,
|
|
|
|
srcRect.size.width, srcRect.size.height, gState,
|
|
|
|
dstRect.origin.x, dstRect.origin.y, op);
|
|
|
|
|
|
|
|
[ctxt GSUndefineGState: gState];
|
|
|
|
|
|
|
|
DESTROY(cache);
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Adds the NSImageRep imageRep to the NSImage's representations array.
|
|
|
|
</p><p>See Also: -addRepresentations: removeRepresentation:</p>
|
|
|
|
*/
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (void) addRepresentation: (NSImageRep *)imageRep
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
GSRepData *repd;
|
1999-03-26 15:59:01 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = [GSRepData new];
|
2000-12-23 14:19:23 +00:00
|
|
|
repd->rep = RETAIN(imageRep);
|
|
|
|
[_reps addObject: repd];
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(repd);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Adds the NSImageRep array imageRepArray to the NSImage's
|
|
|
|
representations array.</p>
|
|
|
|
<p>See Also: -addRepresentation: -removeRepresentation:</p>
|
|
|
|
*/
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) addRepresentations: (NSArray *)imageRepArray
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
unsigned i, count;
|
|
|
|
GSRepData *repd;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
count = [imageRepArray count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = [GSRepData new];
|
1999-12-01 13:49:47 +00:00
|
|
|
repd->rep = RETAIN([imageRepArray objectAtIndex: i]);
|
1999-04-28 11:16:26 +00:00
|
|
|
[_reps addObject: repd];
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(repd);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Remove the NSImageRep imageRep from the NSImage's representations
|
|
|
|
array</p><p>See Also: -addRepresentations: -addRepresentation:</p>
|
|
|
|
*/
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) removeRepresentation: (NSImageRep *)imageRep
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
unsigned i;
|
|
|
|
GSRepData *repd;
|
|
|
|
|
|
|
|
i = [_reps count];
|
|
|
|
while (i-- > 0)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = (GSRepData*)[_reps objectAtIndex: i];
|
|
|
|
if (repd->rep == imageRep)
|
|
|
|
{
|
|
|
|
[_reps removeObjectAtIndex: i];
|
|
|
|
}
|
|
|
|
else if (repd->original == imageRep)
|
|
|
|
{
|
|
|
|
repd->original = nil;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/** <p>Locks the focus on the best representation</p>
|
|
|
|
<p>See Also: -lockFocusOnRepresentation:</p>
|
|
|
|
*/
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) lockFocus
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
[self lockFocusOnRepresentation: nil];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2005-11-24 13:48:41 +00:00
|
|
|
/**<p>Locks the focus in the imageRep. if imageRep is nil this method
|
|
|
|
locks the focus on the best representation</p>
|
|
|
|
*/
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) lockFocusOnRepresentation: (NSImageRep *)imageRep
|
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
if (_cacheMode != NSImageCacheNever)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
NSWindow *window;
|
2002-08-03 03:32:19 +00:00
|
|
|
GSRepData *repd;
|
1999-12-01 13:49:47 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
if (imageRep == nil)
|
|
|
|
imageRep = [self bestRepresentationForDevice: nil];
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
imageRep = [self _cacheForRep: imageRep];
|
2002-08-03 03:32:19 +00:00
|
|
|
repd = repd_for_rep(_reps, imageRep);
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
window = [(NSCachedImageRep *)imageRep window];
|
|
|
|
_lockedView = [window contentView];
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_lockedView == nil)
|
|
|
|
[NSException raise: NSImageCacheException
|
|
|
|
format: @"Cannot lock focus on nil rep"];
|
1999-12-01 13:49:47 +00:00
|
|
|
[_lockedView lockFocus];
|
2002-08-03 03:32:19 +00:00
|
|
|
|
|
|
|
/* Validate cached image */
|
|
|
|
if (repd->bg == nil)
|
|
|
|
{
|
|
|
|
repd->bg = [_color copy];
|
|
|
|
[_color set];
|
2002-08-23 00:40:41 +00:00
|
|
|
|
|
|
|
if ([_color alphaComponent] < 1)
|
|
|
|
{
|
|
|
|
/* With a Quartz-like alpha model, alpha can't be cleared
|
|
|
|
with a rectfill, so we need to clear the alpha channel
|
|
|
|
explictly. (A compositerect with NSCompositeCopy would
|
|
|
|
be more efficient, but it doesn't seem like it's
|
|
|
|
implemented correctly in all backends yet (as of
|
|
|
|
2002-08-23). Also, this will work with both the Quartz-
|
|
|
|
and DPS-model.) */
|
|
|
|
PScompositerect(0, 0, _size.width, _size.height,
|
|
|
|
NSCompositeClear);
|
|
|
|
}
|
2002-08-03 03:32:19 +00:00
|
|
|
NSRectFill(NSMakeRect(0, 0, _size.width, _size.height));
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) unlockFocus
|
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
if (_lockedView != nil)
|
|
|
|
{
|
|
|
|
[_lockedView unlockFocus];
|
|
|
|
_lockedView = nil;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
/* Determine if the device is color or gray scale and find the reps of
|
|
|
|
the same type
|
|
|
|
*/
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
|
|
|
withColorMatch: (NSDictionary*)deviceDescription
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
int colors = 3;
|
|
|
|
NSImageRep* rep;
|
|
|
|
NSMutableArray *breps;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
NSString *colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
|
|
|
|
|
|
|
|
if (colorSpace != nil)
|
|
|
|
colors = NSNumberOfColorComponents(colorSpace);
|
|
|
|
|
|
|
|
breps = [NSMutableArray array];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep colorSpaceName] || abs(NSNumberOfColorComponents([rep colorSpaceName]) - colors) <= 1)
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find reps that match the resolution of the device or return the rep
|
|
|
|
that has the highest resolution */
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
|
|
|
withResolutionMatch: (NSDictionary*)deviceDescription
|
|
|
|
{
|
|
|
|
NSImageRep* rep;
|
|
|
|
NSMutableArray *breps;
|
|
|
|
NSSize dres;
|
2000-12-24 14:05:12 +00:00
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
2003-01-21 05:08:26 +00:00
|
|
|
NSValue *resolution = [deviceDescription objectForKey: NSDeviceResolution];
|
|
|
|
|
|
|
|
if (resolution)
|
|
|
|
dres = [resolution sizeValue];
|
|
|
|
else
|
|
|
|
dres = NSMakeSize(0, 0);
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
breps = [NSMutableArray array];
|
2000-12-24 14:05:12 +00:00
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
/* FIXME: Not sure about checking resolution */
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find reps that match the bps of the device or return the rep that
|
|
|
|
has the highest bps */
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
|
|
|
withBpsMatch: (NSDictionary*)deviceDescription
|
|
|
|
{
|
|
|
|
NSImageRep* rep, *max_rep;
|
|
|
|
NSMutableArray *breps;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
int bps = [[deviceDescription objectForKey: NSDeviceBitsPerSample] intValue];
|
|
|
|
int max_bps;
|
|
|
|
|
|
|
|
breps = [NSMutableArray array];
|
|
|
|
max_bps = 0;
|
|
|
|
max_rep = nil;
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
2003-01-30 04:29:00 +00:00
|
|
|
int rep_bps = 0;
|
2003-01-21 05:08:26 +00:00
|
|
|
if ([rep respondsToSelector: @selector(bitsPerPixel)])
|
|
|
|
rep_bps = [(NSBitmapImageRep *)rep bitsPerPixel];
|
|
|
|
if (rep_bps > max_bps)
|
|
|
|
{
|
|
|
|
max_bps = rep_bps;
|
|
|
|
max_rep = rep;
|
|
|
|
}
|
|
|
|
if (rep_bps == bps)
|
|
|
|
[breps addObject: rep];
|
1999-12-01 13:49:47 +00:00
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
if ([breps count] == 0 && max_rep != nil)
|
|
|
|
[breps addObject: max_rep];
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
1999-12-01 13:49:47 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSMutableArray *) _representationsWithCachedImages: (BOOL)flag
|
1999-12-01 13:49:47 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
if (_flags.syncLoad)
|
1999-12-01 13:49:47 +00:00
|
|
|
{
|
2000-12-24 14:05:12 +00:00
|
|
|
/* Make sure any images that were added with _useFromFile: are loaded
|
|
|
|
in and added to the representation list. */
|
|
|
|
[self _loadFromFile: _fileName];
|
|
|
|
_flags.syncLoad = NO;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
2000-12-24 14:05:12 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
count = [_reps count];
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
return [NSArray array];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id repList[count];
|
2003-01-21 05:08:26 +00:00
|
|
|
unsigned i, j;
|
1999-12-01 13:49:47 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
[_reps getObjects: repList];
|
2003-01-21 05:08:26 +00:00
|
|
|
j = 0;
|
2000-12-23 14:19:23 +00:00
|
|
|
for (i = 0; i < count; i++)
|
1999-04-28 11:16:26 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
if (flag || ((GSRepData*)repList[i])->original == nil)
|
|
|
|
{
|
|
|
|
repList[j] = ((GSRepData*)repList[i])->rep;
|
|
|
|
j++;
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
return [NSArray arrayWithObjects: repList count: j];
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSImageRep*) bestRepresentationForDevice: (NSDictionary*)deviceDescription
|
|
|
|
{
|
|
|
|
NSMutableArray *reps = [self _representationsWithCachedImages: NO];
|
|
|
|
|
|
|
|
if (deviceDescription == nil)
|
|
|
|
{
|
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == YES)
|
|
|
|
{
|
2005-11-06 19:37:27 +00:00
|
|
|
// Take the device description from the current context.
|
|
|
|
deviceDescription = [GSCurrentContext() attributes];
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
|
|
|
else if ([NSPrintOperation currentOperation])
|
|
|
|
{
|
|
|
|
/* FIXME: We could try to use the current printer,
|
|
|
|
but there are many cases where might
|
|
|
|
not be printing (EPS, PDF, etc) to a specific device */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_flags.colorMatchPreferred == YES)
|
|
|
|
{
|
|
|
|
reps = [self _bestRep: reps withColorMatch: deviceDescription];
|
|
|
|
reps = [self _bestRep: reps withResolutionMatch: deviceDescription];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reps = [self _bestRep: reps withResolutionMatch: deviceDescription];
|
|
|
|
reps = [self _bestRep: reps withColorMatch: deviceDescription];
|
|
|
|
}
|
|
|
|
reps = [self _bestRep: reps withBpsMatch: deviceDescription];
|
|
|
|
/* Pick an arbitrary representation if there is more than one */
|
|
|
|
return [reps lastObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) representations
|
|
|
|
{
|
|
|
|
return [self _representationsWithCachedImages: YES];
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setDelegate: anObject
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
_delegate = anObject;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (id) delegate
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
return _delegate;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
// Producing TIFF Data for the Image
|
2000-12-23 14:19:23 +00:00
|
|
|
- (NSData *) TIFFRepresentation
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2002-02-02 00:27:32 +00:00
|
|
|
return [bitmapClass TIFFRepresentationOfImageRepsInArray: [self representations]];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (NSData *) TIFFRepresentationUsingCompression: (NSTIFFCompression)comp
|
|
|
|
factor: (float)aFloat
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-11 18:34:22 +00:00
|
|
|
return [bitmapClass TIFFRepresentationOfImageRepsInArray: [self representations]
|
|
|
|
usingCompression: comp
|
2000-12-23 14:19:23 +00:00
|
|
|
factor: aFloat];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
// NSCoding
|
1999-03-02 08:58:30 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)coder
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-12-28 16:02:01 +00:00
|
|
|
BOOL flag;
|
|
|
|
|
2006-10-20 13:08:20 +00:00
|
|
|
if ([coder allowsKeyedCoding])
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2006-09-03 16:41:10 +00:00
|
|
|
// FIXME: Not sure this is the way it goes...
|
1999-12-28 16:02:01 +00:00
|
|
|
/*
|
2006-10-20 13:08:20 +00:00
|
|
|
if (_flags.archiveByName == NO)
|
2006-09-03 16:41:10 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *container = [NSMutableArray array];
|
|
|
|
NSMutableArray *reps = [NSMutableArray array];
|
|
|
|
NSEnumerator *en = [_reps objectEnumerator];
|
|
|
|
GSRepData *rd = nil;
|
|
|
|
|
|
|
|
// add the reps to the container...
|
|
|
|
[container addObject: reps];
|
2006-10-20 13:08:20 +00:00
|
|
|
while ((rd = [en nextObject]) != nil)
|
2006-09-03 16:41:10 +00:00
|
|
|
{
|
|
|
|
[reps addObject: rd->rep];
|
|
|
|
}
|
|
|
|
[coder encodeObject: container forKey: @"NSReps"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[coder encodeObject: _name forKey: @"NSImageName"];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
// encode the rest...
|
|
|
|
[coder encodeObject: _color forKey: @"NSColor"];
|
|
|
|
[coder encodeInt: 0 forKey: @"NSImageFlags"]; // zero...
|
|
|
|
[coder encodeSize: _size forKey: @"NSSize"];
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-09-03 16:41:10 +00:00
|
|
|
flag = _flags.archiveByName;
|
1999-12-28 16:02:01 +00:00
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2006-09-03 16:41:10 +00:00
|
|
|
if (flag == YES)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* System image - just encode the name.
|
|
|
|
*/
|
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &_name];
|
|
|
|
}
|
|
|
|
else
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2006-09-03 16:41:10 +00:00
|
|
|
NSMutableArray *a;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSImageRep *r;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Normal image - encode the ivars
|
|
|
|
*/
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSSize) at: &_size];
|
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &_color];
|
|
|
|
flag = _flags.scalable;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.dataRetained;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.flipDraw;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.sizeWasExplicitlySet;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.useEPSOnResolutionMismatch;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.colorMatchPreferred;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.multipleResolutionMatching;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.cacheSeparately;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.unboundedCacheDepth;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
|
|
|
// FIXME: The documentation says to archive only the file name,
|
|
|
|
// if not data retained!
|
|
|
|
/*
|
|
|
|
* Now encode an array of all the image reps (excluding cache)
|
|
|
|
*/
|
|
|
|
a = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
e = [[self representations] objectEnumerator];
|
|
|
|
while ((r = [e nextObject]) != nil)
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2006-09-03 16:41:10 +00:00
|
|
|
if ([r isKindOfClass: cachedClass] == NO)
|
|
|
|
{
|
|
|
|
[a addObject: r];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
2006-09-03 16:41:10 +00:00
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &a];
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
1999-03-02 08:58:30 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)coder
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-12-28 16:02:01 +00:00
|
|
|
BOOL flag;
|
|
|
|
|
2001-09-01 20:57:51 +00:00
|
|
|
_reps = [[NSMutableArray alloc] initWithCapacity: 2];
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder allowsKeyedCoding])
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder containsValueForKey: @"NSColor"])
|
|
|
|
{
|
|
|
|
[self setBackgroundColor: [coder decodeObjectForKey: @"NSColor"]];
|
|
|
|
}
|
|
|
|
if ([coder containsValueForKey: @"NSImageFlags"])
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
//FIXME
|
|
|
|
flags = [coder decodeIntForKey: @"NSImageFlags"];
|
|
|
|
}
|
|
|
|
if ([coder containsValueForKey: @"NSReps"])
|
|
|
|
{
|
|
|
|
NSArray *reps;
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2004-10-10 22:36:02 +00:00
|
|
|
// FIXME: NSReps is in a strange format. It is a mutable array with one
|
|
|
|
// element which is an array with a first element 0 and than the image rep.
|
|
|
|
reps = [coder decodeObjectForKey: @"NSReps"];
|
|
|
|
reps = [reps objectAtIndex: 0];
|
|
|
|
[self addRepresentation: [reps objectAtIndex: 1]];
|
|
|
|
}
|
|
|
|
if ([coder containsValueForKey: @"NSSize"])
|
|
|
|
{
|
|
|
|
[self setSize: [coder decodeSizeForKey: @"NSSize"]];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-30 22:02:38 +00:00
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2004-10-10 22:36:02 +00:00
|
|
|
if (flag == YES)
|
|
|
|
{
|
|
|
|
NSString *theName = [coder decodeObject];
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2004-10-10 22:36:02 +00:00
|
|
|
RELEASE(self);
|
|
|
|
self = RETAIN([NSImage imageNamed: theName]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSArray *a;
|
|
|
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSSize) at: &_size];
|
|
|
|
[coder decodeValueOfObjCType: @encode(id) at: &_color];
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.scalable = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.dataRetained = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.flipDraw = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.sizeWasExplicitlySet = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.useEPSOnResolutionMismatch = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.colorMatchPreferred = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.multipleResolutionMatching = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.cacheSeparately = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.unboundedCacheDepth = flag;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get the image reps and add them.
|
|
|
|
*/
|
|
|
|
a = [coder decodeObject];
|
|
|
|
[self addRepresentations: a];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_name && [nameDict objectForKey: _name])
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
return [nameDict objectForKey: _name];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
+ (BOOL) canInitWithPasteboard: (NSPasteboard *)pasteboard
|
|
|
|
{
|
|
|
|
int i, count;
|
|
|
|
NSArray* array = [NSImageRep registeredImageRepClasses];
|
|
|
|
|
|
|
|
count = [array count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
if ([[array objectAtIndex: i] canInitWithPasteboard: pasteboard])
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageUnfilteredFileTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageUnfilteredFileTypes));
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageFileTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageFileTypes));
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageUnfilteredPasteboardTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageUnfilteredPasteboardTypes));
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imagePasteboardTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imagePasteboardTypes));
|
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
@end
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
/* For every image rep, call the specified method to obtain an
|
|
|
|
array of objects. Add these together, with duplicates
|
|
|
|
weeded out. Used by imageUnfilteredPasteboardTypes,
|
|
|
|
imageUnfilteredFileTypes, etc. */
|
2003-10-30 00:23:23 +00:00
|
|
|
static NSArray *
|
1996-08-22 18:51:08 +00:00
|
|
|
iterate_reps_for_types(NSArray* imageReps, SEL method)
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSMutableArray *types;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
types = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
|
|
|
|
// Iterate through all the image reps
|
|
|
|
e = [imageReps objectEnumerator];
|
|
|
|
rep = [e nextObject];
|
|
|
|
while (rep)
|
|
|
|
{
|
|
|
|
id e1;
|
|
|
|
id obj;
|
|
|
|
NSArray* pb_list;
|
|
|
|
|
|
|
|
// Have the image rep perform the operation
|
1997-08-27 21:20:19 +00:00
|
|
|
pb_list = [rep performSelector: method];
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
// Iterate through the returned array
|
|
|
|
// and add elements to types list, duplicates weeded.
|
|
|
|
e1 = [pb_list objectEnumerator];
|
|
|
|
obj = [e1 nextObject];
|
|
|
|
while (obj)
|
|
|
|
{
|
1997-01-31 13:40:15 +00:00
|
|
|
if ([types indexOfObject: obj] == NSNotFound)
|
1996-08-22 18:51:08 +00:00
|
|
|
[types addObject: obj];
|
|
|
|
obj = [e1 nextObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
rep = [e nextObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NSArray *)types;
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
@implementation NSImage (Private)
|
|
|
|
|
|
|
|
- (BOOL)_loadFromData: (NSData *)data
|
|
|
|
{
|
|
|
|
BOOL ok;
|
|
|
|
Class rep;
|
|
|
|
|
|
|
|
ok = NO;
|
|
|
|
rep = [NSImageRep imageRepClassForData: data];
|
|
|
|
if (rep && [rep respondsToSelector: @selector(imageRepsWithData:)])
|
|
|
|
{
|
|
|
|
NSArray* array;
|
|
|
|
array = [rep imageRepsWithData: data];
|
|
|
|
if (array)
|
|
|
|
ok = YES;
|
|
|
|
[self addRepresentations: array];
|
|
|
|
}
|
|
|
|
else if (rep)
|
|
|
|
{
|
|
|
|
NSImageRep* image;
|
|
|
|
image = [rep imageRepWithData: data];
|
|
|
|
if (image)
|
|
|
|
ok = YES;
|
|
|
|
[self addRepresentation: image];
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _loadFromFile: (NSString *)fileName
|
|
|
|
{
|
|
|
|
NSArray* array;
|
|
|
|
|
|
|
|
array = [NSImageRep imageRepsWithContentsOfFile: fileName];
|
|
|
|
if (array)
|
|
|
|
[self addRepresentations: array];
|
|
|
|
|
|
|
|
return (array) ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _useFromFile: (NSString *)fileName
|
|
|
|
{
|
|
|
|
NSArray *array;
|
|
|
|
NSString *ext;
|
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
if ([manager fileExistsAtPath: fileName] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext = [fileName pathExtension];
|
|
|
|
if (!ext)
|
|
|
|
return NO;
|
|
|
|
array = [isa imageFileTypes];
|
|
|
|
if ([array indexOfObject: ext] == NSNotFound)
|
|
|
|
return NO;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
ASSIGN(_fileName, fileName);
|
2000-12-23 14:19:23 +00:00
|
|
|
_flags.syncLoad = YES;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache the bestRepresentation. If the bestRepresentation is not itself
|
|
|
|
// a cache and no cache exists, create one and draw the representation in it
|
|
|
|
// If a cache exists, but is not valid, redraw the cache from the original
|
|
|
|
// image (if there is one).
|
|
|
|
- (NSImageRep *)_doImageCache
|
|
|
|
{
|
2001-08-11 18:34:22 +00:00
|
|
|
NSImageRep *rep = [self bestRepresentationForDevice: nil];
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
if (_cacheMode != NSImageCacheNever)
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2001-08-11 18:34:22 +00:00
|
|
|
GSRepData *repd;
|
|
|
|
|
|
|
|
rep = [self _cacheForRep: rep];
|
|
|
|
repd = repd_for_rep(_reps, rep);
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2006-09-03 16:41:10 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Cached image rep is %p", rep);
|
2000-12-23 14:19:23 +00:00
|
|
|
/*
|
|
|
|
* if the cache is not valid, it's background color will not exist
|
|
|
|
* and we must draw the background then render from the original
|
|
|
|
* image rep into the cache.
|
|
|
|
*/
|
|
|
|
if (repd->bg == nil)
|
|
|
|
{
|
|
|
|
[self lockFocusOnRepresentation: rep];
|
2001-08-11 18:34:22 +00:00
|
|
|
[self drawRepresentation: repd->original
|
|
|
|
inRect: NSMakeRect(0, 0, _size.width, _size.height)];
|
|
|
|
[self unlockFocus];
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_color != nil && [_color alphaComponent] != 0.0)
|
|
|
|
{
|
|
|
|
repd->bg = [_color copy];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
repd->bg = [clearColor copy];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([repd->bg alphaComponent] == 1.0)
|
|
|
|
{
|
|
|
|
[rep setOpaque: YES];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[rep setOpaque: [repd->original isOpaque]];
|
|
|
|
}
|
2006-09-03 16:41:10 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Rendered rep %p on background %@",
|
|
|
|
rep, repd->bg);
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rep;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSImageRep*) _cacheForRep: (NSImageRep*)rep
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If this is not a cached image rep - create a cache to be used to
|
|
|
|
* render the image rep into, and switch to the cached rep.
|
|
|
|
*/
|
2001-08-11 18:34:22 +00:00
|
|
|
if ([rep isKindOfClass: cachedClass] == NO)
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
|
|
|
NSImageRep *cacheRep = nil;
|
|
|
|
unsigned count = [_reps count];
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
GSRepData *invalidCache = nil;
|
|
|
|
GSRepData *partialCache = nil;
|
|
|
|
GSRepData *validCache = nil;
|
|
|
|
GSRepData *reps[count];
|
|
|
|
unsigned partialCount = 0;
|
|
|
|
unsigned i;
|
|
|
|
BOOL opaque = [rep isOpaque];
|
|
|
|
|
|
|
|
[_reps getObjects: reps];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the cached image reps for any whose original is our
|
|
|
|
* 'best' image rep. See if we can notice any invalidated
|
|
|
|
* cache as we go - if we don't find a valid cache, we want to
|
|
|
|
* re-use an invalidated one rather than creating a new one.
|
|
|
|
* NB. If the image rep is opaque, then any cached rep is valid
|
|
|
|
* irrespective of the background color it was drawn with.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
GSRepData *repd = reps[i];
|
|
|
|
|
|
|
|
if (repd->original == rep && repd->rep != rep)
|
|
|
|
{
|
|
|
|
if (repd->bg == nil)
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"NSImage", @"Invalid %@ ... %@ %d", repd->bg, _color, repd->rep);
|
|
|
|
invalidCache = repd;
|
|
|
|
}
|
|
|
|
else if (opaque == YES || [repd->bg isEqual: _color] == YES)
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"NSImage", @"Exact %@ ... %@ %d", repd->bg, _color, repd->rep);
|
|
|
|
validCache = repd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"NSImage", @"Partial %@ ... %@ %d", repd->bg, _color, repd->rep);
|
|
|
|
partialCache = repd;
|
|
|
|
partialCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (validCache != nil)
|
|
|
|
{
|
|
|
|
if (NSImageForceCaching == NO && [rep isOpaque] == NO)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the image rep is not opaque and we are drawing
|
|
|
|
* without an opaque background then the cache can't
|
|
|
|
* really be valid 'cos we might be drawing transparency
|
|
|
|
* on top of anything. So we invalidate the cache by
|
|
|
|
* removing the background color information.
|
|
|
|
*/
|
|
|
|
if ([validCache->bg alphaComponent] != 1.0)
|
|
|
|
{
|
|
|
|
DESTROY(validCache->bg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cacheRep = validCache->rep;
|
|
|
|
}
|
|
|
|
else if (partialCache != nil && partialCount > 2)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Only re-use partially correct caches if there are already
|
|
|
|
* a few partial matches - otherwise we fall default to
|
|
|
|
* creating a new cache.
|
|
|
|
*/
|
|
|
|
if (NSImageForceCaching == NO && [rep isOpaque] == NO)
|
|
|
|
{
|
|
|
|
if (invalidCache != nil)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If there is an unused cache - use it rather than
|
|
|
|
* re-using this one, since we might get a request
|
|
|
|
* to draw with this color again.
|
|
|
|
*/
|
|
|
|
partialCache = invalidCache;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DESTROY(partialCache->bg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cacheRep = partialCache->rep;
|
|
|
|
}
|
|
|
|
else if (invalidCache != nil)
|
|
|
|
{
|
|
|
|
cacheRep = invalidCache->rep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cacheRep == nil)
|
|
|
|
{
|
|
|
|
NSScreen *cur = [NSScreen mainScreen];
|
|
|
|
NSSize imageSize;
|
|
|
|
GSRepData *repd;
|
|
|
|
|
|
|
|
imageSize = [self size];
|
|
|
|
if (imageSize.width == 0 || imageSize.height == 0)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
cacheRep = [[cachedClass alloc] initWithSize: _size
|
|
|
|
depth: [cur depth]
|
|
|
|
separate: NO
|
|
|
|
alpha: NO];
|
|
|
|
[self addRepresentation: cacheRep];
|
|
|
|
RELEASE(cacheRep); /* Retained in _reps array. */
|
|
|
|
repd = repd_for_rep(_reps, cacheRep);
|
|
|
|
repd->original = rep;
|
|
|
|
}
|
|
|
|
return cacheRep;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return rep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|