home *** CD-ROM | disk | FTP | other *** search
- // 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
-