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