185

なぜCGContextDrawImage私のイメージを上下逆さまに描くのか誰か知っていますか? アプリケーションから画像を読み込んでいます:

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

そして、コアグラフィックスにそれを私のコンテキストに描画するように依頼するだけです:

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

適切な場所と寸法でレンダリングされますが、画像は上下逆になっています。ここで本当に明白な何かが欠けているに違いありませんか?

4

18 に答える 18

242

それ以外の

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

使用する

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

begin/endCGcontextメソッドの途中。

これにより、正しい向きの画像が現在の画像コンテキストに描画されます。これは、向きを理解せずに基になる生の画像データを取得するUIImageときに、向きの知識を保持することと関係があると確信しています。CGContextDrawImage

于 2009-02-06T20:46:51.277 に答える
217

私が言及したすべてを適用した後でも、私はまだイメージとのドラマを持っています. 最後に、Gimp を使用して、すべての画像の「反転した垂直」バージョンを作成しました。これで、トランスフォームを使用する必要がなくなりました。うまくいけば、これが今後さらに問題を引き起こすことはありません。

CGContextDrawImage が私の画像を上下逆さまに描画する理由を知っている人はいますか? アプリケーションから画像を読み込んでいます:

Quartz2d は、原点が左下隅にある別の座標系を使用します。そのため、Quartz が 100 * 100 画像のピクセル x[5]、y[10] を描画すると、そのピクセルは左上隅ではなく左下隅に描画されます。したがって、「反転」画像が発生します。

x 座標系が一致するため、y 座標を反転する必要があります。

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

これは、画像を x 軸で 0 単位、y 軸で画像の高さだけ変換したことを意味します。ただし、これだけでは、画像が上下逆さまになっていて、描画したい場所の下に「image.size.height」が描画されているだけです。

Quartz2D プログラミング ガイドでは、ScaleCTM を使用し、負の値を渡して画像を反転することを推奨しています。これを行うには、次のコードを使用できます-

CGContextScaleCTM(context, 1.0, -1.0);

呼び出しの直前に 2 つを組み合わせると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);
于 2009-02-04T12:49:36.610 に答える
21

両方の長所を生かして、カスタム コンテキストを指定しながらUIImage のdrawAtPoint:またはを使用します。drawInRect:

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

また、コンテキストを変更することも、2番目の回答が行うことも避けCGContextTranslateCTMますCGContextScaleCTM

于 2013-08-07T05:47:55.447 に答える
9

コンテキスト内のカスタム四角形に画像を描画するための簡単なソリューションに興味がある場合:

 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)

}

画像は四角形を埋めるようにスケーリングされます。

于 2016-02-18T14:20:40.980 に答える
7

についてはわかりませんUIImageが、この種の動作は通常、座標が反転したときに発生します。OS X 座標系のほとんどは、Postscript や PDF のように、左下隅に原点があります。ただし、CGImage座標系の原点は左上隅にあります。

isFlipped考えられる解決策には、プロパティまたはscaleYBy:-1アフィン変換が含まれる場合があります。

于 2009-02-03T10:34:26.477 に答える
4

これは、QuartzCore の座標系が「左下」で、UIKit の座標系が「左上」であるために発生します。

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)
于 2019-09-30T08:28:44.700 に答える
3

UIImageCGImageメインコンテンツメンバーとして、スケーリングと方向の要素が含まれています。とそのさまざまな機能はOSXから派生しているためCGImage、iPhoneと比較して逆さまの座標系が期待されます。を作成するUIImageと、デフォルトで上下逆向きに補正されます(これは変更できます!)。使用 。CGImage非常に強力な機能にアクセスするためのプロパティですCGImageが、iPhone画面などへの描画はUIImageメソッドを使用して行うのが最適です。

于 2010-07-31T23:26:32.087 に答える
3

Swiftコードによる補足回答

Quartz 2D グラフィックスは左下を原点とする座標系を使用しますが、iOS の UIKit は左上を原点とする座標系を使用します。通常はすべて問題なく動作しますが、一部のグラフィック操作を行う場合は、座標系を自分で変更する必要があります。ドキュメントには次のように記載されています。

一部のテクノロジは、Quartz が使用する座標系とは異なるデフォルトの座標系を使用してグラフィックス コンテキストをセットアップします。Quartz と比較すると、このような座標系は修正された座標系であり、一部の Quartz 描画操作を実行するときに補正する必要があります。最も一般的な修正座標系は、原点をコンテキストの左上隅に配置し、y 軸を変更してページの下部を指すようにします。

この現象は、メソッド内で画像を描画するカスタム ビューの次の 2 つのインスタンスで見られます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)
}
于 2015-12-22T03:25:46.050 に答える
1

drawInRect確かに行く方法です。これを行うときに役立つもう 1 つの小さなことを次に示します。通常、画像とそれが入る長方形は一致しません。その場合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];
于 2010-02-22T05:57:20.200 に答える
1

同じ関数を使用してこの問題を解決できます。

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

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

UIGraphicsPopContext();

UIGraphicsEndImageContext();
于 2011-08-25T06:27:55.470 に答える
0

私のプロジェクトの過程で、電話自体からロードされた画像のこの問題を解決するために、 Kendall の回答からCliff の回答にジャンプしました。

結局、CGImageCreateWithPNGDataProvider代わりに使用することになりました:

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

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

CGImageこれは、 aから を取得する際に発生する向きの問題に悩まされることはなく、問題なく aUIImageのコンテンツとして使用できますCALayer

于 2014-03-15T16:13:31.560 に答える
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()
    }
}
于 2018-05-03T12:06:37.670 に答える
-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.
于 2012-04-04T01:55:04.057 に答える