Changeset 4902

Show
Ignore:
Timestamp:
09/26/07 17:05:07 (1 year ago)
Author:
morris
Message:

Huge refactoring of image scaling/positioning code, should now work cleanly in all configurations/rotations etc

This code also supports individual rotation of images within a spread, so we can pull out Exif data from images and use that

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • Footagehead/trunk/English.lproj/ReleaseNotes.rtf

    r4896 r4902  
    1 {\rtf1\ansi\ansicpg1252\cocoartf929 
     1{\rtf1\ansi\ansicpg1252\cocoartf941 
    22{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset238 LucidaGrande;\f2\fnil\fcharset0 AppleSymbols; 
    33} 
     
    215215- Add German localization\ 
    216216- Add support for saving all images in the list to a local folder\ 
     217- Detect image orientation from EXIF data if available\ 
    217218- Update the status bar after deleting a file to reflect correct count\ 
    218219- Reverse rotate right/left so they do what they're called\ 
  • Footagehead/trunk/FHBrowserController.m

    r4895 r4902  
    369369        FHSpread                        *spread; 
    370370        FHFile                          *leftFile, *rightFile; 
    371         NSSize                          imageSize, frameSize
    372         CGFloat                         zoom, size
    373          
    374         imageSize = [_imageView combinedImageSize]; 
     371        NSSize                          imageSize
     372        CGFloat                         zoom
     373         
     374        imageSize = [_imageView imageSize]; 
    375375         
    376376        if(imageSize.width < 1.0 || imageSize.height <= 1.0) { 
     
    379379                return; 
    380380        } 
    381          
    382         if(ABS([_imageView imageRotation]) == 90 || ABS([_imageView imageRotation]) == 270) { 
    383                 size = imageSize.width; 
    384                 imageSize.width = imageSize.height; 
    385                 imageSize.height = size; 
    386         } 
    387  
    388         frameSize = [NSScrollView frameSizeForContentSize:[_imageView frame].size 
    389                                                                 hasHorizontalScroller:[_scrollView hasHorizontalScroller] 
    390                                                                   hasVerticalScroller:[_scrollView hasVerticalScroller] 
    391                                                                                    borderType:[_scrollView borderType]]; 
    392          
    393         if(imageSize.height > frameSize.height && imageSize.width <= frameSize.width) 
    394                 frameSize.width = frameSize.height * (imageSize.width / imageSize.height); 
    395          
    396         if(imageSize.width > frameSize.width && imageSize.height <= frameSize.height) 
    397                 frameSize.height = frameSize.width * (imageSize.height / imageSize.width); 
    398          
    399         zoom = 100.0 * ((frameSize.width * frameSize.height) / (imageSize.width * imageSize.height)); 
    400          
    401         if(zoom > 100.0) 
    402                 zoom = 100.0; 
    403381         
    404382        if([FHSettings intForKey:FHSpreadMode] == FHSpreadNone) { 
     
    422400                } 
    423401        } 
     402         
     403        zoom = [_imageView zoom]; 
    424404         
    425405        string = [NSMutableString stringWithFormat:NSLS(@"%@, %.0fx%.0f", @"'image.jpg, 640x480'"), 
  • Footagehead/trunk/FHFileCell.m

    r4706 r4902  
    8282        NSString                        *name; 
    8383        FHImage                         *icon; 
     84        CGContextRef            context; 
    8485        NSRect                          rect, imageRect; 
    8586        NSSize                          size; 
    86         float                          dx, dy, d
     87        CGFloat                                dx, dy, d, angle
    8788         
    8889        name = [(NSDictionary *) [self objectValue] objectForKey:FHFileCellNameKey]; 
     
    9899        rect                            = NSMakeRect(frame.origin.x, frame.origin.y + 2.0, frame.size.width, frame.size.height - 28.0); 
    99100        size                            = [icon size]; 
     101        angle                           = [icon orientation]; 
    100102        imageRect.origin        = rect.origin; 
    101103        imageRect.size          = size; 
    102         dx                                      = rect.size.width  / imageRect.size.width; 
    103         dy                                      = rect.size.height / imageRect.size.height; 
    104         d                                       = dx < dy ? dx : dy; 
    105                                  
     104         
     105        if(angle == 0.0 || angle == 180.0) { 
     106                dx = rect.size.width  / imageRect.size.width; 
     107                dy = rect.size.height / imageRect.size.height; 
     108        } else { 
     109                dx = rect.size.width  / imageRect.size.height; 
     110                dy = rect.size.height / imageRect.size.width; 
     111        } 
     112         
     113        d = dx < dy ? dx : dy; 
     114         
    106115        if(d < 1.0) { 
    107116                imageRect.size.width    = floorf(imageRect.size.width  * d); 
     
    109118        } 
    110119 
    111         imageRect.origin.x += floorf((rect.size.width  - imageRect.size.width) / 2.0); 
    112         imageRect.origin.y += floorf((rect.size.height - imageRect.size.height) / 2.0); 
     120        if(angle == 0.0 || angle == 180.0) { 
     121                imageRect.origin.x += floorf((rect.size.width  - imageRect.size.width)  / 2.0); 
     122                imageRect.origin.y += floorf((rect.size.height - imageRect.size.height) / 2.0); 
     123        } else { 
     124                imageRect.origin.x += floorf((rect.size.width  - imageRect.size.height) / 2.0); 
     125                imageRect.origin.y += floorf((rect.size.height - imageRect.size.width)  / 2.0); 
     126        } 
    113127         
    114         [icon setFlipped:YES]; 
    115         [icon drawInRect:imageRect atAngle:0.0]; 
     128        if(angle == 90.0) { 
     129                imageRect.origin.y -= imageRect.size.height; 
     130        } 
     131        else if(angle == 180.0) { 
     132                imageRect.origin.x += imageRect.size.width; 
     133                imageRect.origin.y += imageRect.size.height; 
     134        } 
     135        else if(angle == 270.0) { 
     136                imageRect.origin.x += imageRect.size.height; 
     137        } 
     138         
     139        context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; 
     140        CGContextSaveGState(context); 
     141 
     142        if(angle == 90.0) { 
     143                CGContextTranslateCTM(context, 0.0, imageRect.origin.y + imageRect.origin.y + imageRect.size.height); 
     144                CGContextScaleCTM(context, 1.0, -1.0); 
     145        } 
     146         
     147        if(angle == 90.0 || angle == 180.0 || angle == 270.0) { 
     148                CGContextTranslateCTM(context, imageRect.origin.x, imageRect.origin.y); 
     149                CGContextRotateCTM(context, -angle * M_PI / 180.0); 
     150                CGContextTranslateCTM(context, -imageRect.origin.x, -imageRect.origin.y); 
     151        } 
     152         
     153        if(angle == 0.0 || angle == 180.0 || angle == 270.0) { 
     154                CGContextTranslateCTM(context, 0.0, imageRect.origin.y + imageRect.origin.y + imageRect.size.height); 
     155                CGContextScaleCTM(context, 1.0, -1.0); 
     156        } 
     157         
     158        [icon drawInRect:imageRect]; 
     159         
     160        CGContextRestoreGState(context); 
    116161} 
    117162 
  • Footagehead/trunk/FHImage.h

    r4735 r4902  
    3131        CGImageRef                                      _CGImage; 
    3232         
     33        NSDictionary                            *_properties; 
     34 
    3335        WIURL                                           *_url; 
    3436         
    3537        NSSize                                          _size; 
    3638        BOOL                                            _flipped; 
     39        CGFloat                                         _orientation; 
    3740} 
    3841 
     
    5154- (NSSize)size; 
    5255- (NSUInteger)pixels; 
     56- (CGFloat)orientation; 
    5357 
    54 - (void)drawInRect:(NSRect)rect atAngle:(float)angle
     58- (void)drawInRect:(NSRect)rect
    5559 
    5660@end 
  • Footagehead/trunk/FHImage.m

    r4876 r4902  
    3434- (BOOL)_initImageWithImageSource:(CGImageSourceRef)imageSource; 
    3535- (BOOL)_initThumbnailWithImageSource:(CGImageSourceRef)imageSource preferredSize:(NSSize)size; 
     36- (void)_initProperties; 
    3637 
    3738@end 
     
    5455         
    5556        _size = NSMakeSize(CGImageGetWidth(_CGImage), CGImageGetHeight(_CGImage)); 
     57 
     58        _properties = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef) options); 
     59 
     60        [self _initProperties]; 
    5661         
    5762        return YES; 
     
    7883        _size = NSMakeSize(CGImageGetWidth(_CGImage), CGImageGetHeight(_CGImage)); 
    7984         
     85        _properties = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef) options); 
     86         
     87        [self _initProperties]; 
     88         
    8089        return YES; 
     90} 
     91 
     92 
     93 
     94- (void)_initProperties { 
     95        switch([[_properties objectForKey:(id) kCGImagePropertyOrientation] intValue]) { 
     96                case 3: 
     97                        _orientation = 180.0; 
     98                        break; 
     99                         
     100                case 6: 
     101                        _orientation = 90.0; 
     102                        break; 
     103                         
     104                case 8: 
     105                        _orientation = 270.0; 
     106                        break; 
     107                         
     108                default: 
     109                        _orientation = 0.0; 
     110                        break; 
     111        } 
    81112} 
    82113 
     
    124155                return NULL; 
    125156        } 
    126  
     157         
    127158        if(![self _initImageWithImageSource:imageSource]) { 
    128159                CFRelease(imageSource); 
     
    152183                return NULL; 
    153184        } 
    154  
     185         
    155186        if(![self _initImageWithImageSource:imageSource]) { 
    156187                CFRelease(imageSource); 
     
    162193         
    163194        CFRelease(imageSource); 
    164                 
     195         
    165196        return self; 
    166197} 
     
    230261         
    231262        [_NSImage release]; 
     263         
     264        [_properties release]; 
    232265 
    233266        [super dealloc]; 
     
    262295 
    263296 
     297- (CGFloat)orientation { 
     298        return _orientation; 
     299} 
     300 
     301 
     302 
    264303#pragma mark - 
    265304 
    266 - (void)drawInRect:(NSRect)rect atAngle:(float)angle
     305- (void)drawInRect:(NSRect)rect
    267306        NSImageRep              *imageRep; 
    268307        CGContextRef    context; 
    269         BOOL                    restore = NO; 
    270          
     308 
    271309        context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; 
    272  
    273         if(_flipped || angle != 0.0f) { 
    274                 CGContextSaveGState(context); 
    275                  
    276                 if(_flipped) { 
    277                         CGContextTranslateCTM(context, 0.0f, rect.origin.y + rect.origin.y + rect.size.height); 
    278                         CGContextScaleCTM(context, 1.0f, -1.0f); 
    279                 } else { 
    280                         CGContextTranslateCTM(context, rect.origin.x, rect.origin.y); 
    281                         CGContextRotateCTM(context, -angle * M_PI / 180.0f); 
    282                         CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y); 
    283                 } 
    284                  
    285                 restore = YES; 
    286         } 
    287310 
    288311        if(_CGImage) { 
     
    298321                } 
    299322        } 
    300          
    301         if(restore) 
    302                 CGContextRestoreGState(context); 
    303323} 
    304324 
  • Footagehead/trunk/FHImageView.h

    r4731 r4902  
    4747        FHImage                                         *_image; 
    4848        FHImage                                         *_leftImage, *_rightImage; 
    49         NSSize                                          _combinedImageSize; 
    50         NSSize                                          _leftSize, _rightSize; 
    5149         
    5250        FHImageScaling                          _imageScaling; 
    5351        CGFloat                                         _imageRotation; 
     52 
     53        NSSize                                          _imageSize, _leftImageSize, _rightImageSize; 
     54        NSSize                                          _rotatedImageSize, _rotatedLeftImageSize, _rotatedRightImageSize; 
     55        CGFloat                                         _imageOrientation, _leftImageOrientation, _rightImageOrientation; 
     56        CGFloat                                         _imageAngle, _leftImageAngle, _rightImageAngle; 
    5457         
    5558        NSColor                                         *_backgroundColor; 
     
    5962         
    6063        BOOL                                            _dragging; 
    61         BOOL                                            _adjustingScaling; 
     64        BOOL                                            _adjustingFrameSize; 
     65        FHImageScaling                          _adjustedImageScaling; 
    6266} 
    6367 
     
    6872- (FHImage *)leftImage; 
    6973- (FHImage *)rightImage; 
    70 - (NSSize)combinedImageSize; 
     74- (NSSize)imageSize; 
     75- (CGFloat)zoom; 
    7176- (void)setImageScaling:(FHImageScaling)newScaling; 
    7277- (FHImageScaling)imageScaling; 
  • Footagehead/trunk/FHImageView.m

    r4878 r4902  
    3535- (void)_initImageView; 
    3636 
    37 - (void)_adjustScaling; 
    38 - (NSSize)_scaledImageSizeForSize:(NSSize)size bounds:(NSSize)bounds; 
     37- (void)_adjustImageSize; 
     38- (void)_adjustFrameSize; 
     39- (CGFloat)_scaleFactorUsingScaling:(FHImageScaling)imageScaling bounds:(NSSize)bounds; 
     40- (NSSize)_scaledSizeForSize:(NSSize)size usingScaling:(FHImageScaling)imageScaling bounds:(NSSize)bounds; 
    3941 
    4042@end 
     
    6365 
    6466- (void)_FH_viewFrameDidChange:(NSNotification *)notification { 
    65         [self _adjustScaling]; 
     67        [self _adjustFrameSize]; 
    6668                 
    6769        if([_scrollView hasHorizontalScroller] || [_scrollView hasVerticalScroller]) 
     
    7577#pragma mark - 
    7678 
    77 - (void)_adjustScaling { 
    78         NSSize      contentSize, imageSize, combinedImageSize, frameSize; 
    79         CGFloat         scrollerWidth; 
    80         double          diff; 
    81          
    82         if(_adjustingScaling) 
     79- (void)_adjustImageSize { 
     80        NSSize          orientedLeftSize, orientedRightSize; 
     81         
     82        if(_image) { 
     83                _imageAngle = _imageRotation + _imageOrientation; 
     84                 
     85                if(_imageAngle >= 360.0) 
     86                        _imageAngle -= 360.0; 
     87                 
     88                if(_imageAngle == 0.0 || _imageAngle == 180.0) 
     89                        _rotatedImageSize = _imageSize; 
     90                else 
     91                        _rotatedImageSize = WISwapSize(_imageSize); 
     92        } else { 
     93                _leftImageAngle = _imageRotation + _leftImageOrientation; 
     94                 
     95                if(_leftImageAngle >= 360.0) 
     96                        _leftImageAngle -= 360.0; 
     97                 
     98                if(_leftImageAngle == 0.0 || _leftImageAngle == 180.0) 
     99                        _rotatedLeftImageSize = _leftImageSize; 
     100                else 
     101                        _rotatedLeftImageSize = WISwapSize(_leftImageSize); 
     102 
     103                if(_leftImageOrientation == 0.0 || _leftImageOrientation == 180.0) 
     104                        orientedLeftSize = _leftImageSize; 
     105                else 
     106                        orientedLeftSize = WISwapSize(_leftImageSize); 
     107                 
     108                _rightImageAngle = _imageRotation + _rightImageOrientation; 
     109                 
     110                if(_rightImageAngle >= 360.0) 
     111                        _rightImageAngle -= 360.0; 
     112                 
     113                if(_rightImageAngle == 0.0 || _rightImageAngle == 180.0) 
     114                        _rotatedRightImageSize = _rightImageSize; 
     115                else 
     116                        _rotatedRightImageSize = WISwapSize(_rightImageSize); 
     117                 
     118                if(_rightImageOrientation == 0.0 || _rightImageOrientation == 180.0) 
     119                        orientedRightSize = _rightImageSize; 
     120                else 
     121                        orientedRightSize = WISwapSize(_rightImageSize); 
     122 
     123                _imageSize.width = orientedLeftSize.width + orientedRightSize.width; 
     124                _imageSize.height = MAX(orientedLeftSize.height, orientedRightSize.height); 
     125                 
     126                if(_imageRotation == 0.0 || _imageRotation == 180.0) 
     127                        _rotatedImageSize = _imageSize; 
     128                else 
     129                        _rotatedImageSize = WISwapSize(_imageSize); 
     130        } 
     131
     132 
     133 
     134 
     135- (void)_adjustFrameSize { 
     136        NSSize          visibleSize, imageSize, frameSize; 
     137        CGFloat         diff, scrollerWidth, widthAdjustment, heightAdjustment; 
     138        BOOL            horizontalScroller, verticalScroller; 
     139         
     140        if(_adjustingFrameSize) 
    83141                return; 
    84142         
    85         _adjustingScaling = YES; 
    86          
    87         if(_scrollView) { 
    88                 [_scrollView setHasHorizontalScroller:NO]; 
    89                 [_scrollView setHasVerticalScroller:NO]; 
    90  
    91                 contentSize = [_scrollView documentVisibleRect].size; 
    92                  
    93                 [self setFrameSize:contentSize]; 
    94                  
    95                 if(_combinedImageSize.width > 0.0 && 
    96                    (_imageScaling == FHScaleNone || 
    97                         _imageScaling == FHScaleWidthProportionally || 
    98                         _imageScaling == FHScaleHeightProportionally)) { 
    99                          
    100                         if(ABS(_imageRotation) == 0.0 || ABS(_imageRotation) == 180.0) { 
    101                                 imageSize = [self _scaledImageSizeForSize:_combinedImageSize bounds:contentSize]; 
     143        _adjustingFrameSize = YES; 
     144         
     145        [_scrollView setHasHorizontalScroller:NO]; 
     146        [_scrollView setHasVerticalScroller:NO]; 
     147         
     148        visibleSize = [_scrollView documentVisibleRect].size; 
     149         
     150        _adjustedImageScaling = _imageScaling; 
     151         
     152        if(_imageScaling == FHScaleNone || 
     153           _imageScaling == FHScaleWidthProportionally || 
     154           _imageScaling == FHScaleHeightProportionally) { 
     155                scrollerWidth = [NSScroller scrollerWidth]; 
     156                widthAdjustment = heightAdjustment = 0.0; 
     157                horizontalScroller = verticalScroller = NO; 
     158                 
     159                imageSize = [self _scaledSizeForSize:_rotatedImageSize usingScaling:_imageScaling bounds:visibleSize]; 
     160 
     161                if(_imageScaling == FHScaleNone) { 
     162                        if(imageSize.height > visibleSize.height && imageSize.width > visibleSize.width) 
     163                                horizontalScroller = verticalScroller = YES; 
     164                        else if(imageSize.height > visibleSize.height) 
     165                                verticalScroller = YES; 
     166                        else if(imageSize.width > visibleSize.width) 
     167                                horizontalScroller = YES; 
     168                } 
     169                else if(_imageScaling == FHScaleWidthProportionally) { 
     170                        if(imageSize.height - visibleSize.height > scrollerWidth) { 
     171                                diff = scrollerWidth - (visibleSize.width - imageSize.width); 
     172 
     173                                if(diff > 0.0) 
     174                                        heightAdjustment = ceil((imageSize.height / imageSize.width) * diff); 
     175                                 
     176                                verticalScroller = YES; 
    102177                        } else { 
    103                                 if(_image) { 
    104                                         combinedImageSize.width = _combinedImageSize.height; 
    105                                         combinedImageSize.height = _combinedImageSize.width; 
    106                                 } else { 
    107                                         combinedImageSize.width = MAX(_leftSize.height, _rightSize.height); 
    108                                         combinedImageSize.height = _leftSize.width + _rightSize.width; 
    109                                 } 
    110  
    111                                 imageSize = [self _scaledImageSizeForSize:combinedImageSize bounds:contentSize]; 
    112                         } 
    113                          
    114                         frameSize = NSMakeSize(MAX(contentSize.width, imageSize.width), MAX(contentSize.height, imageSize.height)); 
    115                          
    116                         scrollerWidth = [NSScroller scrollerWidth]; 
    117                          
    118                         diff = (contentSize.width / imageSize.width) * scrollerWidth; 
    119  
    120                         if(imageSize.width - diff > contentSize.width) { 
    121                                 [_scrollView setHasHorizontalScroller:YES]; 
     178                                _adjustedImageScaling = FHScaleProportionally; 
     179                        } 
     180                } 
     181                else if(_imageScaling == FHScaleHeightProportionally) { 
     182                        if(imageSize.width - visibleSize.width > scrollerWidth) { 
     183                                diff = scrollerWidth - (visibleSize.height - imageSize.height); 
    122184                                 
    123                                 frameSize.height -= scrollerWidth; 
    124                                  
    125                                 if(imageSize.height > contentSize.height - scrollerWidth) 
    126                                         frameSize.width -= diff; 
    127                         } 
    128                          
    129                         diff = (contentSize.height / imageSize.height) * scrollerWidth; 
    130  
    131                         if(imageSize.height - diff > contentSize.height) { 
    132                                 [_scrollView setHasVerticalScroller:YES]; 
    133                                  
    134                                 frameSize.width -= scrollerWidth; 
    135                                  
    136                                 if(imageSize.width > contentSize.width - scrollerWidth) 
    137                                         frameSize.height -= diff; 
    138                         } 
    139                          
    140                         [self setFrameSize:frameSize]; 
    141                         [self scrollPoint:NSMakePoint(0.0, frameSize.height)]; 
     185                                if(diff > 0.0) 
     186                                        widthAdjustment = ceil((imageSize.width / imageSize.height) * diff); 
     187 
     188                                horizontalScroller = YES; 
     189                        } else { 
     190                                _adjustedImageScaling = FHScaleProportionally; 
     191                        } 
    142192                } 
    143         } 
    144          
    145         _adjustingScaling = NO; 
    146 
    147  
    148  
    149  
    150 - (NSSize)_scaledImageSizeForSize:(NSSize)size bounds:(NSSize)bounds { 
    151         float           dx, dy, d; 
    152          
    153         if(_imageScaling == FHScaleNone) 
     193                 
     194                if(_imageScaling != _adjustedImageScaling) 
     195                        imageSize = [self _scaledSizeForSize:_rotatedImageSize usingScaling:_adjustedImageScaling bounds:visibleSize]; 
     196                 
     197                frameSize = NSMakeSize(MAX(visibleSize.width, imageSize.width), MAX(visibleSize.height, imageSize.height)); 
     198                frameSize.width -= widthAdjustment; 
     199                frameSize.height -= heightAdjustment; 
     200                 
     201                [self setFrameSize:frameSize]; 
     202                 
     203                [_scrollView setHasHorizontalScroller:horizontalScroller]; 
     204                [_scrollView setHasVerticalScroller:verticalScroller]; 
     205 
     206                [self scrollPoint:NSMakePoint(0.0, frameSize.height)]; 
     207        } else { 
     208                [self setFrameSize:visibleSize]; 
     209        } 
     210 
     211        _adjustingFrameSize = NO; 
     212
     213 
     214 
     215 
     216- (CGFloat)_scaleFactorUsingScaling:(FHImageScaling)imageScaling bounds:(NSSize)bounds { 
     217        CGFloat         dx, dy; 
     218         
     219        dx = bounds.width  / _rotatedImageSize.width; 
     220        dy = bounds.height / _rotatedImageSize.height; 
     221         
     222        if(imageScaling == FHScaleProportionally || imageScaling == FHScaleStretchedProportionally) 
     223                return dx < dy ? dx : dy; 
     224        else if(imageScaling == FHScaleWidthProportionally) 
     225                return dx; 
     226        else if(imageScaling == FHScaleHeightProportionally) 
     227                return dy; 
     228         
     229        return 1.0; 
     230
     231 
     232 
     233 
     234- (NSSize)_scaledSizeForSize:(NSSize)size usingScaling:(FHImageScaling)imageScaling bounds:(NSSize)bounds { 
     235        CGFloat         factor; 
     236         
     237        if(imageScaling == FHScaleNone) 
    154238                return size; 
    155239         
    156         if(_imageScaling == FHScaleStretched) 
     240        if(imageScaling == FHScaleStretched) 
    157241                return bounds; 
    158242         
    159         if(ABS(_imageRotation) == 0.0 || ABS(_imageRotation) == 180.0) { 
    160                 dx = bounds.width  / _combinedImageSize.width; 
    161                 dy = bounds.height / _combinedImageSize.height; 
    162         } else { 
    163                 dx = bounds.width  / _combinedImageSize.height; 
    164                 dy = bounds.height / _combinedImageSize.width; 
    165         } 
    166          
    167         if(_imageScaling == FHScaleProportionally || _imageScaling == FHScaleStretchedProportionally) 
    168                 d = dx < dy ? dx : dy; 
    169         else if(_imageScaling == FHScaleWidthProportionally) 
    170                 d = dx; 
    171         else if(_imageScaling == FHScaleHeightProportionally) 
    172                 d = dy; 
    173          
    174         if(d < 1.0 || _imageScaling == FHScaleStretchedProportionally) { 
    175                 size.width              = floorf(size.width  * d); 
    176                 size.height             = floorf(size.height * d); 
     243        factor = [self _scaleFactorUsingScaling:imageScaling bounds:bounds]; 
     244         
     245        if(factor < 1.0 || imageScaling == FHScaleStretchedProportionally) { 
     246                size.width              = floorf(size.width  * factor); 
     247                size.height             = floorf(size.height * factor); 
    177248        } 
    178249         
     
    239310         
    240311        if(_image) { 
    241                 _combinedImageSize = [_image size]; 
     312                _imageSize                      = [_image size]; 
     313                _imageOrientation       = [_image orientation]; 
    242314        } else { 
    243                 _combinedImageSize.width = 0.0; 
    244                 _combinedImageSize.height = 0.0; 
    245         } 
    246  
    247         [self _adjustScaling]; 
     315                _imageSize.width        = 0.0; 
     316                _imageSize.height       = 0.0; 
     317                _imageOrientation       = 0.0; 
     318        } 
     319         
     320        [self _adjustImageSize]; 
     321        [self _adjustFrameSize]; 
    248322         
    249323        if(display) 
     
    273347         
    274348        if(_leftImage) { 
    275                 _leftSize = [_leftImage size]; 
     349                _leftImageSize                  = [_leftImage size]; 
     350                _leftImageOrientation   = [_leftImage orientation]; 
    276351        } else { 
    277                 _leftSize.width = 0.0; 
    278                 _leftSize.height = 0.0; 
     352                _leftImageSize.width    = 0.0; 
     353                _leftImageSize.height   = 0.0; 
     354                _leftImageOrientation   = 0.0; 
    279355        } 
    280356         
     
    285361         
    286362        if(_rightImage) { 
    287                 _rightSize = [_rightImage size]; 
     363                _rightImageSize                 = [_rightImage size]; 
     364                _rightImageOrientation  = [_rightImage orientation]; 
    288365        } else { 
    289                 _rightSize.width = 0.0; 
    290                 _rightSize.height = 0.0; 
    291         } 
    292          
    293         _combinedImageSize.width = _leftSize.width + _rightSize.width; 
    294         _combinedImageSize.height = MAX(_leftSize.height, _rightSize.height); 
    295  
    296         [self _adjustScaling]; 
     366                _rightImageSize.width   = 0.0; 
     367                _rightImageSize.height  = 0.0; 
     368                _rightImageOrientation  = 0.0; 
     369        } 
     370         
     371        [self _adjustImageSize]; 
     372        [self _adjustFrameSize]; 
    297373         
    298374        if(display) 
     
    314390 
    315391 
    316 - (NSSize)combinedImageSize { 
    317         return _combinedImageSize; 
     392- (NSSize)imageSize { 
     393        return _imageSize; 
     394
     395 
     396 
     397 
     398- (CGFloat)zoom { 
     399        CGFloat         zoom; 
     400         
     401        zoom = 100.0 * [self _scaleFactorUsingScaling:_adjustedImageScaling bounds:[self bounds].size]; 
     402         
     403        if(zoom > 100.0 && _adjustedImageScaling != FHScaleStretched && _adjustedImageScaling != FHScaleStretchedProportionally) 
     404                zoom = 100.0; 
     405         
     406        return zoom; 
    318407} 
    319408 
     
    323412        _imageScaling = imageScaling; 
    324413 
    325         [self _adjustScaling]; 
     414        [self _adjustFrameSize]; 
    326415         
    327416        [self setNeedsDisplay:YES]; 
     
    339428        _imageRotation = imageRotation; 
    340429 
    341         [self _adjustScaling]; 
     430        [self _adjustImageSize]; 
     431        [self _adjustFrameSize]; 
    342432         
    343433        [self setNeedsDisplay:YES]; 
     
    465555 
    466556- (void)drawRect:(NSRect)frame { 
    467         FHImage         *image; 
    468         NSRect          bounds, rect, leftRect, rightRect; 
    469         NSSize          size; 
     557        FHImage                 *image; 
     558        CGContextRef    context; 
     559        NSRect                  bounds, rect, leftRect, rightRect; 
     560        NSSize                  size, rotatedLeftSize, rotatedRightSize; 
    470561         
    471562        bounds = [self bounds]; 
     
    475566         
    476567        if(_image || _leftImage || _rightImage) { 
     568                context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; 
     569 
    477570                if(_leftImage && _rightImage) { 
    478                         size                    = [self _scaledImageSizeForSize:_combinedImageSize bounds:bounds.size]; 
    479                         leftRect.size   = [self _scaledImageSizeForSize:_leftSize bounds:bounds.size]; 
    480                         rightRect.size  = [self _scaledImageSizeForSize:_rightSize bounds:bounds.size]; 
     571                        size                            = [self _scaledSizeForSize:_imageSize usingScaling:_adjustedImageScaling bounds:bounds.size]; 
     572                        leftRect.size           = [self _scaledSizeForSize:_leftImageSize usingScaling:_adjustedImageScaling bounds:bounds.size]; 
     573                        rightRect.size          = [self _scaledSizeForSize:_rightImageSize usingScaling:_adjustedImageScaling bounds:bounds.size]; 
     574                        rotatedLeftSize         = [self _scaledSizeForSize:_rotatedLeftImageSize usingScaling:_adjustedImageScaling bounds:bounds.size]; 
     575                        rotatedRightSize        = [self _scaledSizeForSize:_rotatedRightImageSize usingScaling:_adjustedImageScaling bounds:bounds.size]; 
     576                         
     577                        if(_imageRotation == 0.0 || _imageRotation == 180.0) { 
     578                                leftRect.origin.x = rightRect.origin.x = floorf((bounds.size.width  - size.width)  / 2.0); 
     579                                leftRect.origin.y = rightRect.origin.y = floorf((bounds.size.height - size.height) / 2.0); 
     580                        } else { 
     581                                leftRect.origin.x = rightRect.origin.x = floorf((bounds.size.width  - size.height) / 2.0); 
     582                                leftRect.origin.y = rightRect.origin.y = floorf((bounds.size.height - size.width)  / 2.0); 
     583                        } 
    481584                         
    482585                        if(_imageRotation == 0.0) { 
    483                                 leftRect.origin.x       = floorf((bounds.size.width  - size.width)  / 2.0); 
    484                                 leftRect.origin.y       = floorf((bounds.size.height - size.height) / 2.0); 
    485                                 rightRect.origin.x      = leftRect.origin.x + leftRect.size.width; 
    486                                 rightRect.origin.y      = leftRect.origin.y; 
     586                                if(_leftImageOrientation == 90.0) { 
     587                                        leftRect.origin.y += rotatedLeftSize.height; 
     588                                } 
     589                                else if(_leftImageOrientation == 180.0) { 
     590                                        leftRect.origin.x += rotatedLeftSize.width; 
     591                                        leftRect.origin.y += rotatedLeftSize.height; 
     592                                } 
     593                                else if(_leftImageOrientation == 270.0) { 
     594                                        leftRect.origin.x += rotatedLeftSize.width; 
     595                                } 
    487596                        } 
    488597                        else if(_imageRotation == 90.0) { 
    489                                 rightRect.origin.x      = floorf((bounds.size.width - size.height) / 2.0); 
    490                                 rightRect.origin.y      = rightRect.size.width + floorf((bounds.size.height - size.width) / 2.0); 
    491                                 leftRect.origin.x = rightRect.origin.x; 
    492                                 leftRect.origin.y = rightRect.origin.y + rightRect.size.width; 
     598                                if(_leftImageOrientation == 0.0) { 
     599                                        leftRect.origin.y += rotatedRightSize.height + rotatedLeftSize.height; 
     600                                } 
     601                                else if(_leftImageOrientation == 90.0) { 
     602                                        leftRect.origin.x += rotatedLeftSize.width; 
     603                                        leftRect.origin.y += rotatedRightSize.height + rotatedLeftSize.height; 
     604                                } 
     605                                else if(_leftImageOrientation == 180.0) { 
     606                                        leftRect.origin.x += rotatedLeftSize.width; 
     607                                        leftRect.origin.y += rotatedRightSize.height; 
     608                                } 
     609                                else if(_leftImageOrientation == 270.0) { 
     610                                        leftRect.origin.y += rotatedRightSize.height; 
     611                                } 
    493612                        } 
    494613                        else if(_imageRotation == 180.0) { 
    495                                 rightRect.origin.x      = rightRect.size.width  + floorf((bounds.size.width  - size.width)  / 2.0); 
    496                                 rightRect.origin.y      = rightRect.size.height + floorf((bounds.size.height - size.height) / 2.0); 
    497                                 leftRect.origin.x       = rightRect.origin.x + rightRect.size.width; 
    498                                 leftRect.origin.y       = rightRect.origin.y; 
     614                                if(_leftImageOrientation == 0.0) { 
     615                                        leftRect.origin.x += rotatedRightSize.width + rotatedLeftSize.width; 
     616                                        leftRect.origin.y += rotatedLeftSize.height; 
     617                                } 
     618                                else if(_leftImageOrientation == 90.0) { 
     619                                        leftRect.origin.x += rotatedRightSize.width + rotatedLeftSize.width; 
     620                                } 
     621                                else if(_leftImageOrientation == 180.0) { 
     622                                        leftRect.origin.x += rotatedRightSize.width; 
     623                                } 
     624                                else if(_leftImageOrientation == 270.0) { 
     625                                        leftRect.origin.x += rotatedRightSize.width; 
     626                                        leftRect.origin.y += rotatedLeftSize.height;