2012-07-07 18 views
6

Tengo una secuencia de NSViews fuera de pantalla en una aplicación Cocoa, que se utilizan para componer un PDF para imprimir. Las vistas no están en una ventana NSW, o son visibles de ninguna manera.Generar imagen escalada desde fuera de la pantalla NSView

Me gustaría poder generar imágenes en miniatura de esa vista, exactamente como se vería en el PDF, pero reducida para ajustarse a un determinado tamaño de píxel (restringido a un ancho o alto). Esto debe ser lo más rápido posible, por lo que me gustaría evitar renderizar en PDF, luego convertir a ráster y escalar. Me gustaría ir directamente al ráster.

En el momento que estoy haciendo:

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

Este enfoque funciona bien, pero no puedo encontrar la manera de aplicar una escala a la NSView antes de dibujar la bitmapImageRep. Quiero evitar el uso de scaleUnitSquareToSize, porque tal como lo entiendo, eso solo cambia los límites, no el marco de NSView.

¿Alguna sugerencia sobre la mejor manera de hacerlo?

Respuesta

6

Esto es lo que terminé haciendo, que funciona perfectamente. Dibujamos directamente en un NSBitmapImageRep, pero escala el contexto explícitamente utilizando CGContextScaleCTM de antemano. graphicsContext.graphicsPort le da el mango en el CGContextRef para el 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

Estaba usando 'bitmapImageRepForCacheDisplayInRect:' y 'cacheDisplayInRect: toBitmapImageRep:' para generar miniaturas dinámicamente para una aplicación de notebook en el momento del lanzamiento. Con más de 40 páginas (NSView alojados en capas) con mucho contenido visual, generar miniaturas tardaba cerca de 90 segundos. Este no era el caso en las versiones anteriores de macOS. Reemplacé este método con el enfoque de @ tomtaylor anterior, usando una escala de 1.0 (ya que necesito miniaturas para escalar fluidamente hacia arriba a tamaño completo) y la generación de miniaturas cayó a 20 segundos (fondo), ¡con aproximadamente la mitad del uso de memoria virtual! – Dalmazio

0

¿Qué le parece usar scaleUnitSquareToSize: y luego pasar en rect menor a bitmapImageRepForCachingDisplayInRect: y ?

Por lo tanto, si reduce la escala por un factor de 2, pasaría un rect a la mitad con límites y altura.

+0

Estoy usando el sistema de diseño de texto Cocoa, junto con NSTextContainer. Tal como lo entiendo, eso solo es posible en el nivel NSView. – tomtaylor

+0

Ah, lo siento, lo malentendí. Pensé que mostrabas un PDF, pero estás * creando * un PDF desde vistas existentes. –

+0

He hecho algunas sugerencias nuevas; Creo que tu plan tiene sentido. También podría intentar usar una vista respaldada por capa y usar una transformación en esa capa. (Estoy más acostumbrado a iOS, donde sería lo más natural). –

Cuestiones relacionadas