ios CGContextDrawImage 在传递 UIImage.CGImage 时将图像倒置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/506622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CGContextDrawImage draws image upside down when passed UIImage.CGImage
提问by rustyshelf
Does anyone know why CGContextDrawImage
would be drawing my image upside down? I am loading an image in from my application:
有谁知道为什么CGContextDrawImage
要把我的图像倒过来画?我正在从我的应用程序加载图像:
UIImage *image = [UIImage imageNamed:@"testImage.png"];
And then simply asking core graphics to draw it to my context:
然后简单地要求核心图形将其绘制到我的上下文中:
CGContextDrawImage(context, CGRectMake(0, 0, 145, 15), image.CGImage);
It renders in the right place, and dimensions, but the image is upside down. I must be missing something really obvious here?
它呈现在正确的位置和尺寸,但图像是颠倒的。我一定在这里遗漏了一些非常明显的东西?
回答by Kendall Helmstetter Gelner
Instead of
代替
CGContextDrawImage(context, CGRectMake(0, 0, 145, 15), image.CGImage);
Use
用
[image drawInRect:CGRectMake(0, 0, 145, 15)];
In the middle of your begin/end CGcontext
methods.
在开始/结束CGcontext
方法的中间。
This will draw the image with the correct orientation into your current image context - I'm pretty sure this has something to do with the UIImage
holding onto knowledge of the orientation while the CGContextDrawImage
method gets the underlying raw image data with no understanding of orientation.
这会将具有正确方向的图像绘制到您当前的图像上下文中 - 我很确定这与UIImage
保持方向知识有关,而该CGContextDrawImage
方法在不了解方向的情况下获取底层原始图像数据。
回答by Cliff Viegas
Even after applying everything I have mentioned, I've still had dramas with the images. In the end, i've just used Gimp to create a 'flipped vertical' version of all my images. Now I don't need to use any Transforms. Hopefully this won't cause further problems down the track.
即使在应用了我提到的所有内容之后,我仍然有图像的戏剧性。最后,我刚刚使用 Gimp 创建了我所有图像的“垂直翻转”版本。现在我不需要使用任何变换。希望这不会在赛道上造成进一步的问题。
Does anyone know why CGContextDrawImage would be drawing my image upside down? I am loading an image in from my application:
有谁知道为什么 CGContextDrawImage 会颠倒绘制我的图像?我正在从我的应用程序加载图像:
Quartz2d uses a different co-ordinate system, where the origin is in the lower left corner. So when Quartz draws pixel x[5], y[10] of a 100 * 100 image, that pixel is being drawn in the lower left corner instead of the upper left. Thus causing the 'flipped' image.
Quartz2d 使用不同的坐标系,原点在左下角。因此,当 Quartz 绘制 100 * 100 图像的像素 x[5], y[10] 时,该像素被绘制在左下角而不是左上角。从而导致“翻转”图像。
The x co-ordinate system matches, so you will need to flip the y co-ordinates.
x 坐标系匹配,因此您需要翻转 y 坐标。
CGContextTranslateCTM(context, 0, image.size.height);
This means we have translated the image by 0 units on the x axis and by the images height on the y axis. However, this alone will mean our image is still upside down, just being drawn "image.size.height" below where we wish it to be drawn.
这意味着我们已经将图像在 x 轴上平移了 0 个单位,在 y 轴上平移了图像高度。然而,仅此一项就意味着我们的图像仍然是颠倒的,只是在我们希望绘制的位置下方绘制了“image.size.height”。
The Quartz2D programming guide recommends using ScaleCTM and passing negative values to flip the image. You can use the following code to do this -
Quartz2D 编程指南推荐使用 ScaleCTM 并传递负值来翻转图像。您可以使用以下代码来执行此操作 -
CGContextScaleCTM(context, 1.0, -1.0);
Combine the two just before your CGContextDrawImage
call and you should have the image drawn correctly.
在您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);
Just be careful if your imageRect co-ordinates do not match those of your image, as you can get unintended results.
如果您的 imageRect 坐标与图像的坐标不匹配,请小心,因为您可能会得到意想不到的结果。
To convert back the coordinates:
转换回坐标:
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);
回答by Rivera
Best of both worlds, use UIImage's drawAtPoint:
or drawInRect:
while still specifying your custom context:
两全其美,使用 UIImagedrawAtPoint:
或drawInRect:
同时仍然指定您的自定义上下文:
UIGraphicsPushContext(context);
[image drawAtPoint:CGPointZero]; // UIImage will handle all especial cases!
UIGraphicsPopContext();
Also you avoid modifying your context with CGContextTranslateCTM
or CGContextScaleCTM
which the second answer does.
你也避免修改你的上下文CGContextTranslateCTM
或CGContextScaleCTM
第二个答案所做的。
回答by kcmoffat
Relevant Quartz2D docs: https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW4
相关 Quartz2D 文档:https: //developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW4
Flipping the Default Coordinate System
Flipping in UIKit drawing modifies the backing CALayer to align a drawing environment having a LLO coordinate system with the default coordinate system of UIKit. If you only use UIKit methods and function for drawing, you shouldn't need to flip the CTM. However, if you mix Core Graphics or Image I/O function calls with UIKit calls, flipping the CTM might be necessary.
Specifically, if you draw an image or PDF document by calling Core Graphics functions directly, the object is rendered upside-down in the view's context. You must flip the CTM to display the image and pages correctly.
To flip a object drawn to a Core Graphics context so that it appears correctly when displayed in a UIKit view, you must modify the CTM in two steps. You translate the origin to the upper-left corner of the drawing area, and then you apply a scale translation, modifying the y-coordinate by -1. The code for doing this looks similar to the following:
翻转默认坐标系
在 UIKit 绘图中翻转会修改支持 CALayer 以将具有 LLO 坐标系的绘图环境与 UIKit 的默认坐标系对齐。如果只使用 UIKit 方法和函数进行绘图,则不需要翻转 CTM。但是,如果您将 Core Graphics 或 Image I/O 函数调用与 UIKit 调用混合使用,则可能需要翻转 CTM。
具体来说,如果您通过直接调用 Core Graphics 函数来绘制图像或 PDF 文档,则该对象在视图的上下文中会颠倒呈现。您必须翻转 CTM 才能正确显示图像和页面。
要翻转绘制到 Core Graphics 上下文的对象,以便它在 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);
回答by ZpaceZombor
If anyone is interested in a no-brainer solution for drawing an image in a custom rect in a 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)
}
The image will be scaled to fill the rect.
图像将被缩放以填充矩形。
回答by mouviciel
I'm not sure for UIImage
, but this kind of behaviour usually occurs when coordinates are flipped. Most of OS X coordinate systems have their origin at the lower left corner, as in Postscript and PDF. But CGImage
coordinate system has its origin at the upper left corner.
我不确定UIImage
,但这种行为通常发生在坐标翻转时。大多数 OS X 坐标系的原点都在左下角,如 Postscript 和 PDF。但是CGImage
坐标系的原点在左上角。
Possible solutions may involve an isFlipped
property or a scaleYBy:-1
affine transform.
可能的解决方案可能涉及isFlipped
属性或scaleYBy:-1
仿射变换。
回答by James L
UIImage
contains a CGImage
as its main content member as well as scaling and orientation factors. Since CGImage
and its various functions are derived from OSX, it expects a coordinate system that is upside down compared to the iPhone. When you create a UIImage
, it defaults to an upside-down orientation to compensate (you can change this!). Use the .CGImage
property to access the very powerful CGImage
functions, but drawing onto the iPhone screen etc. is best done with the UIImage
methods.
UIImage
包含 aCGImage
作为其主要内容成员以及缩放和方向因素。由于CGImage
其各种功能源自 OSX,因此与 iPhone 相比,它需要一个颠倒的坐标系。创建 时UIImage
,它默认为颠倒方向以进行补偿(您可以更改此设置!)。使用 。CGImage
属性来访问非常强大的CGImage
功能,但最好使用UIImage
方法来完成在 iPhone 屏幕等上的绘制。
回答by Abdul Waheed
Swift 3.0 & 4.0
斯威夫特 3.0 和 4.0
yourImage.draw(in: CGRect, blendMode: CGBlendMode, alpha: ImageOpacity)
No Alteration needed
无需改动
回答by Suragch
Supplemental answer with Swift code
Swift 代码的补充答案
Quartz 2D graphics use a coordinate system with the origin in the bottom left while UIKit in iOS uses a coordinate system with the origin at the top left. Everything usually works fine but when doing some graphics operations, you have to modify the coordinate system yourself. The documentationstates:
Quartz 2D 图形使用原点在左下角的坐标系,而 iOS 中的 UIKit 使用原点在左上角的坐标系。通常一切正常,但在进行一些图形操作时,您必须自己修改坐标系。该文件指出:
Some technologies set up their graphics contexts using a different default coordinate system than the one used by Quartz. Relative to Quartz, such a coordinate system is a modified coordinate system and must be compensated for when performing some Quartz drawing operations. The most common modified coordinate system places the origin in the upper-left corner of the context and changes the y-axis to point towards the bottom of the page.
一些技术使用不同于 Quartz 使用的默认坐标系来设置它们的图形上下文。相对于Quartz,这样的坐标系是修改后的坐标系,在进行一些Quartz绘制操作时必须进行补偿。最常见的修改坐标系将原点放置在上下文的左上角,并将 y 轴更改为指向页面底部。
This phenomenon can be seen in the following two instances of custom views that draw an image in their drawRect
methods.
这种现象可以在以下两个在其drawRect
方法中绘制图像的自定义视图实例中看到。
On the left side, the image is upside-down and on the right side the coordinate system has been translated and scaled so that the origin is in the top left.
在左侧,图像是倒置的,在右侧,坐标系已被平移和缩放,因此原点位于左上角。
Upside-down image
颠倒的图像
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 coordinate system
修正坐标系
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)
}
回答by Priyanka V
We can solve this problem using the same function:
我们可以使用相同的函数解决这个问题:
UIGraphicsBeginImageContext(image.size);
UIGraphicsPushContext(context);
[image drawInRect:CGRectMake(gestureEndPoint.x,gestureEndPoint.y,350,92)];
UIGraphicsPopContext();
UIGraphicsEndImageContext();