Domanda

Per parte della mia applicazione ho bisogno di creare un'immagine di una determinata vista e di tutte le sue sottovisualizzazioni.

Per fare ciò sto creando un contesto che avvolge una bitmap con le stesse dimensioni della vista, ma non sono sicuro di come disegnarvi la gerarchia della vista.Posso disegnare una singola vista semplicemente impostando il contesto e chiamando esplicitamente drawRect, ma questo non riguarda tutte le sottoviste.

Non riesco a vedere nulla nell'interfaccia di NSView che potrebbe aiutare in questo, quindi sospetto che la soluzione possa trovarsi a un livello superiore.

È stato utile?

Soluzione

Ho scoperto che scrivere personalmente il codice di disegno era il modo migliore per:

  • gestire potenziali problemi di trasparenza (alcune delle altre opzioni aggiungono uno sfondo bianco all'intera immagine)
  • le prestazioni erano molto migliori

Il codice seguente non è perfetto, perché non affronta i problemi di ridimensionamento quando si passa dai limiti ai fotogrammi, ma tiene conto dello stato isFlipped e funziona molto bene per l'uso per cui lo ho utilizzato.Tieni presente che disegna solo le sottoviste (e le sottoviste,...ricorsivamente), ma farlo disegnare anche da solo è molto semplice, basta aggiungere a [self drawRect:[self bounds]] nell'attuazione di 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;
}

Altri suggerimenti

Puoi usare -[NSView dataWithPDFInsideRect:] per eseguire il rendering dell'intera gerarchia della vista a cui la invii in un PDF, restituito come file NSData oggetto.Puoi quindi fare quello che desideri con quello, incluso il rendering in una bitmap.

Sei sicuro di volere una rappresentazione bitmap?Dopotutto, quel PDF potrebbe essere (almeno in teoria) indipendente dalla risoluzione.

Puoi usare -[NSBitmapImageRep initWithFocusedViewRect:] dopo aver bloccato lo stato attivo su una vista per fare in modo che la vista esegua il rendering di se stessa (e delle sue sottoviste) nel rettangolo specificato.

Quello che vuoi fare è già disponibile esplicitamente.Consulta la sezione "API di reindirizzamento del disegno NSView" nelle note sulla versione 10.4 di AppKit.

Crea un NSBitmapImageRep per la memorizzazione nella cache e cancellalo:

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];

Memorizza nella cache:

-[NSView cacheDisplayInRect:toBitmapImageRep:]

Se desideri attingere più in generale a un contesto specifico gestendo correttamente la ricorsione e la trasparenza,

-[NSView displayRectIgnoringOpacity:inContext:]

Sì, per questo utilizzo specifico i dati dell'immagine non in scala sono esattamente ciò di cui ho bisogno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top