/* Project: LaternaMagica AppController.m Copyright (C) 2006-2017 Riccardo Mottola Author: Riccardo Mottola Created: 2006-01-16 This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This application is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if defined(__MINGW32__) #define srandom srand #define random rand #endif #include #include #import "AppController.h" #import "LMImage.h" #import "PRScale.h" #if !defined (GNUSTEP) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4) #define NSInteger int #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 #define NSImageGamma @"NSImageGamma" #define NSImageEXIFData @"NSImageEXIFData" #endif #endif #define LM_KEY_DESTROYRECYCLE @"DestroyOrRecycle" #define LM_KEY_ASKDELETING @"AskBeforeDeleting" @implementation AppController - (id) init { if ((self = [super init])) { /* initialize random number generator */ srandom(time(NULL)); } return self; } - (void)awakeFromNib { NSRect frame; window = smallWindow; view = smallView; frame = [[NSScreen mainScreen] frame]; fullWindow = [[LMWindow alloc] initWithContentRect: frame styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO]; [fullWindow setAutodisplay:YES]; [fullWindow setExcludedFromWindowsMenu: YES]; [fullWindow setBackgroundColor: [NSColor blackColor]]; [smallView setFrame:[scrollView documentVisibleRect]]; [smallView setImageAlignment:NSImageAlignTopLeft]; [smallWindow setDelegate:smallView]; fullView = [[LMFlipView alloc] initWithFrame:[fullWindow frame]]; [fullView setImageScaling: NSScaleNone]; [fullView setImageAlignment:NSImageAlignCenter]; [fullView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; [fullView setController:self]; /* avoid replacing the contentview with a NSControl subclass, thus add a subview instead */ [[fullWindow contentView] addSubview: fullView]; [fullWindow setInitialFirstResponder:fullView]; [fullWindow setDelegate:fullView]; /* register the file view as drag destionation */ [fileListView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]]; /* add an observer for the file table view */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_selectionDidChange:) name:NSTableViewSelectionDidChangeNotification object:fileListView]; /* add an observer for the window resize */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResize:) name:NSWindowDidResizeNotification object:window]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } - (void)addFile:(NSString *)filename { if([fileListData addPathAndRecurse:filename]) [fileListView reloadData]; } - (void)addFiles:(id)sender { NSOpenPanel *openPanel; NSArray *files; NSEnumerator *e; NSString *filename; NSFileManager *fmgr; NSDictionary *attrs; openPanel = [NSOpenPanel openPanel]; [openPanel setAllowsMultipleSelection:YES]; [openPanel setCanChooseDirectories:YES]; [openPanel setCanChooseFiles:YES]; if ([openPanel runModalForTypes:NULL] != NSOKButton) return; files = [openPanel filenames]; e = [files objectEnumerator]; fmgr = [NSFileManager defaultManager]; while ((filename = (NSString*)[e nextObject])) { attrs = [fmgr fileAttributesAtPath:filename traverseLink:YES]; if (attrs) { [self addFile:filename]; } else { NSLog(@"open panel did not return a valid path"); } } [fileListView selectRow: [fileListView numberOfRows]-1 byExtendingSelection: NO]; } // scale image view according to options - (void)scaleView:(NSImage *) image { NSPoint rectOrigin; NSSize rectSize; if (image == nil) return; rectSize = [window frame].size; if (scaleToFit) { NSSize imageSize; NSAffineTransform *at; float scaleH, scaleW; float scale; imageSize = [image size]; scaleW = rectSize.width / imageSize.width; scaleH = rectSize.height / imageSize.height; if (scaleW < scaleH) scale = scaleW; else scale = scaleH; at = [NSAffineTransform transform]; [at scaleBy:scale]; [view setFrameSize:[at transformSize:imageSize]]; } else { [view setFrameSize:[image size]]; } rectOrigin = NSMakePoint((rectSize.width - [view frame].size.width)/2, (rectSize.height - [view frame].size.height)/2); [view setFrameOrigin:rectOrigin]; } - (void)changeImage:(LMImage *) image { NSImage *nsImage; NSImage *img; nsImage = [[NSImage alloc] initByReferencingFile:[image path]]; [nsImage autorelease]; img = nsImage; if ([image rotation] > 0) { NSImage *destImage; destImage = [self rotate: nsImage byAngle:[image rotation]]; img = destImage; } [self scaleView: img]; [view setImage: img]; [view setNeedsDisplay:YES]; [[view superview] setNeedsDisplay:YES]; /* we don't need to update the full-screen window title */ [smallWindow setTitleWithRepresentedFilename:[image name]]; } - (IBAction)setScaleToFit:(id)sender { if ([fitButton state] == NSOnState) { scaleToFit = YES; [view setImageScaling:NSScaleToFit]; } else { scaleToFit = NO; [view setImageScaling:NSScaleNone]; } [scrollView setHasVerticalScroller:!scaleToFit]; [scrollView setHasHorizontalScroller:!scaleToFit]; [self scaleView:[view image]]; [view setNeedsDisplay:YES]; } /** method called as a notification from the selection change */ - (void)_selectionDidChange :(NSNotification *)notif { NSTableView *table; int selectedRow; table = [notif object]; selectedRow = [table selectedRow]; if (selectedRow >= 0) [self changeImage:[fileListData imageAtIndex:selectedRow]]; } /** method called as a notification from the window resize or if scale preferences changed */ - (void)_windowDidResize :(NSNotification *)notif { [self scaleView: [view image]]; } - (IBAction)setFullScreen: (id)sender { NSImage *image; /* trick for GS so that we don't have order problems with GWorkspace */ [window makeKeyAndOrderFront: self]; /* we choose not to respond to key events if not in fullscreen */ if ([sender isKindOfClass:[NSEvent class]] && [fullScreenMenuItem state] == NSOffState) return; image = [view image]; [image retain]; /* check the sender and set the other item accordingly */ if (sender == fullScreenButton) [fullScreenMenuItem setState:[fullScreenButton state]]; else { if ([fullScreenMenuItem state] == NSOnState) [fullScreenMenuItem setState:NSOffState]; else [fullScreenMenuItem setState:NSOnState]; [fullScreenButton setState:[fullScreenMenuItem state]]; } if ([fullScreenButton state] == NSOnState) { [smallView setImage: nil]; [fullWindow setLevel: NSScreenSaverWindowLevel]; window = fullWindow; view = fullView; } else { [fullView setImage: nil]; [fullWindow orderOut:self]; window = smallWindow; view = smallView; } [view setImage: image]; [image release]; [self setScaleToFit: self]; [view setNeedsDisplay:YES]; [[view superview] setNeedsDisplay:YES]; [window makeKeyAndOrderFront: self]; } - (IBAction)prevImage:(id)sender { int sr; int rows; rows = [fileListView numberOfRows]; if (rows > 0) { sr = [fileListView selectedRow]; if (sr > 0) sr--; else sr = (rows - 1); [fileListView selectRow: sr byExtendingSelection: NO]; } } - (IBAction)nextImage:(id)sender { int sr; int rows; rows = [fileListView numberOfRows]; if (rows > 0) { sr = [fileListView selectedRow]; if (sr < (rows - 1)) sr++; else sr = 0; [fileListView selectRow: sr byExtendingSelection: NO]; } } - (IBAction)removeAllImages:(id)sender { NSInteger rows; NSInteger i; rows = [fileListView numberOfRows]; for (i = (rows - 1); i >= 0 ; i--) [fileListData removeObjectAtIndex: i]; [fileListView reloadData]; [view setImage: nil]; [window setTitle:@"None"]; } - (IBAction)scrambleList:(id)sender { NSInteger selRow; [fileListData scrambleObjects]; [fileListView reloadData]; /* we reload the image directly without calling selectRow, the selected row did not actually change and no notification triggers */ selRow = [fileListView selectedRow]; if (selRow > 0) [self changeImage: [fileListData imageAtIndex: (NSUInteger)selRow]]; } - (IBAction)removeImage:(id)sender { int sr; int rows; rows = [fileListView numberOfRows]; if (rows >= 0) { sr = [fileListView selectedRow]; if (sr >= 0) { [fileListData removeObjectAtIndex: sr]; [fileListView reloadData]; rows = [fileListView numberOfRows]; if (rows > 0) { // if we remove the last image, the selection changes // otherwise no selection change notification is generated // and thus we update simply the image if (sr >= rows) [fileListView selectRow: rows-1 byExtendingSelection: NO]; else [self changeImage: [fileListData imageAtIndex: sr]]; } else { // no image to select, we clear the display [view setImage: nil]; [window setTitle:@"None"]; } } } } - (IBAction)eraseImage:(id)sender { int sr; BOOL shallErase; NSUserDefaults *defaults; defaults = [NSUserDefaults standardUserDefaults]; sr = [fileListView selectedRow]; if (sr >= 0) { if ([defaults boolForKey:LM_KEY_ASKDELETING]) { int result; result = NSRunAlertPanel(nil, @"Really delete the image from disk?", @"Delete", @"Abort", nil); shallErase = NO; if (result == NSAlertDefaultReturn) shallErase = YES; } else shallErase = YES; if (shallErase) { NSWorkspace *ws; NSString *fileOperation; NSInteger opTag; NSString *folder; NSString *file; if ([defaults boolForKey:LM_KEY_DESTROYRECYCLE]) fileOperation = NSWorkspaceDestroyOperation; else fileOperation = NSWorkspaceRecycleOperation; folder = [[fileListData pathAtIndex:sr]stringByDeletingLastPathComponent]; file = [[fileListData pathAtIndex:sr] lastPathComponent]; ws = [NSWorkspace sharedWorkspace]; opTag = 1; [ws performFileOperation:fileOperation source:folder destination:nil files:[NSArray arrayWithObject: file] tag:&opTag]; [self removeImage:self]; } } } - (IBAction)rotateImage90:(id)sender { NSImage *destImage; LMImage *imageInfo; imageInfo = [fileListData imageAtIndex:[fileListView selectedRow]]; [imageInfo setRotation: 90]; destImage = [self rotate: [view image] byAngle:90]; [self scaleView:destImage]; [view setImage: destImage]; [view setNeedsDisplay:YES]; [[view superview] setNeedsDisplay:YES]; } - (IBAction)rotateImage180:(id)sender { NSImage *destImage; LMImage *imageInfo; imageInfo = [fileListData imageAtIndex:[fileListView selectedRow]]; [imageInfo setRotation: 180]; destImage = [self rotate: [view image] byAngle:180]; [self scaleView:destImage]; [view setImage: destImage]; [view setNeedsDisplay:YES]; [[view superview] setNeedsDisplay:YES]; } - (IBAction)rotateImage270:(id)sender { NSImage *destImage; LMImage *imageInfo; imageInfo = [fileListData imageAtIndex:[fileListView selectedRow]]; [imageInfo setRotation: 270]; destImage = [self rotate: [view image] byAngle: 270]; [self scaleView:destImage]; [view setImage: destImage]; [[view superview] setNeedsDisplay:YES]; } - (NSImage *)rotate: (NSImage *)image byAngle:(unsigned)angle { NSBitmapImageRep *srcImageRep; NSImage *destImage; NSBitmapImageRep *destImageRep; NSMutableDictionary *imgProps; NSInteger x, y; NSInteger w, h; NSInteger newW, newH; NSInteger srcSamplesPerPixel; NSInteger destSamplesPerPixel; unsigned char *srcData; unsigned char *destData; unsigned char *p1, *p2; NSSize oldRepSize, newRepSize; NSSize oldImgSize, newImgSize; register NSInteger srcBytesPerPixel; register NSInteger destBytesPerPixel; register NSInteger srcBytesPerRow; register NSInteger destBytesPerRow; /* get source image representation and associated information */ oldImgSize = [image size]; srcImageRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]]; oldRepSize = [srcImageRep size]; w = [srcImageRep pixelsWide]; h = [srcImageRep pixelsHigh]; if (angle == 90 || angle == 270) { newH = w; newW = h; newImgSize = NSMakeSize(oldImgSize.height, oldImgSize.width); newRepSize = NSMakeSize(oldRepSize.height, oldRepSize.width); } else { newH = h; newW = w; newImgSize = oldImgSize; newRepSize = oldRepSize; } srcSamplesPerPixel = [srcImageRep samplesPerPixel]; destSamplesPerPixel = srcSamplesPerPixel; srcBytesPerRow = [srcImageRep bytesPerRow]; srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8; srcSamplesPerPixel = [srcImageRep samplesPerPixel]; imgProps = [[NSMutableDictionary alloc] init]; [imgProps setValue:[srcImageRep valueForProperty:NSImageCompressionMethod] forKey:NSImageCompressionMethod]; [imgProps setValue:[srcImageRep valueForProperty:NSImageCompressionFactor] forKey:NSImageCompressionFactor]; [imgProps setValue:[srcImageRep valueForProperty:NSImageEXIFData] forKey:NSImageEXIFData]; [imgProps setValue:[srcImageRep valueForProperty:NSImageGamma] forKey:NSImageGamma]; [imgProps setValue:[srcImageRep valueForProperty:NSImageColorSyncProfileData] forKey:NSImageColorSyncProfileData]; NSLog(@"Properties: %@", imgProps); destSamplesPerPixel = srcSamplesPerPixel; destImage = [[NSImage alloc] initWithSize:newImgSize]; destImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:newW pixelsHigh:newH bitsPerSample:[srcImageRep bitsPerSample] samplesPerPixel:[srcImageRep samplesPerPixel] hasAlpha:[srcImageRep hasAlpha] isPlanar:[srcImageRep isPlanar] colorSpaceName:[srcImageRep colorSpaceName] bytesPerRow:0 bitsPerPixel:0]; [destImageRep setSize:newRepSize]; [destImageRep setProperty:NSImageEXIFData withValue:[imgProps valueForKey:NSImageEXIFData]]; [destImageRep setProperty:NSImageColorSyncProfileData withValue:[imgProps valueForKey:NSImageColorSyncProfileData]]; [destImageRep setProperty:NSImageGamma withValue:[imgProps valueForKey:NSImageGamma]]; [imgProps release]; srcData = [srcImageRep bitmapData]; destData = [destImageRep bitmapData]; destBytesPerRow = [destImageRep bytesPerRow]; destBytesPerPixel = [destImageRep bitsPerPixel] / 8; if (angle == 90) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned s; p1 = srcData + srcBytesPerRow * y + srcBytesPerPixel * x; p2 = destData + destBytesPerRow * (w-x-1) + destBytesPerPixel * y; for (s = 0; s < srcSamplesPerPixel; s++) p2[s] = p1[s]; } } else if (angle == 180) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned s; p1 = srcData + srcBytesPerRow * y + srcBytesPerPixel * x; p2 = destData + destBytesPerRow * (h-y-1) + destBytesPerPixel * (w-x-1); for (s = 0; s < srcSamplesPerPixel; s++) p2[s] = p1[s]; } } else if (angle == 270) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned s; p1 = srcData + srcBytesPerRow * y + srcBytesPerPixel * x; p2 = destData + destBytesPerRow * x + destBytesPerPixel * (h-y-1); for (s = 0; s < srcSamplesPerPixel; s++) p2[s] = p1[s]; } } [destImage addRepresentation:destImageRep]; [destImageRep release]; [destImage autorelease]; return destImage; } - (BOOL)validateMenuItem:(id)sender { /* the menu item returned is not the same object, so we use isEqual */ if ([sender isEqual:saveAsMenuItem]) { if ([view image] == nil) return NO; } return YES; } - (void)updateImageCount { [fieldImageCount setIntValue:(int)[fileListData imageCount]]; } - (IBAction)saveImageAs:(id)sender { NSImage *srcImage; NSBitmapImageRep *srcImageRep; NSData *dataOfRep = nil; NSDictionary *repProperties; NSString *origFileName; NSString *filenameNoExtension; origFileName = [[fileListData pathAtIndex:[fileListView selectedRow]] lastPathComponent]; filenameNoExtension = [origFileName stringByDeletingPathExtension]; savePanel = [NSSavePanel savePanel]; [savePanel setDelegate: self]; /* if the accessory view comes from a window it needs a retain */ [savePanel setAccessoryView: [saveOptionsView retain]]; /* simulate clicks to be sure interface is consistent */ [jpegCompressionSlider performClick:nil]; [fileTypePopUp sendAction:@selector(setCompressionType:) to:self]; if ([savePanel runModalForDirectory:@"" file:filenameNoExtension] == NSFileHandlingPanelOKButton) { NSString *fileName; int selItem; srcImage = [view image]; srcImageRep = [NSBitmapImageRep imageRepWithData:[srcImage TIFFRepresentation]]; fileName = [savePanel filename]; selItem = [fileTypePopUp indexOfSelectedItem]; if (selItem == 0) { NSLog(@"Tiff"); repProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:NSTIFFCompressionLZW] forKey:NSImageCompressionMethod]; dataOfRep = [srcImageRep representationUsingType: NSTIFFFileType properties:repProperties]; } else if (selItem == 1) { NSLog(@"Jpeg"); repProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:[jpegCompressionSlider floatValue]/100] forKey:NSImageCompressionFactor]; dataOfRep = [srcImageRep representationUsingType: NSJPEGFileType properties:repProperties]; } [dataOfRep writeToFile:fileName atomically:NO]; } } /* ===== delegates =====*/ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { [self addFile:filename]; [fileListView selectRow: [fileListView numberOfRows]-1 byExtendingSelection: NO]; return YES; } /* save panel delegates */ /** change the file type */ - (IBAction)setCompressionType:(id)sender { int selItem; selItem = [fileTypePopUp indexOfSelectedItem]; if (selItem == 0) { NSLog(@"Tiff"); [jpegCompressionSlider setEnabled:NO]; [jpegCompressionField setEnabled:NO]; #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_2) [savePanel setRequiredFileType:@"tiff"]; #else [savePanel setAllowedFileTypes:[NSArray arrayWithObjects: @"tif", @"tiff", nil]]; #endif } else if (selItem == 1) { NSLog(@"Jpeg"); [jpegCompressionSlider setEnabled:YES]; [jpegCompressionField setEnabled:YES]; #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_2) [savePanel setRequiredFileType:@"jpg"]; #else [savePanel setAllowedFileTypes:[NSArray arrayWithObjects: @"jpg", @"jpeg", nil]]; #endif } } /** keep the slider and the text view of the compression level in sync */ - (IBAction)setCompressionLevel:(id)sender { if (sender == jpegCompressionField) [jpegCompressionSlider takeFloatValueFrom:sender]; else [jpegCompressionField takeFloatValueFrom:sender]; } /* exporter */ - (IBAction)exportImages:(id)sender { [exporterPanel makeKeyAndOrderFront:self]; [exportProgress setDoubleValue: 0.0]; } - (IBAction)setExportPath:(id)sender { NSOpenPanel *openPanel; NSString *choosenFilePath; openPanel = [NSOpenPanel openPanel]; [openPanel setAllowsMultipleSelection:NO]; [openPanel setCanChooseDirectories:YES]; [openPanel setCanChooseFiles:NO]; if ([openPanel runModalForTypes:NULL] != NSOKButton) { return; } choosenFilePath = [openPanel filename]; [fieldOutputPath setStringValue:choosenFilePath]; } - (IBAction)execExportImages:(id)sender { int givenHeight; int givenWidth; NSDictionary *repProperties; NSString *origFileName; NSString *filenameNoExtension; NSImage *srcImage; NSBitmapImageRep *srcImageRep; NSData *dataOfRep; NSString *destFileName; NSString *destFileExtension; NSString *destFolder; NSInteger i; givenHeight = [fieldHeight intValue]; givenWidth = [fieldWidth intValue]; destFolder = [fieldOutputPath stringValue]; if ([popupFileType indexOfSelectedItem] == 0) destFileExtension = @"tiff"; else destFileExtension = @"jpeg"; [exportProgress setDoubleValue: 0.0]; [exporterPanel displayIfNeeded]; for (i = 0; i < [fileListView numberOfRows]; i++) { NSInteger newW, newH; double aspectRatio; NSBitmapImageRep *scaledImageRep; NSAutoreleasePool *pool; LMImage *lmImage; lmImage = [fileListData imageAtIndex:i]; /* create a local pool to avoid the autorelease to grow too much */ pool = [[NSAutoreleasePool alloc] init]; origFileName = [lmImage name]; filenameNoExtension = [origFileName stringByDeletingPathExtension]; srcImage = [[NSImage alloc] initByReferencingFile:[lmImage path]]; if ([lmImage rotation] > 0) { NSImage *rotImage; rotImage = [self rotate:srcImage byAngle:[lmImage rotation]]; [rotImage retain]; [srcImage release]; srcImage = rotImage; } srcImageRep = [[srcImage representations] objectAtIndex:0];; #if !defined (GNUSTEP) && (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3) /* since 10.4 we have different Alpha format position, let's convert it */ NSMutableDictionary *imgProps; if ([srcImageRep bitmapFormat] != 0) { NSInteger x, y; NSInteger w, h; BOOL alphaFirst; NSImage *destImage; NSBitmapImageRep *destImageRep; NSInteger srcBytesPerRow; NSInteger destBytesPerRow; NSInteger srcBytesPerPixel; NSInteger destBytesPerPixel; NSLog(@"We have a non-standard format, let's try to convert it"); alphaFirst = [srcImageRep bitmapFormat] & NSAlphaFirstBitmapFormat; if ([srcImageRep bitsPerSample] == 8) { unsigned char *srcData; unsigned char *destData; unsigned char *p1; unsigned char *p2; /* swap Alpha is hopefully only for chunky images */ if (alphaFirst) { imgProps = [[NSMutableDictionary alloc] init]; [imgProps setValue:[srcImageRep valueForProperty:NSImageCompressionMethod] forKey:NSImageCompressionMethod]; [imgProps setValue:[srcImageRep valueForProperty:NSImageCompressionFactor] forKey:NSImageCompressionFactor]; [imgProps setValue:[srcImageRep valueForProperty:NSImageEXIFData] forKey:NSImageEXIFData]; w = [srcImageRep pixelsWide]; h = [srcImageRep pixelsHigh]; srcBytesPerRow = [srcImageRep bytesPerRow]; srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8; destImage = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; destImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:w pixelsHigh:h bitsPerSample:8 samplesPerPixel:[srcImageRep samplesPerPixel] hasAlpha:[srcImageRep hasAlpha] isPlanar:NO colorSpaceName:[srcImageRep colorSpaceName] bytesPerRow:0 bitsPerPixel:0]; destBytesPerRow = [destImageRep bytesPerRow]; destBytesPerPixel = [destImageRep bitsPerPixel] / 8; srcData = [srcImageRep bitmapData]; destData = [destImageRep bitmapData]; if ([srcImageRep samplesPerPixel] == 2) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { p1 = srcData + srcBytesPerRow * y + srcBytesPerPixel * x; p2 = destData + destBytesPerRow * y + destBytesPerPixel * x; p2[0] = p1[1]; p2[1] = p1[0]; } } else { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { p1 = srcData + srcBytesPerRow * y + srcBytesPerPixel * x; p2 = destData + destBytesPerRow * y + destBytesPerPixel * x; p2[0] = p1[1]; p2[1] = p1[2]; p2[2] = p1[3]; p2[3] = p1[0]; } } [destImageRep setProperty:NSImageEXIFData withValue:[imgProps objectForKey:NSImageEXIFData]]; [destImageRep setSize:[srcImageRep size]]; [destImage addRepresentation:destImageRep]; [destImageRep release]; [srcImage release]; srcImage = destImage; [imgProps release]; } } else /* for 16 bit */ { } } #endif newW = [srcImageRep pixelsWide]; newH = [srcImageRep pixelsHigh]; aspectRatio = (double)newW / newH; NSLog(@"aspect ratio: %f", aspectRatio); switch([popupConstraints indexOfSelectedItem]) { case 0: /* none */ break; case 1: /* width */ newW = givenWidth; newH = givenWidth / aspectRatio; break; case 2: /* height */ newH = givenHeight; newW = givenHeight * aspectRatio; break; case 3: /* both */ newW = givenWidth; newH = givenWidth / aspectRatio; if (newH > givenHeight) { newH = givenHeight; newW = givenHeight * aspectRatio; } break; case 4: /* largest side */ if ([srcImageRep pixelsHigh] > [srcImageRep pixelsWide]) { newH = givenWidth; newW = givenWidth * aspectRatio; } else { newW = givenWidth; newH = givenWidth / aspectRatio; } break; default: NSLog(@"Unexpected constraint selection value."); } if (newW == [srcImageRep pixelsWide]) { NSLog(@"nothing"); scaledImageRep = srcImageRep; } else { NSImage *scaledImage; PRScale *scaleFilter; scaleFilter = [[PRScale alloc] init]; scaledImage = [scaleFilter scaleImage:srcImage :newW :newH :BILINEAR :nil]; [scaleFilter release]; scaledImageRep = [NSBitmapImageRep imageRepWithData:[scaledImage TIFFRepresentation]]; } if ([popupFileType indexOfSelectedItem] == 0) { repProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:NSTIFFCompressionLZW] forKey:NSImageCompressionMethod]; dataOfRep = [scaledImageRep representationUsingType: NSTIFFFileType properties:repProperties]; } else { float quality; switch ([popupFileQuality indexOfSelectedItem]) { case 0: quality = 1.0; break; case 1: quality = 0.75; break; case 2: quality = 0.66; break; case 3: quality = 0.4; break; default: quality = 0.5; } repProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:quality] forKey:NSImageCompressionFactor]; dataOfRep = [scaledImageRep representationUsingType: NSJPEGFileType properties:repProperties]; } [srcImage release]; destFileName = [destFolder stringByAppendingPathComponent:[filenameNoExtension stringByAppendingPathExtension: destFileExtension]]; NSLog(@"%@", destFileName); if (dataOfRep != nil) { [dataOfRep writeToFile:destFileName atomically:NO]; } [exportProgress setDoubleValue: ((double)(i+1)*100)/(double)[fileListView numberOfRows]]; [exporterPanel displayIfNeeded]; [pool release]; } } /* preferences */ - (IBAction)showPreferences:(id)sender { NSUserDefaults *defaults; defaults = [NSUserDefaults standardUserDefaults]; [destroyOrRecycleButton setState:[defaults boolForKey:LM_KEY_DESTROYRECYCLE] ? NSOnState : NSOffState]; [askBeforeDeletingButton setState:[defaults boolForKey:LM_KEY_ASKDELETING] ? NSOnState : NSOffState]; [prefPanel makeKeyAndOrderFront: sender]; } - (IBAction)savePreferences:(id)sender { NSUserDefaults *defaults; defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:[destroyOrRecycleButton state] forKey:LM_KEY_DESTROYRECYCLE]; [defaults setBool:[askBeforeDeletingButton state] forKey:LM_KEY_ASKDELETING]; [prefPanel performClose:self]; } - (IBAction)cancelPreferences:(id)sender { [prefPanel performClose:self]; } /* printing */ - (void)print:(id)sender { [view print:sender]; } @end