CGContextDrawImage εφιστά την εικόνα ανάποδα όταν πέρασε UIImage.CGImage

ψήφοι
169

Ξέρει κανείς γιατί CGContextDrawImageθα σχεδίων εικόνα μου ανάποδα; Είμαι φόρτωση μιας εικόνας από αίτησή μου:

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

Και τότε απλά ζητώντας πυρήνα γραφικών για να σχεδιάσετε το πλαίσιό μου:

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

Αυτό καθιστά στη σωστή θέση και διαστάσεις, αλλά η εικόνα είναι ανάποδα. Θα πρέπει να λείπει κάτι πραγματικά προφανές εδώ;

Δημοσιεύθηκε 03/02/2009 στις 11:23
πηγή χρήστη
Σε άλλες γλώσσες...                            


18 απαντήσεις

ψήφοι
218

Αντί

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

Χρήση

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

Στη μέση της έναρξης / λήξης σας CGcontextμεθόδους.

Αυτό θα επιστήσει την εικόνα με το σωστό προσανατολισμό στο σημερινό πλαίσιο της εικόνας σας - Είμαι απόλυτα σίγουρος ότι αυτό έχει να κάνει με την UIImageεκμετάλλευση σε γνώση του προσανατολισμού, ενώ η CGContextDrawImageμέθοδος παίρνει τα υποκείμενα των δεδομένων των πρώτων εικόνων χωρίς την κατανόηση της προσανατολισμό.

Σημειώστε ότι θα αντιμετωπίσετε αυτό το πρόβλημα σε πολλούς τομείς, αλλά ένα συγκεκριμένο παράδειγμα ασχολείται με τις εικόνες του χρήστη βιβλίο διευθύνσεων.

Απαντήθηκε 06/02/2009 στις 21:46
πηγή χρήστη

ψήφοι
211

Ακόμα και μετά την εφαρμογή όλα όσα ανέφερα, έχω ακόμα είχε δράματα με τις εικόνες. Στο τέλος, έχω απλώς χρησιμοποιείται Gimp για τη δημιουργία ενός «γυρίσει κάθετα» έκδοση του όλες τις εικόνες μου. Τώρα δεν χρειάζεται να χρησιμοποιήσετε οποιαδήποτε Μετασχηματισμοί. Ας ελπίσουμε ότι αυτό δεν θα προκαλέσει περαιτέρω προβλήματα κάτω από το δρόμο.

Ξέρει κανείς γιατί CGContextDrawImage θα σχεδίων εικόνα μου ανάποδα; Είμαι φόρτωση μιας εικόνας από αίτησή μου:

Quartz2d χρησιμοποιεί ένα διαφορετικό σύστημα συντεταγμένων, όπου η καταγωγή είναι στην κάτω αριστερή γωνία. Έτσι, όταν Quartz εφιστά pixel x [5], y [10] ενός 100 * 100 εικόνα, ότι το εικονοστοιχείο έλκεται στην κάτω αριστερή γωνία αντί του άνω αριστερού. Έτσι, προκαλώντας την «γυρίσει» την εικόνα.

Το σύστημα x συντεταγμένη ταιριάζει, έτσι θα πρέπει να αναστρέψετε τις y συντεταγμένες.

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

Αυτό σημαίνει ότι έχουμε μεταφραστεί την εικόνα από το 0 μονάδες στον άξονα χ και από το ύψος εικόνες στον άξονα y. Ωστόσο, αυτό από μόνο του θα σημάνει την εικόνα μας εξακολουθεί να είναι ανάποδα, μόνο στο στάδιο της επεξεργασίας «image.size.height» κάτω από εκεί που το επιθυμούν να εξαχθούν.

Ο οδηγός προγραμματισμού Quartz2D συνιστά τη χρήση ScaleCTM και περνώντας αρνητικές τιμές για την αναστροφή της εικόνας. Μπορείτε να χρησιμοποιήσετε τον παρακάτω κώδικα για να γίνει αυτό -

CGContextScaleCTM(context, 1.0, -1.0);

Συνδυάστε τα δύο λίγο πριν σας CGContextDrawImageκλήση και θα πρέπει να έχετε την εικόνα που σωστά.

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

Απλά να είστε προσεκτικοί αν imageRect συντεταγμένες σας δεν ταιριάζουν με εκείνα της εικόνας σας, όπως μπορείτε να πάρετε ακούσια αποτελέσματα.

Για να μετατρέψετε πίσω τις συντεταγμένες:

CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);
Απαντήθηκε 04/02/2009 στις 13:49
πηγή χρήστη

ψήφοι
19

Καλύτερο και των δύο κόσμων, χρησιμοποιήστε UIImage του drawAtPoint:ή drawInRect:ενώ εξακολουθεί να καθορίζει έθιμο πλαίσιο σας:

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

Επίσης, μπορείτε να αποφύγετε την τροποποίηση του πλαισίου σας CGContextTranslateCTMή CGContextScaleCTMτις οποίες η δεύτερη απάντηση κάνει.

Απαντήθηκε 07/08/2013 στις 06:47
πηγή χρήστη

ψήφοι
8

Σχετικές docs Quartz2D: https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW4

Flipping το προεπιλεγμένο σύστημα συντεταγμένων

Το κτύπημα στην UIKit σχέδιο τροποποιεί την CALayer υποστήριξη για να ευθυγραμμιστεί ένα περιβάλλον σχεδίασης που έχει ένα LLO σύστημα με το προεπιλεγμένο σύστημα συντεταγμένων της UIKit συντεταγμένων. Εάν χρησιμοποιείτε μόνο μεθόδους και τη λειτουργία UIKit για το σχέδιο, δεν θα χρειαστεί να αναστρέψετε το CTM. Ωστόσο, εάν αναμίξετε πυρήνα γραφικών ή εικόνας I / O λειτουργία κλήσεις με κλήσεις UIKit, ρίχνεις το CTM μπορεί να είναι απαραίτητη.

Συγκεκριμένα, αν σχεδιάσετε μια εικόνα ή ένα έγγραφο PDF καλώντας άμεσα τις λειτουργίες πυρήνα γραφικών, το αντικείμενο καθίσταται ανάποδα στο πλαίσιο της προβολής. Πρέπει αναστρέψετε το CTM για να εμφανιστεί η εικόνα και σελίδες σωστά.

Για να αναστρέψετε ένα αντικείμενο που σε ένα πλαίσιο πυρήνα γραφικών, έτσι ώστε να εμφανίζεται σωστά όταν εμφανίζονται σε μια προβολή UIKit, πρέπει να τροποποιήσετε το CTM σε δύο στάδια. Μπορείτε μεταφράσει την προέλευση στην επάνω αριστερή γωνία της περιοχής σχεδίασης, και στη συνέχεια να εφαρμόσετε μια μετάφραση κλίμακα, τροποποιώντας τη συντεταγμένη y από -1. Ο κώδικας για να γίνει αυτό μοιάζει με το ακόλουθο:

CGContextSaveGState(graphicsContext);
CGContextTranslateCTM(graphicsContext, 0.0, imageHeight);
CGContextScaleCTM(graphicsContext, 1.0, -1.0);
CGContextDrawImage(graphicsContext, image, CGRectMake(0, 0, imageWidth, imageHeight));
CGContextRestoreGState(graphicsContext);
Απαντήθηκε 08/04/2016 στις 06:11
πηγή χρήστη

ψήφοι
7

Δεν είμαι σίγουρος για το UIImage, αλλά αυτό το είδος της συμπεριφοράς που συνήθως συμβαίνει όταν οι συντεταγμένες γυρίσει. Τα περισσότερα από τα OS X συστήματα συντεταγμένων έχουν την προέλευσή τους στην κάτω αριστερή γωνία, όπως το Postscript και PDF. Αλλά CGImageσύστημα συντεταγμένων έχει την προέλευσή της στην πάνω αριστερή γωνία.

Πιθανές λύσεις μπορεί να περιλαμβάνει ένα isFlippedακίνητο ή ένα scaleYBy:-1affine μετασχηματισμό.

Απαντήθηκε 03/02/2009 στις 11:34
πηγή χρήστη

ψήφοι
6

Αν κάποιος ενδιαφέρεται για μια λύση μη-brainer για την κατάρτιση μιας εικόνας σε μια προσαρμοσμένη ορθ σε ένα πλαίσιο:

 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)

}

Η εικόνα θα προσαρμοστεί για να γεμίσει το ορθ.

Απαντήθηκε 18/02/2016 στις 14:20
πηγή χρήστη

ψήφοι
3

Swift 3.0 & 4.0

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

Δεν Τροποποίηση χρειάζεται

Απαντήθηκε 04/08/2017 στις 10:41
πηγή χρήστη

ψήφοι
3

Μπορούμε να λύσουμε αυτό το πρόβλημα χρησιμοποιώντας την ίδια λειτουργία:

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

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

UIGraphicsPopContext();

UIGraphicsEndImageContext();
Απαντήθηκε 25/08/2011 στις 07:27
πηγή χρήστη

ψήφοι
3

UIImageπεριέχει ένα CGImageως κύριο μέλος περιεχόμενό της, καθώς και την κλιμάκωση και τον προσανατολισμό παράγοντες. Δεδομένου ότι CGImageκαι οι διάφορες λειτουργίες του προέρχεται από OSX, αναμένει ένα σύστημα που είναι ανάποδα σε σχέση με το iPhone συντεταγμένων. Όταν δημιουργείτε ένα UIImage, από προεπιλογή σε έναν προσανατολισμό ανάποδα για να αντισταθμίσει (μπορείτε να το αλλάξετε αυτό!). Χρησιμοποιήστε το . CGImageιδιοκτησία για να αποκτήσετε πρόσβαση στις πολύ ισχυρές CGImageλειτουργίες, αλλά αντλώντας πάνω στην οθόνη του iPhone κλπ είναι καλύτερο να γίνεται με τις UIImageμεθόδους.

Απαντήθηκε 01/08/2010 στις 00:26
πηγή χρήστη

ψήφοι
2

Συμπληρωματικό απάντηση με το Swift code

Quartz 2D γραφικά χρησιμοποιούν ένα σύστημα συντεταγμένων με την προέλευση στο κάτω αριστερά, ενώ UIKit στο iOS χρησιμοποιεί ένα σύστημα συντεταγμένων με την προέλευση στην επάνω αριστερή γωνία. Όλα συνήθως λειτουργεί καλά, αλλά όταν κάνει κάποιες εργασίες γραφικών, θα πρέπει να τροποποιήσετε το σύστημα μόνοι σας συντεταγμένων. Τα έγγραφα που αναφέρει:

Ορισμένες τεχνολογίες που έχει συσταθεί πλαίσια γραφικά τους χρησιμοποιώντας ένα διαφορετικό προεπιλεγμένο σύστημα από αυτό που χρησιμοποιείται από χαλαζία συντεταγμένων. Σε σχέση με χαλαζία, ένα τέτοιο σύστημα συντεταγμένων είναι ένα τροποποιημένο σύστημα συντεταγμένων και πρέπει να αποζημιωθούν για κατά την εκτέλεση ορισμένων εργασιών κατάρτιση χαλαζία. Η πιο κοινή τροποποιημένο σύστημα συντεταγμένων τοποθετεί την προέλευση στην επάνω αριστερή γωνία του πλαισίου και αλλάζει τον άξονα y στο σημείο προς το κάτω μέρος της σελίδας.

Αυτό το φαινόμενο μπορεί να φανεί στις ακόλουθες δύο περιπτώσεις προσαρμοσμένες προβολές που σύρουν μια εικόνα σε τους drawRectμεθόδους.

εισάγετε περιγραφή της εικόνας εδώ

Στην αριστερή πλευρά, η εικόνα είναι ανάποδα και στη δεξιά πλευρά το σύστημα συντεταγμένων έχει μεταφραστεί και κλιμακώνεται έτσι ώστε η προέλευση είναι επάνω αριστερά.

Ανάποδα εικόνα

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)

}

Τροποποιημένο σύστημα συντεταγμένων

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)
}
Απαντήθηκε 22/12/2015 στις 03:25
πηγή χρήστη

ψήφοι
1

drawInRectείναι σίγουρα ο τρόπος να πάει. Εδώ είναι ένα άλλο μικρό πράγμα που θα έρθουν στο δρόμο χρήσιμο όταν κάνετε κάτι τέτοιο. Συνήθως η εικόνα και το ορθογώνιο μέσα στο οποίο πρόκειται να πάει δεν συμμορφώνονται. Σε αυτή την περίπτωση drawInRectθα τεντώσει την εικόνα. Εδώ είναι ένας γρήγορος και έξυπνος τρόπος για να βεβαιωθείτε ότι η αναλογία διαστάσεων της εικόνας δεν αλλάζει, αντιστρέφοντας το μετασχηματισμό (η οποία θα είναι για να χωρέσει το όλο θέμα σε):

//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];
Απαντήθηκε 22/02/2010 στις 06:57
πηγή χρήστη

ψήφοι
0

Αυτό συμβαίνει γιατί QuartzCore έχει το σύστημα συντεταγμένων "από κάτω προς τα αριστερά", ενώ UIKit - "top-left".

Στην περίπτωση μπορείτε να επεκτείνετε 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)
Απαντήθηκε 30/09/2019 στις 11:28
πηγή χρήστη

ψήφοι
0

Swift 5 απάντηση με βάση @ ZpaceZombor είναι εξαιρετική απάντηση

Εάν έχετε ένα UIImage, απλά χρησιμοποιήστε

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

Εάν έχετε ένα CGImage χρησιμοποιήσετε την κατηγορία μου παρακάτω

Σημείωση: Σε αντίθεση με κάποιες άλλες απαντήσεις, αυτό λαμβάνει υπόψη ότι η ορθ θέλετε να προσελκύσει μπορεί να έχει y = 0. τις απαντήσεις που δεν λαμβάνουν υπόψη το γεγονός αυτό δεν είναι σωστές και δεν θα λειτουργήσει στη γενική περίπτωση!.

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)

    }
} 

Χρησιμοποιήστε σαν αυτό:

let imageFrame: CGRect = ...
let context: CGContext = ....
let img: CGImage = ..... 
context.drawImage(image: img, inRect: imageFrame)
Απαντήθηκε 20/09/2019 στις 10:24
πηγή χρήστη

ψήφοι
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()
    }
}
Απαντήθηκε 03/05/2018 στις 12:06
πηγή χρήστη

ψήφοι
0

Swift Λύση 3 CoreGraphics

Αν θέλετε να χρησιμοποιήσετε το CG για ό, τι θα μπορούσε να είναι ο λόγος σας, αντί να UIImage, αυτό το Swift 3 κατασκευής με βάση τις προηγούμενες απαντήσεις έλυσε το ζήτημα για μένα:

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()
}
Απαντήθηκε 31/08/2017 στις 20:05
πηγή χρήστη

ψήφοι
0

Κατά τη διάρκεια του έργου μου πήδηξα από την απάντηση του Kendall για την απάντηση Cliff για να λύσει αυτό το πρόβλημα για εικόνες που φορτώνονται από το ίδιο το τηλέφωνο.

Στο τέλος κατέληξα να χρησιμοποιούν CGImageCreateWithPNGDataProviderαντ 'αυτού:

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

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

Αυτό δεν πάσχει από τα προβλήματα προσανατολισμού που θα πάρετε από το να πάρει το CGImageαπό ένα UIImageκαι μπορεί να χρησιμοποιηθεί ως το περιεχόμενο ενός CALayerχωρίς κανένα πρόβλημα.

Απαντήθηκε 15/03/2014 στις 17:13
πηγή χρήστη

Απαντήθηκε 26/11/2009 στις 13:24
πηγή χρήστη

ψήφοι
-5

Μπορείτε, επίσης, να λύσει αυτό το πρόβλημα με τον τρόπο αυτό:

//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.
Απαντήθηκε 04/04/2012 στις 02:55
πηγή χρήστη

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