Domanda

Qualcuno sa perché CGContextDrawImage sarebbe attirato la mia immagine a testa in giù? Sto caricando un'immagine in dalla mia applicazione:

UIImage *image = [UIImage imageNamed:@"testImage.png"];

E poi semplicemente chiedendo core grafico per disegnare al mio contesto:

CGContextDrawImage(context, CGRectMake(0, 0, 145, 15), image.CGImage);

Rende nel posto giusto, e le dimensioni, ma l'immagine è capovolta. Devo mancare qualcosa di davvero evidente qui?

È stato utile?

Soluzione

Al posto di

CGContextDrawImage(context, CGRectMake(0, 0, 145, 15), image.CGImage);

Usa

[image drawInRect:CGRectMake(0, 0, 145, 15)];

Nel mezzo dei vostri inizio / fine metodi CGcontext.

In questo modo attirare l'immagine con l'orientamento corretto nel vostro contesto immagine corrente - Sono abbastanza sicuro che questo ha qualcosa a che fare con la UIImage trattenendo la conoscenza dell'orientamento mentre il metodo CGContextDrawImage ottiene l'immagine raw sottostante i dati senza alcuna comprensione di orientamento.

Si noti che si incorrerà in questo problema in molti settori, ma un esempio specifico a che fare con le immagini della rubrica degli utenti.

Altri suggerimenti

Anche dopo l'applicazione di tutto quello che ho detto, ho ancora avuto drammi con le immagini. Alla fine, ho appena usato Gimp per creare una versione 'capovolto verticale' di tutte le mie immagini. Ora non ho bisogno di utilizzare tutte le trasformazioni. Speriamo che questo non causerà ulteriori problemi lungo la pista.

  

Qualcuno sa perché   CGContextDrawImage sarebbe attirato la mia   immagine sottosopra? Sto caricando un   immagine dalla mia applicazione:

Quartz2d utilizza un diverso sistema di coordinate, dove l'origine è nell'angolo in basso a sinistra. Così, quando quarzo disegna pixel x [5], y [10] di un'immagine a 100 * 100, tale pixel viene disegnato nell'angolo inferiore sinistro anziché in alto a sinistra. causando in tal modo l'immagine 'capovolto'.

Il sistema coordinata x corrisponde, quindi è necessario capovolgere le coordinate y.

CGContextTranslateCTM(context, 0, image.size.height);

Questo significa abbiamo tradotto l'immagine da 0 unità sull'asse x e dall'altezza immagini sull'asse y. Tuttavia, questo da solo significa che la nostra immagine è ancora a testa in giù, solo in fase di elaborazione "image.size.height" sotto dove vogliamo che da trarre.

La guida di programmazione Quartz2D consiglia di utilizzare ScaleCTM e passando valori negativi per capovolgere l'immagine. È possibile utilizzare il seguente codice per fare questo -

CGContextScaleCTM(context, 1.0, -1.0);

Unire i due poco prima CGContextDrawImage chiamata e si dovrebbe avere l'immagine disegnata in modo corretto.

UIImage *image = [UIImage imageNamed:@"testImage.png"];    
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);       

CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextDrawImage(context, imageRect, image.CGImage);

Basta essere attenti se il vostro imageRect coordinate non corrispondono a quelle dell'immagine, come si può ottenere risultati imprevisti.

Per riconvertire le coordinate:

CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);

Il meglio di entrambi i mondi, utilizzare UIImage del drawAtPoint: o drawInRect: pur specificando il contesto personalizzato:

UIGraphicsPushContext(context);
[image drawAtPoint:CGPointZero]; // UIImage will handle all especial cases!
UIGraphicsPopContext();

Inoltre si evita di modificare il contesto con CGContextTranslateCTM o CGContextScaleCTM che la seconda risposta fa.

rilevanti docs Quartz2D: https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW4

  

Sfogliando il sistema di coordinate predefinito

     

Ribaltamento nel disegno UIKit modifica il CALayer supporto per allineare un ambiente di disegno avente sistema con il difetto coordinate LLO sistema di coordinate UIKit. Se si utilizza solo metodi e funzioni UIKit per il disegno, non dovrebbe essere necessario capovolgere il marchio comunitario. Tuttavia, se si mescolano core grafico o l'immagine che la funzione O chiamate / chiamate UIKit, lanciando il marchio comunitario potrebbe essere necessario.

     

In particolare, se si disegna un'immagine o un documento PDF chiamando direttamente le funzioni di core grafico, l'oggetto è reso a testa in giù nel contesto della vista. È necessario capovolgere il marchio comunitario per visualizzare l'immagine e le pagine in modo corretto.

     

Per riflettere un oggetto disegnato per un contesto core grafico in modo che appaia correttamente quando visualizzato in una vista UIKit, è necessario modificare il marchio comunitario in due fasi. Tradurre l'origine all'angolo superiore sinistro dell'area di disegno, e quindi si applica traduzione scala, modificando la coordinata y per -1. Il codice per fare questo è simile al seguente:

CGContextSaveGState(graphicsContext);
CGContextTranslateCTM(graphicsContext, 0.0, imageHeight);
CGContextScaleCTM(graphicsContext, 1.0, -1.0);
CGContextDrawImage(graphicsContext, image, CGRectMake(0, 0, imageWidth, imageHeight));
CGContextRestoreGState(graphicsContext);

Non sono sicuro per UIImage, ma questo tipo di comportamento si verifica in genere quando le coordinate sono capovolte. La maggior parte di OS X sistemi di coordinate hanno la loro origine in basso a sinistra, come in PostScript e PDF. Ma CGImage sistema di coordinate ha la sua origine in alto a sinistra.

Possibili soluzioni possono comportare un isFlipped proprietà o di un scaleYBy:-1 trasformazione affine.

Se qualcuno è interessato a una soluzione non-sforzo per disegnare un'immagine in un rettangolo personalizzato in un contesto:

 func drawImage(image: UIImage, inRect rect: CGRect, context: CGContext!) {

    //flip coords
    let ty: CGFloat = (rect.origin.y + rect.size.height)
    CGContextTranslateCTM(context, 0, ty)
    CGContextScaleCTM(context, 1.0, -1.0)

    //draw image
    let rect__y_zero = CGRect(origin: CGPoint(x: rect.origin.x, y:0), size: rect.size)
    CGContextDrawImage(context, rect__y_zero, image.CGImage)

    //flip back
    CGContextScaleCTM(context, 1.0, -1.0)
    CGContextTranslateCTM(context, 0, -ty)

}

L'immagine verrà ridimensionata per riempire il rect.

Possiamo risolvere questo problema utilizzando la stessa funzione:

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

[image drawInRect:CGRectMake(gestureEndPoint.x,gestureEndPoint.y,350,92)];

UIGraphicsPopContext();

UIGraphicsEndImageContext();

UIImage contiene un CGImage come principale componente contenuto nonché scaling e fattori di orientamento. Poiché <=> e le sue varie funzioni sono derivate da OSX, si prevede un sistema che è capovolto rispetto al iPhone coordinata. Quando si crea un <=>, il valore predefinito è un orientamento capovolto per compensare (si può cambiare questo!). Utilizzare il. <=> Proprietà per accedere alle funzioni molto potenti <=>, ma disegnare sullo schermo di iPhone ecc è meglio farlo con i metodi <=>.

risposta supplementare con il codice Swift

grafico Quartz 2D utilizzano un sistema di coordinate con l'origine in basso a sinistra, mentre UIKit in IOS utilizza un sistema di coordinate con l'origine in alto a sinistra. Tutto di solito funziona bene, ma quando facendo alcune operazioni grafiche, è necessario modificare il sistema da soli coordinate. Il documentazione stati:

  

Alcune tecnologie definire i propri contesti grafiche che utilizzano un diverso   sistema di coordinate predefinito di quella usata da quarzo. Relativo a   Quarzo, un tale sistema di coordinate è un modificato sistema di coordinate e   deve essere compensato durante l'esecuzione di un certo disegno quarzo   operazioni. Il più comune modified sistema di coordinate pone il   origine nell'angolo superiore sinistro del contesto e cambia l'asse y   per puntare verso il fondo della pagina.

Questo fenomeno può essere visto nei seguenti due istanze di visualizzazioni personalizzate che disegnano un'immagine nei loro metodi drawRect.

entrare descrizione dell'immagine qui

Sul lato sinistro, l'immagine è capovolta e sul lato destro del sistema di coordinate è stato tradotto in scala e in modo che l'origine è in alto a sinistra.

immagine Upside-down

override func drawRect(rect: CGRect) {

    // image
    let image = UIImage(named: "rocket")!
    let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

    // context
    let context = UIGraphicsGetCurrentContext()

    // draw image in context
    CGContextDrawImage(context, imageRect, image.CGImage)

}

Modified sistema di coordinate

override func drawRect(rect: CGRect) {

    // image
    let image = UIImage(named: "rocket")!
    let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

    // context
    let context = UIGraphicsGetCurrentContext()

    // save the context so that it can be undone later
    CGContextSaveGState(context)

    // put the origin of the coordinate system at the top left
    CGContextTranslateCTM(context, 0, image.size.height)
    CGContextScaleCTM(context, 1.0, -1.0)

    // draw the image in the context
    CGContextDrawImage(context, imageRect, image.CGImage)

    // undo changes to the context
    CGContextRestoreGState(context)
}

Swift 3.0 e 4.0

yourImage.draw(in: CGRect, blendMode: CGBlendMode, alpha: ImageOpacity)

Nessuna alterazione necessaria

drawInRect è sicuramente la strada da percorrere. Ecco un'altra piccola cosa che verrà in modo utile quando si fa questo. Di solito l'immagine e il rettangolo in cui sta per andare non sono conformi. In tal caso <=> allungherà l'immagine. Ecco un modo veloce e fresco per assicurarsi che razione aspetto del quadro non è cambiato, invertendo la trasformazione (che sarà per adattare il tutto in):

//Picture and irect don't conform, so there'll be stretching, compensate
    float xf = Picture.size.width/irect.size.width;
    float yf = Picture.size.height/irect.size.height;
    float m = MIN(xf, yf);
    xf /= m;
    yf /= m;
    CGContextScaleCTM(ctx, xf, yf);

    [Picture drawInRect: irect];

Swift 3 CoreGraphics Soluzione

Se si desidera utilizzare CG per qualunque possa essere la ragione, invece di UIImage, questo Swift 3 costruzione in base alle risposte precedenti ha risolto il problema per me:

if let cgImage = uiImage.cgImage {
    cgContext.saveGState()
    cgContext.translateBy(x: 0.0, y: cgRect.size.height)
    cgContext.scaleBy(x: 1.0, y: -1.0)
    cgContext.draw(cgImage, in: cgRect)
    cgContext.restoreGState()
}

Nel corso del mio progetto sono saltato dalla risposta di Kendall per di Cliff risposta per risolvere questo problema per le immagini che vengono caricati dal telefono stesso.

Alla fine ho finito per usare CGImageCreateWithPNGDataProvider invece:

NSString* imageFileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"clockdial.png"];

return CGImageCreateWithPNGDataProvider(CGDataProviderCreateWithFilename([imageFileName UTF8String]), NULL, YES, kCGRenderingIntentDefault);

Questa non soffre di problemi di orientamento che si otterrebbe da ottenere il CGImage da un UIImage e può essere utilizzato come il contenuto di un CALayer senza intoppi.

func renderImage(size: CGSize) -> UIImage {
    return UIGraphicsImageRenderer(size: size).image { rendererContext in
        // flip y axis
        rendererContext.cgContext.translateBy(x: 0, y: size.height)
        rendererContext.cgContext.scaleBy(x: 1, y: -1)

        // draw image rotated/offsetted
        rendererContext.cgContext.saveGState()
        rendererContext.cgContext.translateBy(x: translate.x, y: translate.y)
        rendererContext.cgContext.rotate(by: rotateRadians)
        rendererContext.cgContext.draw(cgImage, in: drawRect)
        rendererContext.cgContext.restoreGState()
    }
}

È inoltre possibile risolvere questo problema in questo modo:

//Using an Image as a mask by directly inserting UIImageObject.CGImage causes
//the same inverted display problem. This is solved by saving it to a CGImageRef first.

//CGImageRef image = [UImageObject CGImage];

//CGContextDrawImage(context, boundsRect, image);

Nevermind... Stupid caching.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top