Pregunta

Para parte de mi aplicación, necesito crear una imagen de una determinada vista y todas sus subvistas.

Para hacer esto, estoy creando un contexto que envuelve un mapa de bits del mismo tamaño que la vista, pero no estoy seguro de cómo dibujar la jerarquía de vistas en él.Puedo dibujar una vista única simplemente configurando el contexto y llamando explícitamente a drawRect, pero esto no se ocupa de todas las subvistas.

No veo nada en la interfaz NSView que pueda ayudar con esto, así que sospecho que la solución puede estar en un nivel superior.

¿Fue útil?

Solución

Descubrí que escribir el código de dibujo yo mismo era la mejor manera de:

  • lidiar con posibles problemas de transparencia (algunas de las otras opciones agregan un fondo blanco a toda la imagen)
  • el rendimiento fue mucho mejor

El código siguiente no es perfecto porque no aborda problemas de escala al pasar de límites a fotogramas, pero sí tiene en cuenta el estado isFlipped y funciona muy bien para lo que lo usé.Tenga en cuenta que solo dibuja las subvistas (y las subsubvistas,...recursivamente), pero lograr que también se dibuje a sí mismo es muy fácil, simplemente agregue un [self drawRect:[self bounds]] en la implementación de imageWithSubviews.

- (void)drawSubviews
{
    BOOL flipped = [self isFlipped];

    for ( NSView *subview in [self subviews] ) {

        // changes the coordinate system so that the local coordinates of the subview (bounds) become the coordinates of the superview (frame)
        // the transform assumes bounds and frame have the same size, and bounds origin is (0,0)
        // handling of 'isFlipped' also probably unreliable
        NSAffineTransform *transform = [NSAffineTransform transform];
        if ( flipped ) {
            [transform translateXBy:subview.frame.origin.x yBy:NSMaxY(subview.frame)];
            [transform scaleXBy:+1.0 yBy:-1.0];
        } else
            [transform translateXBy:subview.frame.origin.x yBy:subview.frame.origin.y];
        [transform concat];

        // recursively draw the subview and sub-subviews
        [subview drawRect:[subview bounds]];
        [subview drawSubviews];

        // reset the transform to get back a clean graphic contexts for the rest of the drawing
        [transform invert];
        [transform concat];
    }
}

- (NSImage *)imageWithSubviews
{
    NSImage *image = [[[NSImage alloc] initWithSize:[self bounds].size] autorelease];
    [image lockFocus];
    // it seems NSImage cannot use flipped coordinates the way NSView does (the method 'setFlipped:' does not seem to help)
    // Use instead an NSAffineTransform
    if ( [self isFlipped] ) {
        NSAffineTransform *transform = [NSAffineTransform transform];
        [transform translateXBy:0 yBy:NSMaxY(self.bounds)];
        [transform scaleXBy:+1.0 yBy:-1.0];
        [transform concat];
    }
    [self drawSubviews];
    [image unlockFocus];
    return image;
}

Otros consejos

Puedes usar -[NSView dataWithPDFInsideRect:] para representar toda la jerarquía de la vista a la que la envía en un PDF, devuelto como un NSData objeto.Luego puedes hacer lo que quieras con eso, incluso renderizarlo en un mapa de bits.

¿Estás seguro de que quieres una representación de mapa de bits?Después de todo, ese PDF podría ser (al menos en teoría) independiente de la resolución.

Puedes usar -[NSBitmapImageRep initWithFocusedViewRect:] después de bloquear, céntrese en una vista para que la vista se represente (y sus subvistas) en el rectángulo dado.

Lo que quieres hacer ya está disponible explícitamente.Consulte la sección "API de redirección de dibujos NSView" en las notas de la versión 10.4 de AppKit.

Cree un NSBitmapImageRep para el almacenamiento en caché y bórrelo:

NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:cacheBitmapImageRep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
[[NSColor clearColor] set];
NSRectFill(NSMakeRect(0, 0, [cacheBitmapImageRep size].width, [cacheBitmapImageRep size].height));
[NSGraphicsContext restoreGraphicsState];

Caché para ello:

-[NSView cacheDisplayInRect:toBitmapImageRep:]

Si desea dibujar de manera más general en un contexto específico que maneje correctamente la recursividad y la transparencia de la vista,

-[NSView displayRectIgnoringOpacity:inContext:]

Sí, para este uso específico, los datos de imagen sin escala son exactamente lo que necesito.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top