CGContextDrawImage 传递 UIImage.CGImage 时颠倒绘制图像

发布于 2024-07-12 21:57:57 字数 325 浏览 10 评论 0 原文

有谁知道为什么 CGContextDrawImage 会颠倒绘制我的图像? 我正在从我的应用程序加载图像:

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

然后简单地要求核心图形将其绘制到我的上下文中:

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

它呈现在正确的位置和尺寸,但图像是颠倒的。 我一定在这里遗漏了一些非常明显的东西?

Does anyone know why CGContextDrawImage would be drawing my image upside down? I am loading an image in from my application:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

时光病人 2024-07-19 21:57:57

两全其美,使用 UIImage 的 drawAtPoint:drawInRect:,同时仍指定自定义上下文:

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

此外,您还可以避免使用 CGContextTranslateCTM 或 < code>CGContextScaleCTM 第二个答案就是这样做的。

Best of both worlds, use UIImage's drawAtPoint: or drawInRect: while still specifying your custom context:

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.

本宫微胖 2024-07-19 21:57:57

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

翻转默认坐标系

UIKit 绘图中的翻转会修改支持 CALayer,以将具有 LLO 坐标系的绘图环境与 UIKit 的默认坐标系对齐。 如果您仅使用 UIKit 方法和函数进行绘图,则不需要翻转 CTM。 但是,如果将 Core Graphics 或图像 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);

Relevant Quartz2D docs: https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/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:

CGContextSaveGState(graphicsContext);
CGContextTranslateCTM(graphicsContext, 0.0, imageHeight);
CGContextScaleCTM(graphicsContext, 1.0, -1.0);
CGContextDrawImage(graphicsContext, image, CGRectMake(0, 0, imageWidth, imageHeight));
CGContextRestoreGState(graphicsContext);
情绪操控生活 2024-07-19 21:57:57

即使在应用了我提到的所有内容之后,我仍然对图像产生戏剧性的感觉。 最后,我刚刚使用 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);

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

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.

Does anyone know why
CGContextDrawImage would be drawing my
image upside down? I am loading an
image in from my application:

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.

The x co-ordinate system matches, so you will need to flip the y co-ordinates.

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.

The Quartz2D programming guide recommends using ScaleCTM and passing negative values to flip the image. You can use the following code to do this -

CGContextScaleCTM(context, 1.0, -1.0);

Combine the two just before your CGContextDrawImage call and you should have the image drawn correctly.

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.

To convert back the coordinates:

CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);
╰ゝ天使的微笑 2024-07-19 21:57:57

而不是

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

使用

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

在开始/结束 CGcontext 方法中间

。 这将以正确的方向将图像绘制到当前图像上下文中 - 我很确定这与 UIImageCGContextDrawImage 时掌握方向知识有关> 方法获取底层原始图像数据,但不了解方向。

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.

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.

鼻尖触碰 2024-07-19 21:57:57

我使用这个 Swift 5,纯 Core Graphics 扩展,它可以正确处理图像矩形中的非零原点:

extension CGContext {

    /// Draw `image` flipped vertically, positioned and scaled inside `rect`.
    public func drawFlipped(_ image: CGImage, in rect: CGRect) {
        self.saveGState()
        self.translateBy(x: 0, y: rect.origin.y + rect.height)
        self.scaleBy(x: 1.0, y: -1.0)
        self.draw(image, in: CGRect(origin: CGPoint(x: rect.origin.x, y: 0), size: rect.size))
        self.restoreGState()
    }
}

您可以像 CGContext' 一样使用它常规 draw(: in:) 方法:

ctx.drawFlipped(myImage, in: myRect)

I use this Swift 5, pure Core Graphics extension that correctly handles non-zero origins in image rects:

extension CGContext {

    /// Draw `image` flipped vertically, positioned and scaled inside `rect`.
    public func drawFlipped(_ image: CGImage, in rect: CGRect) {
        self.saveGState()
        self.translateBy(x: 0, y: rect.origin.y + rect.height)
        self.scaleBy(x: 1.0, y: -1.0)
        self.draw(image, in: CGRect(origin: CGPoint(x: rect.origin.x, y: 0), size: rect.size))
        self.restoreGState()
    }
}

You can use it exactly like CGContext's regular draw(: in:) method:

ctx.drawFlipped(myImage, in: myRect)
长伴 2024-07-19 21:57:57

UIImage 包含一个 CGImage 作为其主要内容成员以及缩放和方向因子。 由于 CGImage 及其各种函数源自 OSX,因此与 iPhone 相比,它需要一个颠倒的坐标系。 当您创建 UIImage 时,它默认采用颠倒方向进行补偿(您可以更改此设置!)。 使用 .CGImage 属性可以访问非常强大的 CGImage 函数,但在 iPhone 屏幕等上绘图最好使用 UIImage 方法。

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.

绅士风度i 2024-07-19 21:57:57

用 Swift 代码补充答案

Quartz 2D 图形使用原点位于左下角的坐标系,而 iOS 中的 UIKit 使用原点位于左上角的坐标系。 通常一切都很好,但是在进行一些图形操作时,您必须自己修改坐标系。 文档指出:

某些技术使用不同的方式设置其图形上下文
默认坐标系不同于 Quartz 使用的坐标系。 关系到
Quartz,这样的坐标系是修改后的坐标系并且
进行一些石英绘图时必须进行补偿
运营。 最常见的修改坐标系将
原点位于上下文的左上角并更改 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)
}

Supplemental answer with Swift code

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 documentation states:

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.

This phenomenon can be seen in the following two instances of custom views that draw an image in their drawRect methods.

enter image description here

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)
}
夜巴黎 2024-07-19 21:57:57

发生这种情况是因为 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)

It happens because QuartzCore has the coordinate system "bottom-left", while UIKit – "top-left".

In the case you can extend 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)
豆芽 2024-07-19 21:57:57

我不确定 UIImage,但这种行为通常在翻转坐标时发生。 大多数 OS X 坐标系的原点位于左下角,如 Postscript 和 PDF 中。 但是CGImage坐标系的原点在左上角。

可能的解决方案可能涉及 isFlipped 属性或 scaleYBy:-1 仿射变换。

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.

Possible solutions may involve an isFlipped property or a scaleYBy:-1 affine transform.

噩梦成真你也成魔 2024-07-19 21:57:57

如果有人对在上下文中的自定义矩形中绘制图像的简单解决方案感兴趣:

 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)

}

图像将缩放以填充矩形。

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.

后知后觉 2024-07-19 21:57:57

Swift 3.0 和 4.0

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

无需修改

Swift 3.0 & 4.0

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

No Alteration needed

风铃鹿 2024-07-19 21:57:57

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

drawInRect is certainly the way to go. Here's another little thing that will come in way useful when doing this. Usually the picture and the rectangle into which it is going to go don't conform. In that case drawInRect will stretch the picture. Here's a quick and cool way to make sure that the picture's aspect ration isn't changed, by reversing the transformation (which will be to fit the whole thing 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];
我们只是彼此的过ke 2024-07-19 21:57:57

我们可以使用相同的函数来解决这个问题:

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

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

UIGraphicsPopContext();

UIGraphicsEndImageContext();

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();
彩扇题诗 2024-07-19 21:57:57

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()
}

Swift 3 CoreGraphics Solution

If you want to use CG for whatever your reason might be, instead of UIImage, this Swift 3 construction based on previous answers did solve the issue for 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()
}
天涯离梦残月幽梦 2024-07-19 21:57:57

在我的项目过程中,我从 Kendall 的回答跳到了Cliff 的回答解决了从手机本身加载的图像的问题。

最后我最终使用 CGImageCreateWithPNGDataProvider 相反:

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

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

这不会遇到从 获取 CGImage 时遇到的方向问题UIImage 并且它可以毫无障碍地用作 CALayer 的内容。

During the course of my project I jumped from Kendall's answer to Cliff's answer to solve this problem for images that are loaded from the phone itself.

In the end I ended up using CGImageCreateWithPNGDataProvider instead:

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

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

This doesn't suffer from the orientation issues that you would get from getting the CGImage from a UIImage and it can be used as the contents of a CALayer without a hitch.

热血少△年 2024-07-19 21:57:57
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()
    }
}
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()
    }
}
臻嫒无言 2024-07-19 21:57:57

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)

Swift 5 answer based on @ZpaceZombor's excellent answer

If you have a UIImage, just use

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

If you have a CGImage use my category below

Note: Unlike some other answers, this one takes into account that the rect you want to draw in might have y != 0. Those answers that don't take that into account are incorrect and won't work in the general case.

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)

    }
} 

Use like this:

let imageFrame: CGRect = ...
let context: CGContext = ....
let img: CGImage = ..... 
context.drawImage(image: img, inRect: imageFrame)
彼岸花似海 2024-07-19 21:57:57

您还可以通过执行以下操作来解决此问题:

//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.

You can also solve this problem by doing this:

//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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文