2012-07-07 12 views
6

Ho una sequenza di NSViews fuori schermo in un'applicazione Cocoa, che vengono utilizzate per comporre un PDF per la stampa. Le viste non sono in una NSWindow, o sono visibili in alcun modo.Genera immagine in scala da NSView fuori dallo schermo

Mi piacerebbe essere in grado di generare immagini di anteprima di quella vista, esattamente come sembrerebbe il PDF, ma ridimensionate per adattarle a una certa dimensione di pixel (vincolata a una larghezza o altezza). Questo deve essere il più veloce possibile, quindi mi piacerebbe evitare il rendering in PDF, quindi la conversione in raster e in scala - Mi piacerebbe andare direttamente al raster.

Al momento sto facendo:

NSBitmapImageRep *bitmapImageRep = [pageView bitmapImageRepForCachingDisplayInRect:pageView.bounds]; 
[pageView cacheDisplayInRect:pageView.bounds toBitmapImageRep:bitmapImageRep]; 
NSImage *image = [[NSImage alloc] initWithSize:bitmapImageRep.size]; 
[image addRepresentation:bitmapImageRep]; 

Questo approccio funziona bene, ma non riesco a capire come applicare un ridimensionamento al NSView prima del rendering della bitmapImageRep. Voglio evitare di usare scaleUnitSquareToSize, perché, a quanto ho capito, cambia solo i limiti, non il frame di NSView.

Qualche suggerimento sul modo migliore di farlo?

risposta

6

Questo è quello che ho finito, che funziona perfettamente. Disegniamo direttamente in un NSBitmapImageRep, ma ridimensiona esplicitamente il contesto utilizzando CGContextScaleCTM in anticipo. graphicsContext.graphicsPort fornisce l'handle su CGContextRef per NSGraphicsContext.

NSView *pageView = [self viewForPageIndex:pageIndex]; 

float scale = width/pageView.bounds.size.width; 
float height = scale * pageView.bounds.size.height; 

NSRect targetRect = NSMakeRect(0.0, 0.0, width, height); 
NSBitmapImageRep *bitmapRep; 

bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil 
                pixelsWide:targetRect.size.width 
                pixelsHigh:targetRect.size.height 
               bitsPerSample:8 
               samplesPerPixel:4 
                 hasAlpha:YES 
                 isPlanar:NO 
               colorSpaceName:NSCalibratedRGBColorSpace 
                bitmapFormat:0 
                bytesPerRow:(4 * targetRect.size.width) 
                bitsPerPixel:32]; 

[NSGraphicsContext saveGraphicsState]; 

NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapRep]; 
[NSGraphicsContext setCurrentContext:graphicsContext]; 
CGContextScaleCTM(graphicsContext.graphicsPort, scale, scale); 

[pageView displayRectIgnoringOpacity:pageView.bounds inContext:graphicsContext]; 

[NSGraphicsContext restoreGraphicsState]; 

NSImage *image = [[NSImage alloc] initWithSize:bitmapRep.size]; 
[image addRepresentation:bitmapRep]; 

return image; 
+0

Stavo usando 'bitmapImageRepForCacheDisplayInRect:' e 'cacheDisplayInRect: toBitmapImageRep:' per generare dinamicamente le anteprime per un'app per notebook all'avvio. Con> 40 pagine (NSViews ospitate da layer) con un sacco di contenuti visivi, la generazione delle miniature richiedeva quasi 90 secondi. Questo non era il caso delle versioni precedenti di macOS. Ho sostituito questo metodo con l'approccio di @ tomtaylor sopra, usando una scala di 1.0 (dal momento che ho bisogno di miniature per scalare in modo fluido verso l'alto a grandezza intera) e la generazione di miniature è scesa a 20 secondi (in background), con circa la metà della memoria virtuale utilizzata! – Dalmazio

0

Che ne dici di utilizzare scaleUnitSquareToSize: e quindi di passare in un piccolo rect in bitmapImageRepForCachingDisplayInRect: e cacheDisplayInRect:toBitmapImageRep:?

Quindi, se lo si ridimensiona di un fattore 2, si passa un retto a metà con limiti e altezza.

+0

Sto utilizzando il sistema di layout di testo Cocoa, insieme a NSTextContainer. A quanto ho capito, questo è possibile solo a livello NSView. – tomtaylor

+0

Ah, scusa, ho frainteso. Pensavo che stavi visualizzando un PDF, ma stai * creando * un PDF da viste esistenti. –

+0

Ho fatto alcuni nuovi suggerimenti; Penso che il tuo piano abbia un senso. Puoi anche provare a utilizzare una vista con strato di livello e l'utilizzo di una trasformazione su quel livello. (Sono più abituato a iOS, dove sarebbe la cosa naturale da fare.) –

Problemi correlati