Revision: 14315
          http://sourceforge.net/p/skim-app/code/14315
Author:   hofman
Date:     2024-06-08 17:30:41 +0000 (Sat, 08 Jun 2024)
Log Message:
-----------
Update snapshot thumbnails async on thumbnail queue. For this to work create an 
intermediate object to hold the page configuration for the snapshot, as drqing 
using the pdfView is not thread safe. When snapshots are not shown, initialize 
snapshots with a placeholder thumbnail and update on a low priority queue.

Modified Paths:
--------------
    trunk/SKMainWindowController.h
    trunk/SKMainWindowController.m
    trunk/SKSnapshotWindowController.h
    trunk/SKSnapshotWindowController.m

Modified: trunk/SKMainWindowController.h
===================================================================
--- trunk/SKMainWindowController.h      2024-06-08 14:37:38 UTC (rev 14314)
+++ trunk/SKMainWindowController.h      2024-06-08 17:30:41 UTC (rev 14315)
@@ -119,8 +119,6 @@
     NSMapTable<PDFAnnotation *, id>     *widgetValues;
     
     NSMutableArray<SKSnapshotWindowController *> *snapshots;
-    NSMutableArray<SKSnapshotWindowController *> *dirtySnapshots;
-    NSTimer                             *snapshotTimer;
     CGFloat                             snapshotThumbnailSize;
     
     NSArray<NSString *>                 *tags;
@@ -318,7 +316,6 @@
 - (void)resetSnapshotSizeIfNeeded;
 - (void)snapshotNeedsUpdate:(SKSnapshotWindowController *)dirstySnapshot;
 - (void)allSnapshotsNeedUpdate;
-- (void)updateSnapshotsIfNeeded;
 
 - (void)setPdfDocument:(nullable PDFDocument *)pdfDocument 
addAnnotationsFromDictionaries:(nullable NSArray<NSDictionary<NSString *, id> 
*> *)noteDicts;
 - (void)addAnnotationsFromDictionaries:(NSArray<NSDictionary<NSString *, id> 
*> *)noteDicts removeAnnotations:(nullable NSArray<PDFAnnotation *> 
*)notesToRemove;

Modified: trunk/SKMainWindowController.m
===================================================================
--- trunk/SKMainWindowController.m      2024-06-08 14:37:38 UTC (rev 14314)
+++ trunk/SKMainWindowController.m      2024-06-08 17:30:41 UTC (rev 14315)
@@ -246,7 +246,6 @@
         tags = [[NSArray alloc] init];
         rating = 0.0;
         snapshots = [[NSMutableArray alloc] init];
-        dirtySnapshots = [[NSMutableArray alloc] init];
         pageLabels = [[NSArray alloc] init];
         lastViewedPages = [[NSPointerArray alloc] 
initWithOptions:NSPointerFunctionsOpaqueMemory | 
NSPointerFunctionsIntegerPersonality];
         rowHeights = [[NSMapTable alloc] 
initWithKeyOptions:NSPointerFunctionsStrongMemory | 
NSPointerFunctionsObjectPersonality valueOptions:NSPointerFunctionsOpaqueMemory 
| NSPointerFunctionsIntegerPersonality capacity:0];
@@ -1354,7 +1353,6 @@
 }
 
 - (void)removeObjectFromSnapshotsAtIndex:(NSUInteger)theIndex {
-    [dirtySnapshots removeObject:[snapshots objectAtIndex:theIndex]];
     [snapshots removeObjectAtIndex:theIndex];
 }
 
@@ -1363,8 +1361,6 @@
         NSIndexSet *indexes = [NSIndexSet 
indexSetWithIndexesInRange:NSMakeRange(0, [snapshots count])];
         [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes 
forKey:SNAPSHOTS_KEY];
         
-        [dirtySnapshots removeAllObjects];
-        
         [snapshots removeAllObjects];
         
         [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes 
forKey:SNAPSHOTS_KEY];
@@ -1470,7 +1466,6 @@
         [rightSideController 
replaceSideView:rightSideController.noteOutlineView.enclosingScrollView 
animate:animate];
     } else {
         [rightSideController 
replaceSideView:rightSideController.snapshotTableView.enclosingScrollView 
animate:animate];
-        [self updateSnapshotsIfNeeded];
     }
 }
 
@@ -2327,8 +2322,14 @@
     if (openType == SKSnapshotOpenPreview)
         return;
     
-    NSImage *image = [controller thumbnailWithSize:snapshotCacheSize 
scale:[[self window] backingScaleFactor]];
+    NSImage *image;
+    BOOL isVisible = [self rightSidePaneIsOpen] && [self rightSidePaneState] 
== SKSidePaneStateSnapshot;
     
+    if (isVisible || openType == SKSnapshotOpenFromSetup)
+        image = [[controller currentConfiguration] 
thumbnailWithSize:snapshotCacheSize scale:[[self window] backingScaleFactor]];
+    else
+        image = [controller placeholderThumbnailWithSize:snapshotCacheSize 
scale:[[self window] backingScaleFactor]];
+    
     [image setAccessibilityDescription:[NSString 
stringWithFormat:NSLocalizedString(@"Page %@", @""), [controller pageLabel]]];
     [controller setThumbnail:image];
     
@@ -2335,6 +2336,7 @@
     if (openType == SKSnapshotOpenFromSetup) {
         [self insertObject:controller inSnapshotsAtIndex:[snapshots count]];
         [rightSideController.snapshotTableView reloadData];
+        [self snapshotNeedsUpdate:controller];
     } else {
         [rightSideController.snapshotTableView beginUpdates];
         [self insertObject:controller inSnapshotsAtIndex:[snapshots count]];
@@ -2341,12 +2343,14 @@
         NSUInteger row = [[rightSideController.snapshotArrayController 
arrangedObjects] indexOfObject:controller];
         if (row != NSNotFound) {
             NSTableViewAnimationOptions options = 
NSTableViewAnimationEffectGap | NSTableViewAnimationSlideDown;
-            if ([self rightSidePaneIsOpen] == NO || [self rightSidePaneState] 
!= SKSidePaneStateSnapshot || [NSView shouldShowSlideAnimation] == NO)
+            if (isVisible == NO || [NSView shouldShowSlideAnimation] == NO)
                 options = NSTableViewAnimationEffectNone;
             [rightSideController.snapshotTableView 
insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:options];
         }
         [rightSideController.snapshotTableView endUpdates];
         [self setRecentInfoNeedsUpdate:YES];
+        if (isVisible == NO)
+            [self snapshotNeedsUpdate:controller];
     }
 }
 
@@ -2811,6 +2815,24 @@
 
 #pragma mark Thumbnails
 
++ (dispatch_queue_t)thumbnailQueue {
+    static dispatch_queue_t thumbnailQueue = nil;
+    if (thumbnailQueue == nil) {
+        dispatch_queue_attr_t queuePriority = 
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, 
QOS_CLASS_DEFAULT, 0);
+        thumbnailQueue = 
dispatch_queue_create("net.sourceforge.skim-app.skim.queue.thumbnails", 
queuePriority);
+    }
+    return thumbnailQueue;
+}
+
++ (dispatch_queue_t)lowPriorityThumbnailQueue {
+    static dispatch_queue_t thumbnailQueue = nil;
+    if (thumbnailQueue == nil) {
+        dispatch_queue_attr_t queuePriority = 
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, 
QOS_CLASS_UTILITY, 0);
+        thumbnailQueue = 
dispatch_queue_create("net.sourceforge.skim-app.skim.queue.thumbnails", 
queuePriority);
+    }
+    return thumbnailQueue;
+}
+
 - (PDFPage *)pageForThumbnail:(SKThumbnail *)thumbnail {
     return [[pdfView document] pageAtIndex:[thumbnail pageIndex]];
 }
@@ -2827,11 +2849,7 @@
     if ([self interactionMode] == SKPresentationMode && 
mwcFlags.thumbnailsNeedUpdateAfterPresentaton == 0 && fabs([mainWindow 
backingScaleFactor] - scale) > 0.0)
         mwcFlags.thumbnailsNeedUpdateAfterPresentaton = 1;
     
-    static dispatch_queue_t thumbnailQueue = nil;
-    if (thumbnailQueue == nil)
-        thumbnailQueue = 
dispatch_queue_create("net.sourceforge.skim-app.skim.queue.thumbnails", 
DISPATCH_QUEUE_CONCURRENT);
-    
-    dispatch_async(thumbnailQueue, ^{
+    dispatch_async([[self class] thumbnailQueue], ^{
         NSImage *image = [page thumbnailWithSize:thumbnailCacheSize 
scale:scale forBox:box hasShadow:YES highlights:highlights];
         [image setAccessibilityDescription:[NSString 
stringWithFormat:NSLocalizedString(@"Page %@", @""), [page displayLabel]]];
         
@@ -3001,58 +3019,46 @@
     if (fabs(snapshotSize - snapshotCacheSize) > FUDGE_SIZE) {
         snapshotCacheSize = snapshotSize;
         
-        if (snapshotTimer) {
-            [snapshotTimer invalidate];
-            snapshotTimer = nil;
-        }
-        
         if ([[self snapshots] count])
             [self allSnapshotsNeedUpdate];
     }
 }
 
-- (void)snapshotNeedsUpdate:(SKSnapshotWindowController *)dirtySnapshot {
-    if ([dirtySnapshots containsObject:dirtySnapshot] == NO) {
-        [dirtySnapshots addObject:dirtySnapshot];
-        [self updateSnapshotsIfNeeded];
-    }
-}
-
-- (void)allSnapshotsNeedUpdate {
-    [dirtySnapshots setArray:[self snapshots]];
-    [self updateSnapshotsIfNeeded];
-}
-
-- (void)updateSnapshot {
-    if ([dirtySnapshots count]) {
-        SKSnapshotWindowController *controller = [dirtySnapshots 
objectAtIndex:0];
-        NSSize newSize, oldSize = [[controller thumbnail] size];
-        NSImage *image = [controller thumbnailWithSize:snapshotCacheSize 
scale:[[self window] backingScaleFactor]];
+- (void)snapshotNeedsUpdate:(SKSnapshotWindowController *)controller {
+    CGFloat backingScale = [[self window] backingScaleFactor];
+    SKSnapshotConfiguration *configuration = [controller currentConfiguration];
+    dispatch_queue_t queue;
+    
+    if ([rightSideController.snapshotTableView window])
+        queue = [[self class] thumbnailQueue];
+    else
+        queue = [[self class] lowPriorityThumbnailQueue];
+    
+    dispatch_async(queue, ^{
         
-        [image setAccessibilityDescription:[NSString 
stringWithFormat:NSLocalizedString(@"Page %@", @""), [controller pageLabel]]];
-        [controller setThumbnail:image];
-        [dirtySnapshots removeObject:controller];
+        NSImage *image = [configuration thumbnailWithSize:snapshotCacheSize 
scale:backingScale];
         
-        newSize = [image size];
-        if (fabs(newSize.width - oldSize.width) > 1.0 || fabs(newSize.height - 
oldSize.height) > 1.0) {
-            NSUInteger idx = [[rightSideController.snapshotArrayController 
arrangedObjects] indexOfObject:controller];
-            if (idx != NSNotFound)
-                [rightSideController.snapshotTableView 
noteHeightOfRowChanged:idx animating:YES];
-        }
-    }
-    if ([dirtySnapshots count] == 0) {
-        [snapshotTimer invalidate];
-        snapshotTimer = nil;
-    }
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSSize newSize = [image size];
+            NSSize oldSize = [[controller thumbnail] size];
+            
+            [image setAccessibilityDescription:[NSString 
stringWithFormat:NSLocalizedString(@"Page %@", @""), [controller pageLabel]]];
+            
+            [controller setThumbnail:image];
+            
+            if (fabs(newSize.width - oldSize.width) > 1.0 || 
fabs(newSize.height - oldSize.height) > 1.0) {
+                NSUInteger idx = [[rightSideController.snapshotArrayController 
arrangedObjects] indexOfObject:controller];
+                if (idx != NSNotFound)
+                    [rightSideController.snapshotTableView 
noteHeightOfRowChanged:idx animating:YES];
+            }
+        });
+    });
 }
 
-- (void)updateSnapshotsIfNeeded {
-    if ([rightSideController.snapshotTableView window] != nil && 
[dirtySnapshots count] > 0 && snapshotTimer == nil) {
-        __weak SKMainWindowController *weakSelf = self;
-        snapshotTimer = [NSTimer scheduledTimerWithTimeInterval:0.03 
repeats:YES block:^(NSTimer *timer){
-            [weakSelf updateSnapshot];
-        }];
-    }
+- (void)allSnapshotsNeedUpdate {
+    for (SKSnapshotWindowController *controller in [self snapshots])
+        [self snapshotNeedsUpdate:controller];
+    
 }
 
 - (void)updateSnapshotFilterPredicate {

Modified: trunk/SKSnapshotWindowController.h
===================================================================
--- trunk/SKSnapshotWindowController.h  2024-06-08 14:37:38 UTC (rev 14314)
+++ trunk/SKSnapshotWindowController.h  2024-06-08 17:30:41 UTC (rev 14315)
@@ -37,6 +37,7 @@
  */
 
 #import <Cocoa/Cocoa.h>
+#import <Quartz/Quartz.h>
 #import "SKSnapshotPDFView.h"
 
 NS_ASSUME_NONNULL_BEGIN
@@ -43,7 +44,7 @@
 
 extern NSString *SKSnapshotCurrentSetupKey;
 
-@class PDFDocument, PDFPage, PDFDestination;
+@class PDFDocument, PDFPage, PDFDestination, SKSnapshotConfiguration;
 @protocol SKSnapshotWindowControllerDelegate;
 
 typedef NS_ENUM(NSInteger, SKSnapshotOpenType) {
@@ -73,6 +74,7 @@
 @property (nonatomic, readonly) BOOL hasWindow;
 @property (weak, nonatomic, readonly) NSDictionary<NSString *, id> 
*currentSetup;
 @property (nonatomic) BOOL forceOnTop;
+@property (weak, nonatomic, readonly) SKSnapshotConfiguration 
*currentConfiguration;
 
 @property (weak, nonatomic, readonly) NSAttributedString *thumbnailAttachment, 
*thumbnail512Attachment, *thumbnail256Attachment, *thumbnail128Attachment, 
*thumbnail64Attachment, *thumbnail32Attachment;
 
@@ -86,7 +88,7 @@
 
 - (void)updatePageLabel;
 
-- (NSImage *)thumbnailWithSize:(CGFloat)size scale:(CGFloat)scale;
+- (NSImage *)placeholderThumbnailWithSize:(CGFloat)size scale:(CGFloat)scale;
 
 - (NSAttributedString *)thumbnailAttachmentWithSize:(CGFloat)size;
 
@@ -119,4 +121,22 @@
 
 @end
 
+@interface SKSnapshotConfiguration : NSObject {
+    NSSize size;
+    CGFloat scaleFactor;
+    PDFDisplayBox displayBox;
+    PDFInterpolationQuality interpolationQuality;
+    NSArray<PDFDestination *> *pages;
+}
+
+@property (nonatomic) NSSize size;
+@property (nonatomic) CGFloat scaleFactor;
+@property (nonatomic) PDFDisplayBox displayBox;
+@property (nonatomic) PDFInterpolationQuality interpolationQuality;
+@property (nonatomic, nullable, copy) NSArray<PDFDestination *> *pages;
+
+- (NSImage *)thumbnailWithSize:(CGFloat)aSize scale:(CGFloat)scale;
+
+@end
+
 NS_ASSUME_NONNULL_END

Modified: trunk/SKSnapshotWindowController.m
===================================================================
--- trunk/SKSnapshotWindowController.m  2024-06-08 14:37:38 UTC (rev 14314)
+++ trunk/SKSnapshotWindowController.m  2024-06-08 17:30:41 UTC (rev 14315)
@@ -91,7 +91,7 @@
 
 @implementation SKSnapshotWindowController
 
-@synthesize pdfView, delegate, thumbnail, pageLabel, string, hasWindow, 
forceOnTop;
+@synthesize pdfView, delegate, thumbnail, pageLabel, string, hasWindow, 
forceOnTop, currentConfiguration;
 @dynamic bounds, pageIndex, currentSetup, thumbnailAttachment, 
thumbnail512Attachment, thumbnail256Attachment, thumbnail128Attachment, 
thumbnail64Attachment, thumbnail32Attachment;
 
 - (NSString *)windowNibName {
@@ -393,6 +393,24 @@
     return @{PAGE_KEY:[NSNumber numberWithUnsignedInteger:[self pageIndex]], 
RECT_KEY:NSStringFromRect([self bounds]), SCALEFACTOR_KEY:[NSNumber 
numberWithDouble:[pdfView scaleFactor]], AUTOFITS_KEY:[NSNumber 
numberWithBool:[pdfView autoFits]], HASWINDOW_KEY:[NSNumber 
numberWithBool:[[self window] isVisible]], 
WINDOWFRAME_KEY:NSStringFromRect([[self window] frame])};
 }
 
+- (SKSnapshotConfiguration *)currentConfiguration {
+    SKSnapshotConfiguration *configuration = [[SKSnapshotConfiguration alloc] 
init];
+    NSRect bounds = [pdfView visibleContentRect];
+    PDFDisplayBox box = [pdfView displayBox];
+    NSMutableArray *pages = [NSMutableArray array];
+    for (PDFPage *page in [pdfView visiblePages]) {
+        NSRect pageRect = [pdfView convertRect:[page boundsForBox:box] 
fromPage:page];
+        if (NSIntersectsRect(pageRect, bounds))
+            [pages addObject:[[PDFDestination alloc] initWithPage:page 
atPoint:SKSubstractPoints(pageRect.origin, bounds.origin)]];
+    }
+    [configuration setSize:bounds.size];
+    [configuration setScaleFactor:[pdfView scaleFactor]];
+    [configuration setDisplayBox:box];
+    [configuration setInterpolationQuality:[pdfView interpolationQuality]];
+    [configuration setPages:pages];
+    return configuration;
+}
+
 #pragma mark Actions
 
 - (IBAction)doGoToNextPage:(id)sender {
@@ -470,53 +488,18 @@
 
 #pragma mark Thumbnails
 
-- (NSImage *)thumbnailWithSize:(CGFloat)size scale:(CGFloat)scale {
+- (NSImage *)placeholderThumbnailWithSize:(CGFloat)size scale:(CGFloat)scale {
+    PDFPage *page = [[PDFPage alloc] init];
     NSRect bounds = [pdfView visibleContentRect];
-    NSAffineTransform *transform = [NSAffineTransform transform];
-    NSSize thumbnailSize = bounds.size;
-    CGFloat shadowBlurRadius = 0.0;
-    CGFloat shadowOffset = 0.0;
-    NSImage *image;
-    
-    if (size > 0.0) {
-        shadowBlurRadius = round(scale * size / 32.0) / scale;
-        shadowOffset = -ceil(scale * shadowBlurRadius * 0.75) / scale;
-        if (NSHeight(bounds) > NSWidth(bounds))
-            thumbnailSize = NSMakeSize(round((size - 2.0 * shadowBlurRadius) * 
NSWidth(bounds) / NSHeight(bounds) + 2.0 * shadowBlurRadius), size);
-        else
-            thumbnailSize = NSMakeSize(size, round((size - 2.0 * 
shadowBlurRadius) * NSHeight(bounds) / NSWidth(bounds) + 2.0 * 
shadowBlurRadius));
-        [transform translateXBy:shadowBlurRadius yBy:shadowBlurRadius - 
shadowOffset];
-        [transform scaleXBy:(thumbnailSize.width - 2.0 * shadowBlurRadius) / 
NSWidth(bounds) yBy:(thumbnailSize.height - 2.0 * shadowBlurRadius) / 
NSHeight(bounds)];
-    }
-    
-    if (NSEqualPoints(bounds.origin, NSZeroPoint) == NO)
-        [transform translateXBy:-NSMinX(bounds) yBy:-NSMinY(bounds)];
-    
-    image = [NSImage bitmapImageWithSize:thumbnailSize scale:scale 
drawingHandler:^(NSRect dstRect){
-        
-        [[NSGraphicsContext currentContext] 
setImageInterpolation:NSImageInterpolationHigh];
-        [transform concat];
-        
-        [NSGraphicsContext saveGraphicsState];
-        [[NSColor whiteColor] set];
-        if (shadowBlurRadius > 0.0)
-            [NSShadow setShadowWithWhite:0.0 alpha:0.3 
blurRadius:shadowBlurRadius yOffset:shadowOffset];
-        NSRectFill(bounds);
-        [[NSGraphicsContext currentContext] 
setImageInterpolation:NSImageInterpolationDefault];
-        [NSGraphicsContext restoreGraphicsState];
-        [[NSBezierPath bezierPathWithRect:bounds] addClip];
-        
-        CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
-        [pdfView drawPagesInRect:bounds toContext:context];
-        
-    }];
-    
-    return image;
+    bounds.origin = NSZeroPoint;
+    [page setBounds:bounds forBox:kPDFDisplayBoxMediaBox];
+    return [page thumbnailWithSize:size scale:scale 
forBox:kPDFDisplayBoxMediaBox hasShadow:YES highlights:nil];
 }
 
 - (NSAttributedString *)thumbnailAttachmentWithSize:(CGFloat)size {
-    NSBitmapImageRep *imageRep1 = (NSBitmapImageRep *)[[[self 
thumbnailWithSize:size scale:1.0] representations] firstObject];
-    NSBitmapImageRep *imageRep2 = (NSBitmapImageRep *)[[[self 
thumbnailWithSize:size scale:2.0] representations] firstObject];
+    SKSnapshotConfiguration *configuration = [self currentConfiguration];
+    NSBitmapImageRep *imageRep1 = (NSBitmapImageRep *)[[[configuration 
thumbnailWithSize:size scale:1.0] representations] firstObject];
+    NSBitmapImageRep *imageRep2 = (NSBitmapImageRep *)[[[configuration 
thumbnailWithSize:size scale:2.0] representations] firstObject];
     NSData *data = [NSBitmapImageRep 
TIFFRepresentationOfImageRepsInArray:@[imageRep1, imageRep2]];
     
     NSFileWrapper *wrapper = [[NSFileWrapper alloc] 
initRegularFileWithContents:data];
@@ -741,8 +724,9 @@
 }
 
 - (void)filePromiseProvider:(NSFilePromiseProvider *)filePromiseProvider 
writePromiseToURL:(NSURL *)fileURL completionHandler:(void (^)(NSError 
*))completionHandler {
-    NSBitmapImageRep *imageRep1 = (NSBitmapImageRep *)[[[self 
thumbnailWithSize:0.0 scale:1.0] representations] firstObject];
-    NSBitmapImageRep *imageRep2 = (NSBitmapImageRep *)[[[self 
thumbnailWithSize:0.0 scale:2.0] representations] firstObject];
+    SKSnapshotConfiguration *configuration = [self currentConfiguration];
+    NSBitmapImageRep *imageRep1 = (NSBitmapImageRep *)[[[configuration 
thumbnailWithSize:0.0 scale:1.0] representations] firstObject];
+    NSBitmapImageRep *imageRep2 = (NSBitmapImageRep *)[[[configuration 
thumbnailWithSize:0.0 scale:2.0] representations] firstObject];
     NSData *data = [NSBitmapImageRep 
TIFFRepresentationOfImageRepsInArray:@[imageRep1, imageRep2]];
     NSError *error = nil;
     [data writeToURL:fileURL options:NSDataWritingAtomic error:&error];
@@ -750,3 +734,64 @@
 }
 
 @end
+
+
+@implementation SKSnapshotConfiguration
+
+@synthesize size, scaleFactor, displayBox, interpolationQuality, pages;
+
+- (NSImage *)thumbnailWithSize:(CGFloat)aSize scale:(CGFloat)scale {
+    NSRect bounds = (NSRect){NSZeroPoint, [self size]};
+    NSAffineTransform *transform = [NSAffineTransform transform];
+    NSSize thumbnailSize = bounds.size;
+    CGFloat shadowBlurRadius = 0.0;
+    CGFloat shadowOffset = 0.0;
+    NSImage *image;
+    
+    if (aSize > 0.0) {
+        shadowBlurRadius = round(scale * aSize / 32.0) / scale;
+        shadowOffset = -ceil(scale * shadowBlurRadius * 0.75) / scale;
+        if (NSHeight(bounds) > NSWidth(bounds))
+            thumbnailSize = NSMakeSize(round((aSize - 2.0 * shadowBlurRadius) 
* NSWidth(bounds) / NSHeight(bounds) + 2.0 * shadowBlurRadius), aSize);
+        else
+            thumbnailSize = NSMakeSize(aSize, round((aSize - 2.0 * 
shadowBlurRadius) * NSHeight(bounds) / NSWidth(bounds) + 2.0 * 
shadowBlurRadius));
+        [transform translateXBy:shadowBlurRadius yBy:shadowBlurRadius - 
shadowOffset];
+        [transform scaleXBy:(thumbnailSize.width - 2.0 * shadowBlurRadius) / 
NSWidth(bounds) yBy:(thumbnailSize.height - 2.0 * shadowBlurRadius) / 
NSHeight(bounds)];
+    }
+    
+    if (NSEqualPoints(bounds.origin, NSZeroPoint) == NO)
+        [transform translateXBy:-NSMinX(bounds) yBy:-NSMinY(bounds)];
+    
+    image = [NSImage bitmapImageWithSize:thumbnailSize scale:scale 
drawingHandler:^(NSRect dstRect){
+        
+        [[NSGraphicsContext currentContext] 
setImageInterpolation:NSImageInterpolationHigh];
+        [transform concat];
+        
+        [NSGraphicsContext saveGraphicsState];
+        [[NSColor whiteColor] set];
+        if (shadowBlurRadius > 0.0)
+            [NSShadow setShadowWithWhite:0.0 alpha:0.3 
blurRadius:shadowBlurRadius yOffset:shadowOffset];
+        NSRectFill(bounds);
+        [[NSGraphicsContext currentContext] 
setImageInterpolation:NSImageInterpolationDefault];
+        [NSGraphicsContext restoreGraphicsState];
+        [[NSBezierPath bezierPathWithRect:bounds] addClip];
+        
+        CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
+        PDFDisplayBox *box = [self displayBox];
+        CGFloat scale = [self scaleFactor];
+        CGContextSetInterpolationQuality(context, [self interpolationQuality] 
+ 1);
+        for (PDFDestination *dest in [self pages]) {
+            NSPoint point = [dest point];
+            CGContextSaveGState(context);
+            CGContextTranslateCTM(context, point.x, point.y);
+            CGContextScaleCTM(context, scale, scale);
+            [[dest page] drawWithBox:box toContext:context];
+            CGContextRestoreGState(context);
+        }
+        
+    }];
+    
+    return image;
+}
+
+@end

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to