CGContextDrawImage trage imaginea cu susul în jos atunci când a trecut UIImage.CGImage

voturi
169

Stie cineva de ce CGContextDrawImagear fi de desen imaginea mea cu susul în jos? Sunt de încărcare o imagine de pe cererea mea:

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

Și apoi pur și simplu cere grafică de bază să-l atragă în funcție de contextul meu:

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

Ea face în locul potrivit, și dimensiunile, dar imaginea este cu susul în jos. Trebuie să lipsească ceva foarte evident aici?

Întrebat 03/02/2009 la 11:23
sursa de către utilizator
În alte limbi...                            


18 răspunsuri

voturi
218

In loc de

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

Utilizare

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

În mijlocul începe / finali CGcontextmetode.

Acest lucru va atrage imaginea cu orientarea corectă în contextul imaginii curente - Sunt destul de sigur că acest lucru are ceva de- a face cu UIImagedeținerea pe cunoașterea orientării în timp ce CGContextDrawImagemetoda devine datele imaginii brute care stau la baza cu nici o înțelegere de orientare.

Rețineți că va rula în această problemă în multe domenii, dar un exemplu specific este de a face cu adresa de carte de imagini ale utilizatorilor.

Publicat 06/02/2009 la 21:46
sursa de către utilizator

voturi
211

Chiar și după aplicarea tot ce am menționat, am avut încă drame cu imaginile. În cele din urmă, am folosit doar Gimp pentru a crea o versiune „oglindită pe verticală“ a tuturor imaginilor mele. Acum, nu am nevoie de a utiliza orice Transformări. Să sperăm că acest lucru nu va cauza probleme în continuare în jos pe pista.

Stie cineva de ce CGContextDrawImage ar fi imaginea mea de desen cu susul în jos? Sunt de încărcare o imagine de pe cererea mea:

Quartz2d utilizează un alt sistem de coordonate, în cazul în care originea este în colțul din stânga jos. Deci, atunci când cuarț trage pixeli x [5], y [10] a unei imagini de 100 * 100, care pixel este tras în colțul din stânga jos în loc de stânga sus. Astfel, provocând imaginea „oglindită“.

Sistemul de coordonate x meciuri, astfel încât va trebui să flip coordonatele y.

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

Acest lucru înseamnă că am tradus imaginea de 0 unități pe axa x și de înălțimea imaginilor de pe axa y. Cu toate acestea, numai acest lucru va însemna imaginea noastră este încă cu susul în jos, doar a fi tras „image.size.height“ de mai jos în cazul în care am dori să fie trase.

Ghidul de programare Quartz2D recomandă utilizarea ScaleCTM și trece valori negative pentru a răsturna imaginea. Puteți folosi următorul cod pentru a face acest lucru -

CGContextScaleCTM(context, 1.0, -1.0);

Se combină cele două chiar înainte de dvs. de CGContextDrawImageapel și ar trebui să aveți imaginea desenat corect.

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

Doar fii atent dacă imageRect coordonatelor tale nu se potrivesc cu cele ale imaginii, după cum puteți obține rezultate nedorite.

Pentru a converti înapoi coordonatele:

CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);
Publicat 04/02/2009 la 13:49
sursa de către utilizator

voturi
19

Cel mai bun din ambele lumi, utilizarea lui UIImage drawAtPoint:sau în drawInRect:timp ce încă specificând contextul personalizat:

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

De asemenea , evitați modificarea contextului cu CGContextTranslateCTMsau CGContextScaleCTMcare al doilea răspuns nu.

Publicat 07/08/2013 la 06:47
sursa de către utilizator

voturi
8

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

Inversarea Implicit sistemului de coordonate

Inversarea în desen UIKit modifică CALayer suport pentru a alinia un mediu de desen având coordonate un sistem cu LLO implicit sistemul de coordonate UIKit. Dacă utilizați doar metode și funcția UIKit pentru desen, nu ar trebui să nevoie să flip CTM. Cu toate acestea, dacă se amestecă Core Graphics sau o imagine I / O, funcția de apeluri cu apeluri UIKit, flipping CTM ar putea fi necesare.

Mai exact, în cazul în care desenați o imagine sau un document PDF apelând direct funcții Core Graphics, obiectul este redat cu susul în jos, în contextul vizualizării. Trebuie să flip CTM pentru a afișa corect imaginea și pagini.

Pentru oglinda a unui obiect într-un context grafică de bază, astfel încât să apară în mod corect atunci când sunt afișate într-o vizualizare UIKit, trebuie să modificați CTM în două etape. Tu traduce originea în colțul din stânga-sus al zonei de desenare, apoi aplicați o traducere la scară, modificarea y coordonate de -1. Codul pentru a face acest lucru pare similar cu următorul:

CGContextSaveGState(graphicsContext);
CGContextTranslateCTM(graphicsContext, 0.0, imageHeight);
CGContextScaleCTM(graphicsContext, 1.0, -1.0);
CGContextDrawImage(graphicsContext, image, CGRectMake(0, 0, imageWidth, imageHeight));
CGContextRestoreGState(graphicsContext);
Publicat 08/04/2016 la 06:11
sursa de către utilizator

voturi
7

Nu sunt sigur pentru UIImage, dar acest tip de comportament se produce , de obicei , atunci când coordonatele sunt oglindită. Cele mai multe dintre OS X sisteme de coordonate își au originea în colțul din stânga jos, la fel ca în Postscript și PDF. Dar CGImagesistemul de coordonate are originea în colțul din stânga sus.

Soluții posibile pot implica o isFlippedproprietate sau un scaleYBy:-1afin de transformare.

Publicat 03/02/2009 la 11:34
sursa de către utilizator

voturi
6

Dacă cineva este interesat într-o soluție foarte simplă pentru desen o imagine într-un RECT personalizat într-un context:

 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)

}

Imaginea va fi scalate pentru a umple zona RECT.

Publicat 18/02/2016 la 14:20
sursa de către utilizator

voturi
3

Swift 3.0 & 4.0

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

Nu este nevoie Alterarea

Publicat 04/08/2017 la 10:41
sursa de către utilizator

voturi
3

Putem rezolva această problemă, folosind aceeași funcție:

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

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

UIGraphicsPopContext();

UIGraphicsEndImageContext();
Publicat 25/08/2011 la 07:27
sursa de către utilizator

voturi
3

UIImageconține un CGImageca membru de conținutul principal precum și de scalare și orientare factori. Deoarece CGImageși diversele sale funcții sunt derivate din OSX, se asteapta un sistem care este cu susul în jos în comparație cu iPhone coordonate. Când creați o UIImage, implicit este o orientare cu susul în jos pentru a compensa (puteți schimba acest lucru!). Folosește . CGImageproprietate pentru a avea acces la foarte puternice CGImagefuncții, dar desen pe ecranul iPhone etc este cel mai bine cu UIImagemetodele.

Publicat 01/08/2010 la 00:26
sursa de către utilizator

voturi
2

răspuns cu codul Swift scrisoare

Grafica Quartz 2D folosesc un sistem de coordonate cu originea în partea din stânga jos în timp ce UIKit în iOS utilizează un sistem de coordonate cu originea în partea din stânga sus. Totul funcționează bine , de obicei , dar atunci când faci unele operații grafice, trebuie să modificați sistemul de coordonate tine. Cele documentare state:

Unele tehnologii creat contexte grafice, folosind sistemul decât cel utilizat de cuarț de coordonate un alt implicit. Comparativ cu cuarț, un astfel de sistem de coordonate este un sistem de coordonate modificat și trebuie să fie compensată la efectuarea unor operațiuni de desen cuarț. Cele mai frecvente modificat sistemul de coordonate plasează originea în colțul din stânga sus al contextului și modifică axa y la punctul spre partea de jos a paginii.

Acest fenomen poate fi văzut în următoarele două cazuri de opinii personalizate care atrag o imagine în lor drawRectmetode.

introduceți descrierea imaginii aici

Pe partea stângă, imaginea este cu susul în jos și pe partea dreaptă a fost tradus sistemul de coordonate și scalate astfel încât originea se află în partea stângă sus.

Imagine 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 sistem de coordonate

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)
}
Publicat 22/12/2015 la 03:25
sursa de către utilizator

voturi
1

drawInRecteste cu siguranță mod de a merge. Iată un alt lucru mic , care va veni în mod util atunci când faci acest lucru. De obicei , imaginea și dreptunghiul în care se va merge nu sunt conforme. În acest caz , se drawInRectva întinde imaginea. Iată o modalitate rapidă și se răcește pentru a se asigura că rației aspectul imaginii nu este schimbat, prin inversarea transformarea (care va fi pentru a se potrivi totul în):

//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];
Publicat 22/02/2010 la 06:57
sursa de către utilizator

voturi
0

Aceasta se întâmplă pentru că QuartzCore are sistemul de coordonate „de jos-stânga“, în timp ce UIKit - „sus-stânga“.

In cazul in care se poate extinde CGContext :

extension CGContext {
  func changeToTopLeftCoordinateSystem() {
    translateBy(x: 0, y: boundingBoxOfClipPath.size.height)
    scaleBy(x: 1, y: -1)
  }
}

// somewhere in render 
ctx.saveGState()
ctx.changeToTopLeftCoordinateSystem()
ctx.draw(cgImage!, in: frame)
Publicat 30/09/2019 la 11:28
sursa de către utilizator

voturi
0

Swift 5 răspuns bazat pe @ ZpaceZombor este un răspuns excelent

Dacă aveți un UIImage, trebuie doar să utilizați

var image: UIImage = .... 
image.draw(in: CGRect)

Dacă aveți o CGImage utilizați categoria mea de mai jos

Notă: Spre deosebire de alte răspunsuri, aceasta ia în considerare faptul că doriți să rect atragă ar putea avea y = 0. Aceste răspunsuri care nu iau în considerare faptul că sunt incorecte și nu va funcționa în cazul general!.

extension CGContext {
    final func drawImage(image: CGImage, inRect rect: CGRect) {

        //flip coords
        let ty: CGFloat = (rect.origin.y + rect.size.height)
        translateBy(x: 0, y: ty)
        scaleBy(x: 1.0, y: -1.0)

        //draw image
        let rect__y_zero = CGRect(x: rect.origin.x, y: 0, width: rect.width, height: rect.height)
        draw(image, in: rect__y_zero)

        //flip back
        scaleBy(x: 1.0, y: -1.0)
        translateBy(x: 0, y: -ty)

    }
} 

Utilizați ca aceasta:

let imageFrame: CGRect = ...
let context: CGContext = ....
let img: CGImage = ..... 
context.drawImage(image: img, inRect: imageFrame)
Publicat 20/09/2019 la 10:24
sursa de către utilizator

voturi
0
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()
    }
}
Publicat 03/05/2018 la 12:06
sursa de către utilizator

voturi
0

Swift 3 CoreGraphics Solution

Dacă doriți să utilizați CG pentru oricare ar fi motivul, în loc de UIImage, acest Swift 3 construcție pe baza răspunsurilor anterioare au rezolvat problema pentru mine:

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()
}
Publicat 31/08/2017 la 20:05
sursa de către utilizator

voturi
0

Pe parcursul proiectului meu am sărit de la răspunsul lui Kendall la răspunsul lui Cliff pentru a rezolva această problemă pentru imaginile care sunt încărcate de pe telefonul în sine.

În cele din urmă am ajuns , folosind în CGImageCreateWithPNGDataProviderschimb:

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

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

Acest lucru nu suferă de problemele de orientare pe care le - ar obține de la obtinerea de CGImagela o UIImageși poate fi folosit ca conținutul unui CALayerfara probleme.

Publicat 15/03/2014 la 17:13
sursa de către utilizator

Publicat 26/11/2009 la 13:24
sursa de către utilizator

voturi
-5

Puteți rezolva această problemă, de asemenea, de a face acest lucru:

//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.
Publicat 04/04/2012 la 02:55
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more