GraphicsUtils.m
author snej@snej.local
Tue Mar 10 22:34:39 2009 -0700 (2009-03-10)
changeset 19 5ade3e09a827
parent 5 c9f2e0c7359a
permissions -rw-r--r--
Fixed some problems reported by the CLANG static analyzer.
jens@0
     1
//
jens@0
     2
//  GraphicsUtils.m
jens@0
     3
//  MYUtilities
jens@0
     4
//
jens@0
     5
//  Copyright 2008 Jens Alfke. All rights reserved.
jens@0
     6
//
jens@0
     7
jens@0
     8
#import "GraphicsUtils.h"
jens@3
     9
#import "FileUtils.h"
jens@3
    10
#import <ApplicationServices/ApplicationServices.h>
jens@0
    11
jens@0
    12
jens@0
    13
@implementation NSImage (MYUtilities)
jens@0
    14
jens@0
    15
jens@2
    16
- (NSBitmapImageRep*) my_bitmapRep
jens@2
    17
{
jens@2
    18
    NSSize max = {0,0};
jens@2
    19
    NSBitmapImageRep *bestRep = nil;
jens@2
    20
    for( NSImageRep *rep in self.representations )
jens@2
    21
        if( [rep isKindOfClass: [NSBitmapImageRep class]] ) {
jens@2
    22
            NSSize size = [rep size];
jens@2
    23
            if( size.width > max.width || size.height > max.height ) {
jens@2
    24
                bestRep = (NSBitmapImageRep*)rep;
jens@2
    25
                max = size;
jens@2
    26
            }
jens@2
    27
        }
jens@2
    28
    if( ! bestRep ) {
jens@2
    29
        NSImage *tiffImage = [[NSImage alloc] initWithData:[self TIFFRepresentation]];
jens@2
    30
        bestRep = [[tiffImage representations] objectAtIndex:0];
jens@2
    31
        [tiffImage autorelease];
jens@2
    32
    }
jens@2
    33
    return bestRep;
jens@2
    34
}
jens@2
    35
jens@2
    36
jens@0
    37
- (NSSize) my_sizeOfLargestRep
jens@0
    38
{
jens@0
    39
    NSArray *reps = [self representations];
jens@0
    40
    NSSize max = {0,0};
jens@0
    41
    int i;
jens@0
    42
    for( i=[reps count]-1; i>=0; i-- ) {
jens@0
    43
        NSImageRep *rep = [reps objectAtIndex: i];
jens@0
    44
        NSSize size = [rep size];
jens@0
    45
        if( size.width > max.width || size.height > max.height ) {
jens@0
    46
            max = size;
jens@0
    47
        }
jens@0
    48
    }
jens@0
    49
    return max;
jens@0
    50
}
jens@0
    51
jens@0
    52
jens@0
    53
- (NSImage*) my_shrunkToFitIn: (NSSize) maxSize
jens@0
    54
{
jens@0
    55
    NSSize size = self.size;
jens@1
    56
    float scale = MIN( maxSize.width/size.width, maxSize.height/size.height );
jens@0
    57
    if( scale >= 1.0 )
jens@0
    58
        return self;
jens@0
    59
    
jens@0
    60
    NSSize newSize = {roundf(size.width*scale), roundf(size.height*scale)};
jens@0
    61
    NSImage *newImage = [[NSImage alloc] initWithSize: newSize];
jens@0
    62
    [newImage lockFocus];
jens@0
    63
    NSGraphicsContext *context = [NSGraphicsContext currentContext];
jens@0
    64
    [context saveGraphicsState];
jens@0
    65
    [context setImageInterpolation: NSImageInterpolationHigh];
jens@0
    66
    [self drawInRect: NSMakeRect(0,0,newSize.width,newSize.height)
jens@0
    67
            fromRect: NSMakeRect(0,0,size.width,size.height)
jens@0
    68
           operation: NSCompositeCopy fraction: 1.0f];
jens@0
    69
    [context restoreGraphicsState];
jens@0
    70
    [newImage unlockFocus];
jens@0
    71
    return [newImage autorelease];
jens@0
    72
}
jens@0
    73
jens@0
    74
jens@0
    75
- (NSData*) my_JPEGData
jens@0
    76
{
jens@2
    77
    return [self my_dataInFormat: NSJPEGFileType quality: 0.75f];
jens@2
    78
}
jens@2
    79
jens@2
    80
jens@2
    81
- (NSData*) my_dataInFormat: (NSBitmapImageFileType)format quality: (float)quality
jens@2
    82
{
jens@2
    83
    NSBitmapImageRep *rep = self.my_bitmapRep;
jens@0
    84
    NSDictionary *props = [NSDictionary dictionaryWithObjectsAndKeys:
jens@2
    85
                           [NSNumber numberWithFloat: quality], NSImageCompressionFactor, nil];
jens@2
    86
    return [rep representationUsingType: format properties: props];
jens@0
    87
}
jens@0
    88
jens@0
    89
jens@0
    90
#if 0
jens@0
    91
jens@0
    92
// Adapted from Apple's CocoaCreateMovie sample
jens@0
    93
// <http://developer.apple.com/samplecode/Sample_Code/QuickTime/Basics/CocoaCreateMovie/MyController.m.htm>
jens@0
    94
static void CopyNSImageRepToGWorld(NSBitmapImageRep *imageRepresentation, GWorldPtr gWorldPtr)
jens@0
    95
{
jens@0
    96
    PixMapHandle  pixMapHandle;
jens@0
    97
    unsigned char*   pixBaseAddr;
jens@0
    98
jens@0
    99
    // Lock the pixels
jens@0
   100
    pixMapHandle = GetGWorldPixMap(gWorldPtr);
jens@0
   101
    LockPixels (pixMapHandle);
jens@0
   102
    pixBaseAddr = (unsigned char*) GetPixBaseAddr(pixMapHandle);
jens@0
   103
jens@0
   104
    const unsigned char* bitMapDataPtr = [imageRepresentation bitmapData];
jens@0
   105
jens@0
   106
    if ((bitMapDataPtr != nil) && (pixBaseAddr != nil))
jens@0
   107
    {
jens@0
   108
        int i,j;
jens@0
   109
        int pixmapRowBytes = GetPixRowBytes(pixMapHandle);
jens@0
   110
        NSSize imageSize = [imageRepresentation size];
jens@0
   111
        for (i=0; i< imageSize.height; i++)
jens@0
   112
        {
jens@0
   113
            const unsigned char *src = bitMapDataPtr + i * [imageRepresentation bytesPerRow];
jens@0
   114
            unsigned char *dst = pixBaseAddr + i * pixmapRowBytes;
jens@0
   115
            for (j = 0; j < imageSize.width; j++)
jens@0
   116
            {
jens@0
   117
                *dst++ = 0;  // X - our src is 24-bit only
jens@0
   118
                *dst++ = *src++; // Red component
jens@0
   119
                *dst++ = *src++; // Green component
jens@0
   120
                *dst++ = *src++; // Blue component
jens@0
   121
            }
jens@0
   122
        }
jens@0
   123
    }
jens@0
   124
    UnlockPixels(pixMapHandle);
jens@0
   125
}
jens@0
   126
jens@0
   127
jens@0
   128
- (NSData*) my_PICTData
jens@0
   129
{
jens@0
   130
    // Locate the bitmap image rep:
jens@0
   131
    NSBitmapImageRep *rep;
jens@0
   132
    NSEnumerator *e = [[self representations] objectEnumerator];
jens@0
   133
    while( (rep=[e nextObject]) != nil ) {
jens@0
   134
        if( [rep isKindOfClass: [NSBitmapImageRep class]] )
jens@0
   135
            break;
jens@0
   136
    }
jens@0
   137
    if( ! rep ) {
jens@0
   138
        Warn(@"No bitmap image rep in image");
jens@0
   139
        return nil;
jens@0
   140
    }
jens@0
   141
jens@0
   142
    // Copy the image data into a GWorld:
jens@0
   143
    Rect bounds;
jens@0
   144
    SetRect(&bounds, 0,0,[rep pixelsWide],[rep pixelsHigh]);    
jens@0
   145
    GWorldPtr gworld;
jens@0
   146
    OSStatus err = NewGWorld(&gworld, 32, &bounds, NULL, NULL, 0);
jens@0
   147
    if( err ) {
jens@0
   148
        Warn(@"NewGWorld failed with err %i",err);
jens@0
   149
        return nil;
jens@0
   150
    }
jens@0
   151
    CopyNSImageRepToGWorld(rep,gworld);
jens@0
   152
jens@0
   153
    // Draw the GWorld into a PicHandle:
jens@0
   154
    CGrafPtr oldPort;
jens@0
   155
    GDHandle oldDevice;
jens@0
   156
    GetGWorld(&oldPort,&oldDevice);
jens@0
   157
    SetGWorld(gworld,NULL);
jens@0
   158
    ClipRect(&bounds);
jens@0
   159
    PicHandle pic = OpenPicture(&bounds);
jens@0
   160
    CopyBits(GetPortBitMapForCopyBits(gworld),
jens@0
   161
             GetPortBitMapForCopyBits(gworld),
jens@0
   162
             &bounds,&bounds,srcCopy,NULL);
jens@0
   163
    ClosePicture();
jens@0
   164
    err = QDError();
jens@0
   165
    SetGWorld(oldPort,oldDevice);
jens@0
   166
    DisposeGWorld(gworld);
jens@0
   167
    
jens@0
   168
    if( err ) {
jens@0
   169
        Warn(@"Couldn't convert to PICT: error %i",err);
jens@0
   170
        return nil;
jens@0
   171
    }
jens@0
   172
jens@0
   173
    // Copy the PicHandle into an NSData:
jens@0
   174
    HLock((Handle)pic);
jens@0
   175
    //Test to put PICT on clipboard:
jens@0
   176
    /*ScrapRef scrap;
jens@0
   177
    GetCurrentScrap(&scrap);
jens@0
   178
    ClearScrap(&scrap);
jens@0
   179
    PutScrapFlavor(scrap,'PICT',0,GetHandleSize((Handle)pic),*pic);*/
jens@0
   180
    NSData *data = [NSData dataWithBytes: *pic length: GetHandleSize((Handle)pic)];
jens@0
   181
    DisposeHandle((Handle)pic);
jens@0
   182
    Log(@"Converted image to %i bytes of PICT data",[data length]);
jens@0
   183
    return data;
jens@0
   184
}
jens@0
   185
#endif
jens@0
   186
jens@0
   187
jens@0
   188
@end
jens@0
   189
jens@0
   190
jens@0
   191
jens@0
   192
jens@0
   193
@implementation NSBezierPath (MYUtilities)
jens@0
   194
jens@0
   195
+ (NSBezierPath*) my_bezierPathWithRoundRect: (NSRect)rect radius: (float)radius
jens@0
   196
{
jens@0
   197
    radius = MIN(radius, floorf(rect.size.width/2));
jens@0
   198
    float x0 = NSMinX(rect), y0 = NSMinY(rect),
jens@0
   199
          x1 = NSMaxX(rect), y1 = NSMaxY(rect);
jens@0
   200
    NSBezierPath *path = [NSBezierPath bezierPath];
jens@0
   201
    
jens@0
   202
    [path moveToPoint: NSMakePoint(x0+radius,y0)];
jens@0
   203
    
jens@0
   204
    [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y0)
jens@0
   205
                                   toPoint: NSMakePoint(x1,y1) radius: radius];
jens@0
   206
    [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y1)
jens@0
   207
                                   toPoint: NSMakePoint(x0,y1) radius: radius];
jens@0
   208
    [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y1)
jens@0
   209
                                   toPoint: NSMakePoint(x0,y0) radius: radius];
jens@0
   210
    [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y0)
jens@0
   211
                                   toPoint: NSMakePoint(x1,y0) radius: radius];
jens@0
   212
    [path closePath];
jens@0
   213
    return path;
jens@0
   214
}
jens@0
   215
jens@0
   216
@end
jens@2
   217
jens@2
   218
jens@2
   219
jens@2
   220
NSArray* OpenWindowsWithDelegateClass( Class klass )
jens@2
   221
{
jens@2
   222
    NSMutableArray *windows = $marray();
jens@2
   223
    for( NSWindow *window in [NSApp windows] ) {
jens@2
   224
        id delegate = window.delegate;
jens@5
   225
        if( (window.isVisible || window.isMiniaturized) && (klass==nil || [delegate isKindOfClass: klass]) ) 
jens@2
   226
            [windows addObject: window];
jens@2
   227
    }
jens@2
   228
    return windows;
jens@2
   229
}    
jens@2
   230
jens@2
   231
jens@2
   232
jens@2
   233
NSRect PinRect( NSRect r, NSRect container )
jens@2
   234
{
jens@2
   235
    // Push r's origin inside container, and limit its size to the container's:
jens@2
   236
    r = NSMakeRect(MAX(r.origin.x, container.origin.x),
jens@2
   237
                   MAX(r.origin.y, container.origin.y),
jens@2
   238
                   MIN(r.size.width, container.size.width),
jens@2
   239
                   MIN(r.size.height, container.size.height));
jens@2
   240
    // Push r's outside edges into the container:
jens@2
   241
    r.origin.x -= MAX(0, NSMaxX(r)-NSMaxX(container));
jens@2
   242
    r.origin.y -= MAX(0, NSMaxY(r)-NSMaxY(container));
jens@2
   243
    return r;
jens@2
   244
    
jens@2
   245
}
jens@3
   246
jens@3
   247
jens@3
   248
OSStatus LoadFontsFromBundle( NSBundle *bundle )
jens@3
   249
{
jens@3
   250
    NSString *fontsPath = [[bundle resourcePath] stringByAppendingPathComponent:@"Fonts"];
jens@3
   251
    if( fontsPath )
jens@3
   252
        return LoadFontsFromPath(fontsPath);
jens@3
   253
    else
jens@3
   254
        return fnfErr;
jens@3
   255
}
jens@3
   256
jens@3
   257
jens@3
   258
OSStatus LoadFontsFromPath( NSString* path )
jens@3
   259
{
jens@3
   260
    // Tip of the hat to Buddy Kurz!
jens@3
   261
    FSRef fsRef;
jens@3
   262
    OSStatus err = PathToFSRef(path,&fsRef);
jens@3
   263
    if (err==noErr)
jens@3
   264
        err = ATSFontActivateFromFileReference(&fsRef,
jens@3
   265
                                               kATSFontContextLocal,
jens@3
   266
                                               kATSFontFormatUnspecified,
jens@3
   267
                                               NULL,
jens@3
   268
                                               kATSOptionFlagsDefault,
jens@3
   269
                                               NULL
jens@3
   270
                                               );
jens@3
   271
    if( err ) Warn(@"LoadFontsFromPath: Error %i for %@",err,path);
jens@3
   272
    return err;
jens@3
   273
}
jens@3
   274
jens@11
   275
jens@11
   276
jens@11
   277
/*
jens@11
   278
 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@11
   279
 
jens@11
   280
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@11
   281
 provided that the following conditions are met:
jens@11
   282
 
jens@11
   283
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@11
   284
 and the following disclaimer.
jens@11
   285
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@11
   286
 and the following disclaimer in the documentation and/or other materials provided with the
jens@11
   287
 distribution.
jens@11
   288
 
jens@11
   289
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@11
   290
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@11
   291
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@11
   292
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@11
   293
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@11
   294
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@11
   295
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@11
   296
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@11
   297
 */