This is MorphDocument.m in view mode; [Download] [Up]
// MorphDocument.m // // created by Martin Wennerberg on Sun 12-Nov-1995 // // when who modification #import "MorphDocument.h" #import "AppController.h" #import "MorphLine.h" #import "Morpher.h" #import "Editor.h" #import "NSBitmapImageRep_editing.h" #import "algebra.h" #import "PreviewCell.h" #import "InspectorController.h" #import "MorphLineInspector.h" #define NIB_NAME @"MorphDocument.nib" @implementation MorphDocument + (NSSet *) readableFileTypes; { return [NSSet setWithObject:MORPH_DOC_EXTENTION]; } + (void) load { [[NSApp delegate] registerDocumentClass:[self class]]; } - (void) dealloc { [firstImage release]; [lastImage release]; [morphLines release]; [super dealloc]; } - initWithContentsOfFile:(NSString *)path { NSString *filename; NSString *fullPath; NSImage *image; NSArray *lineDefs; int i; MorphLine *morphLine; NSDictionary *infoDict; NSDictionary *morphLineDict; NSSize interCellSpacing = {2, 2}; self = [super initWithContentsOfFile:path]; morphLines = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:20]; selectedLines = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:20]; if (![NSBundle loadNibNamed:NIB_NAME owner: self]) { [self autorelease]; return nil; } previewMatrix = [[NSMatrix allocWithZone:[self zone]] initWithFrame:[previewBox bounds] mode:0 cellClass:[PreviewCell class] numberOfRows:1 numberOfColumns:5]; [previewMatrix setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [previewMatrix setAutosizesCells:YES]; [previewMatrix setDelegate:self]; [previewMatrix setIntercellSpacing:interCellSpacing]; [(NSBox *)previewBox setContentView:previewMatrix]; [firstEditor setDelta:0.0]; [lastEditor setDelta:1.0]; [[InspectorController sharedInspectorController] registerInspector:[MorphLineInspector sharedInspector]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selectionChanged:) name:NOTIFICATION_SELECTION_CHANGED object:nil]; if (!filePath) return self; [[self window] setTitle:[NSLocalizedString (@"Opening file ", @"Opening window title") stringByAppendingString:filePath]]; infoDict = [[[NSDictionary allocWithZone:[self zone]] initWithContentsOfFile:[filePath stringByAppendingPathComponent:DICT_PATHCOMPONENT]] autorelease]; if (!infoDict) { [self autorelease]; return nil; } filename = [infoDict objectForKey:DICT_IMAGE0_PATH_KEY]; if ([filename characterAtIndex:0] == '/') fullPath = filename; else fullPath = [filePath stringByAppendingPathComponent:filename]; image = [[[NSImage allocWithZone:[self zone]] initWithContentsOfFile:fullPath] autorelease]; [self setImage:image atDelta:0.0]; filename = [infoDict objectForKey:DICT_IMAGE1_PATH_KEY]; if ([filename characterAtIndex:0] == '/') fullPath = filename; else fullPath = [filePath stringByAppendingPathComponent:filename]; image = [[[NSImage allocWithZone:[self zone]] initWithContentsOfFile:fullPath] autorelease]; [self setImage:image atDelta:1.0]; if ([infoDict objectForKey:@"frameWidth"]) [frameWidthField setStringValue:[infoDict objectForKey:@"frameWidth"]]; if ([infoDict objectForKey:@"frameHeight"]) [frameHeightField setStringValue:[infoDict objectForKey:@"frameHeight"]]; lineDefs = [infoDict objectForKey:DICT_MORPHLINES_KEY]; for (i = 0; i < [lineDefs count]; ++i) { morphLineDict = [lineDefs objectAtIndex:i]; morphLine = [[MorphLine allocWithZone:[self zone]] initWithValuesInDict:morphLineDict]; if (morphLine != nil) [self addMorphLine:morphLine]; } [[self window] setRepresentedFilename:path]; [[self window] setDocumentEdited:NO]; [self calcPreview:nil]; if (filePath) [[self window] setTitleWithRepresentedFilename:filePath]; return self; } - (void) selectionChanged:(NSNotification *)sender { [firstEditor setNeedsDisplay:YES]; [lastEditor setNeedsDisplay:YES]; [previewMatrix setNeedsDisplay:YES]; } - (NSArray *) morphLines { return morphLines; } - (void) addMorphLine:(MorphLine *)morphLine { [morphLines addObject:morphLine]; [firstEditor setNeedsDisplay:YES]; [lastEditor setNeedsDisplay:YES]; [[self window] setDocumentEdited:YES]; } - (void) deleteMorphLine:(MorphLine *)morphLine { [morphLines removeObject:morphLine]; [firstEditor setNeedsDisplay:YES]; [lastEditor setNeedsDisplay:YES]; [selectedLines removeObject:morphLine]; [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil]; [[self window] setDocumentEdited:YES]; } // Access methods - (void) setImage:(NSImage *)image atDelta:(float) delta { NSSize size = [image size]; if (delta < 0.5) { [firstImage release]; firstImage = [image retain]; } else { [lastImage release]; lastImage = [image retain]; } [image setScalesWhenResized:YES]; [frameWidthField setIntValue:size.width]; [frameHeightField setIntValue:size.height]; [[self window] setDocumentEdited:YES]; } - (NSImage *) imageAtDelta:(float)delta { if (delta < 0.5) return firstImage; else return lastImage; } - (NSWindow *)window { return [firstEditor window]; } // Actions - (void) save:sender { NSFileManager *fileManager; NSString *dirPath; NSString *fullPath; NSMutableDictionary *dict; NSImageRep *rep; NSEnumerator *repEnum; NSImage *im0; NSImage *im1; NSData *im0Data = nil; NSData *im1Data = nil; if (filePath == nil) return [self saveAs:sender]; // Create the info dict dict = [NSMutableDictionary dictionaryWithCapacity:10]; // Add the morph lines to the dict [dict setObject:[self morphLines] forKey: DICT_MORPHLINES_KEY]; // Get the NSData for the images im0 = [self imageAtDelta:0.0]; im1 = [self imageAtDelta:1.0]; repEnum = [[im0 representations] objectEnumerator]; while ((rep = [repEnum nextObject])) { if ([rep respondsToSelector:@selector(EPSRepresentation)]) { im0Data = [rep performSelector:@selector(EPSRepresentation)]; [dict setObject:@"Image_0.eps" forKey: DICT_IMAGE0_PATH_KEY]; break; } } repEnum = [[im1 representations] objectEnumerator]; while ((rep = [repEnum nextObject])) { if ([rep respondsToSelector:@selector(EPSRepresentation)]) { im1Data = [rep performSelector:@selector(EPSRepresentation)]; [dict setObject:@"Image_0.eps" forKey: DICT_IMAGE1_PATH_KEY]; break; } } if (im0Data == nil) { [dict setObject:@"Image_0.tiff" forKey: DICT_IMAGE0_PATH_KEY]; im0Data = [im0 TIFFRepresentation]; } if (im1Data == nil) { [dict setObject:@"Image_1.tiff" forKey: DICT_IMAGE1_PATH_KEY]; im1Data = [im1 TIFFRepresentation]; } [dict setObject:[NSString stringWithFormat:@"%i", [frameHeightField intValue]] forKey:@"frameHeight"]; [dict setObject:[NSString stringWithFormat:@"%i", [frameWidthField intValue]] forKey:@"frameWidth"]; // (Re)create the file package dirPath = [self filePath]; fileManager = [NSFileManager defaultManager]; [fileManager removeFileAtPath:filePath handler:nil]; [fileManager createDirectoryAtPath:filePath attributes:nil]; // Save the info plist fullPath = [filePath stringByAppendingPathComponent:DICT_PATHCOMPONENT]; NSAssert1 ( [dict writeToFile:fullPath atomically:NO], @"Failed to write info dict %@", fullPath); // Save the image data fullPath = [dirPath stringByAppendingPathComponent:[dict objectForKey: DICT_IMAGE0_PATH_KEY]]; NSAssert1 ( [im0Data writeToFile:fullPath atomically:NO], @"Failed to write image %@", fullPath); fullPath = [dirPath stringByAppendingPathComponent:[dict objectForKey: DICT_IMAGE1_PATH_KEY]]; NSAssert1 ( [im1Data writeToFile:fullPath atomically:NO], @"Failed to write image %@", fullPath); [[self window] setDocumentEdited:NO]; } - (void) saveAs:sender { NSSavePanel *sp; NSString *path; NSString *fname; NSString *dname; int result; [[self window] setDocumentEdited:NO]; path = [self filePath]; if (path) { dname = [path stringByDeletingLastPathComponent]; fname = [path lastPathComponent]; } else { dname = NSHomeDirectory(); fname = nil; } sp = [NSSavePanel savePanel]; [sp setRequiredFileType: MORPH_DOC_EXTENTION]; result = [sp runModalForDirectory:dname file:fname]; if (result == NSOKButton) { path = [sp filename]; [self setFilePath:[sp filename]]; [self save:self]; } } - (void) saveTo:sender { [[self window] setDocumentEdited:NO]; return; } - (void) saveFrames:sender { NSString *path; NSString *fullPath; NSSavePanel *sp; NSString *dname; NSString *fname; NSMutableDictionary *dict; int result; NSFileManager *fileManager; int frameCount; NSSize frameSize; path = [self filePath]; if (path) { dname = [path stringByDeletingLastPathComponent]; fname = [[path lastPathComponent] stringByDeletingPathExtension]; } else { dname = NSHomeDirectory(); fname = nil; } sp = [NSSavePanel savePanel]; [sp setRequiredFileType: XMOVIE_EXTENTION]; [sp setAccessoryView:frameSettingsView]; result = [sp runModalForDirectory:dname file:fname]; if (result != NSOKButton) return; path = [sp filename]; frameCount = [frameCountField intValue]; frameSize.width = [frameWidthField floatValue]; frameSize.height = [frameHeightField floatValue]; // (Re)create the file package fileManager = [NSFileManager defaultManager]; [fileManager removeFileAtPath:path handler:nil]; [fileManager createDirectoryAtPath:path attributes:nil]; // Save the info plist fullPath = [path stringByAppendingPathComponent:DICT_PATHCOMPONENT]; dict = [NSMutableDictionary dictionaryWithCapacity:10]; // Insert code to fill the dictionary with usefull information NSAssert1 ( [dict writeToFile:fullPath atomically:NO], @"Failed to write info dict %@", fullPath); [[self window] display]; [self calcFramesAndSaveToPath:path count:frameCount size:frameSize]; [[[NSApplication sharedApplication] delegate] application:[NSApplication sharedApplication] openFile:path]; } - (void) selectAll:sender { [selectedLines removeAllObjects]; [selectedLines addObjectsFromArray:[self morphLines]]; [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil]; } - (void) selectNone:sender { [selectedLines removeAllObjects]; [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil]; } - (void) addToCurrentSelection:(id)obj { if (obj != nil && ![selectedLines containsObject:obj]) [selectedLines addObject:obj]; [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil]; } - (void) removeFromCurrentSelection:(id)obj { if (obj != nil && [selectedLines containsObject:obj]) { [selectedLines removeObject:obj]; [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil]; } } - (NSArray *) currentSelection { return selectedLines; } - (void) calcPreview:sender { NSBitmapImageRep *firstBitmap; NSBitmapImageRep *lastBitmap; NSBitmapImageRep *bitmap; Morpher *morpher; float delta; NSArray *cells; PreviewCell *cell; int i; NSSize size; NSSize winSize; firstBitmap = [[[self imageAtDelta:0] representations] lastObject]; lastBitmap = [[[self imageAtDelta:1] representations] lastObject]; cells = [previewMatrix cells]; size = [previewMatrix cellSize]; [progressIndicator setDoubleValue:0]; winSize = size; winSize.height += 20; [progressIndicator setDoubleValue:0]; [[progressIndicator window] setContentSize:winSize]; [[progressIndicator window] makeKeyAndOrderFront:nil]; [[progressIndicator window] display]; morpher = [[Morpher allocWithZone:[self zone]] initWithFirstBitmap:firstBitmap lastBitmap:lastBitmap morphLines:morphLines]; for (i = 0; i < [cells count]; ++i) { cell = [cells objectAtIndex:i]; delta = i / (float) ([cells count] - 1.0); [cell setShouldDrawLines:YES]; [progressIndicator setDoubleValue:delta]; [progressIndicator display]; bitmap = [[NSBitmapImageRep allocWithZone:[self zone]] initWithBitmapDataPlanes:NULL pixelsWide:size.width pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(size.width + 1) * 3 bitsPerPixel:24]; [morpher calcMorphBitmap:bitmap atDelta:delta]; [cell setBitmap:bitmap]; [cell setDelta:delta]; [cell setDelegate:self]; [previewMatrix display]; [progressView lockFocus]; [bitmap draw]; [progressView unlockFocus]; [[progressView window] flushWindow]; [[NSDPSContext currentContext] flush]; [bitmap release]; } [morpher release]; [[progressIndicator window] orderOut:nil]; return; } - (void) calcFramesAndSaveToPath:(NSString *)dirPath count:(unsigned int)frameCount size:(NSSize)frameSize { NSBitmapImageRep *firstBitmap; NSBitmapImageRep *lastBitmap; NSBitmapImageRep *bitmap; NSData *data; Morpher *morpher; float delta; NSString *path; int frameNum = 0; NSSize winSize; winSize = frameSize; winSize.height += 20; [progressIndicator setDoubleValue:0]; [[progressIndicator window] setContentSize:winSize]; [[progressIndicator window] makeKeyAndOrderFront:nil]; [[progressIndicator window] display]; bitmap = [[NSBitmapImageRep allocWithZone:[self zone]] initWithBitmapDataPlanes:NULL pixelsWide:frameSize.width pixelsHigh:frameSize.height bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(frameSize.width + 1) * 3 bitsPerPixel:24]; firstBitmap = [[[self imageAtDelta:0] representations] lastObject]; lastBitmap = [[[self imageAtDelta:1] representations] lastObject]; morpher = [[Morpher allocWithZone:[self zone]] initWithFirstBitmap:firstBitmap lastBitmap:lastBitmap morphLines:morphLines]; for (frameNum = 0; frameNum < frameCount; ++frameNum) { delta = frameNum / (float) (frameCount - 1.0); [progressIndicator setDoubleValue:delta]; [progressIndicator display]; [morpher calcMorphBitmap:bitmap atDelta:delta]; [progressView lockFocus]; [bitmap draw]; [progressView unlockFocus]; [[progressView window] flushWindow]; [[NSDPSContext currentContext] flush]; data = [bitmap TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:20]; path = [dirPath stringByAppendingPathComponent:[NSString stringWithFormat:@"Image_%d.tiff", frameNum]]; [data writeToFile:path atomically:NO]; } [morpher release]; [[progressIndicator window] orderOut:nil]; } - (void)windowDidBecomeMain:(NSNotification *)notification { [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self] postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.