GraphicsUtils.m
author Jens Alfke <jens@mooseyard.com>
Mon Apr 14 13:58:48 2008 -0700 (2008-04-14)
changeset 4 64823cdde6a5
parent 2 3d3dcc3116d5
child 5 c9f2e0c7359a
permissions -rw-r--r--
Minor improvements.
     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) && [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