programing

CG ContextDrawImage는 UIImage를 통과할 때 이미지를 거꾸로 그립니다.CGI 이미지

telecom 2023. 6. 9. 21:46
반응형

CG ContextDrawImage는 UIImage를 통과할 때 이미지를 거꾸로 그립니다.CGI 이미지

그런지 ?CGContextDrawImage제 이미지를 거꾸로 그리는 건가요?응용 프로그램에서 이미지를 로드하는 중입니다.

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

그런 다음 핵심 그래픽을 사용하여 이를 제 맥락으로 끌어냅니다.

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

올바른 위치와 치수로 렌더링되지만 이미지는 거꾸로 되어 있습니다.제가 여기서 정말 명백한 것을 놓쳤나 봐요?

대신에

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

사용하다

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

의 시작에 작끝중/에간시중.CGcontext방법들.

이렇게 하면 올바른 방향의 이미지가 현재 이미지 컨텍스트로 그려집니다. 이것이 이미지 컨텍스트와 관련이 있다고 확신합니다.UIImage에 대한 하고 때CGContextDrawImagemethod는 방향을 이해하지 않고 기본 원시 이미지 데이터를 가져옵니다.

제가 언급한 모든 것을 적용한 후에도, 저는 여전히 이미지가 있는 드라마를 가지고 있습니다.마지막으로, 저는 김프를 사용하여 제 모든 이미지의 '플립된 수직' 버전을 만들었습니다.이제 Transforms를 사용할 필요가 없습니다.바라건대 이것이 더 이상의 문제를 일으키지 않기를 바랍니다.

CG ContextDrawImage가 왜 내 이미지를 거꾸로 그리는지 아는 사람?응용 프로그램에서 이미지를 로드하는 중입니다.

Quartz2d는 원점이 왼쪽 하단 모서리에 있는 다른 좌표계를 사용합니다.Quartz가 100 * 100 이미지의 픽셀 x[5], y[10]을 그릴 때 해당 픽셀은 왼쪽 상단이 아닌 왼쪽 하단 모서리에 그려집니다.따라서 '뒤집힌' 이미지가 발생합니다.

x 좌표 시스템이 일치하므로 좌표를 뒤집어야 합니다.

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

즉, X축에서는 영상을 0 단위, Y축에서는 영상 높이로 변환했습니다.그러나 이것만으로도 우리의 이미지는 우리가 원하는 곳 아래에 "image.size.height"로 그려지며 여전히 뒤집혀 있다는 것을 의미합니다.

Quartz 2D 프로그래밍 가이드에서는 Scale을 사용할 것을 권장합니다.CTM 및 음의 값을 전달하여 영상을 플립합니다.다음 코드를 사용하여 이 작업을 수행할 수 있습니다.

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

의도하지 않은 결과를 얻을 수 있으므로 이미지의 Rect 좌표가 이미지의 Rect 좌표와 일치하지 않을 경우에만 주의하십시오.

좌표를 다시 변환하려면:

CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageRect.size.height);

모두의 UIImage를 하십시오.drawAtPoint:또는drawInRect:사용자 지정 컨텍스트를 지정하는 동안:

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

또한 당신은 당신의 문맥을 수정하는 것을 피합니다.CGContextTranslateCTM또는CGContextScaleCTM두 번째 대답이 하는 것입니다.

관련 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을 뒤집을 필요가 없습니다.그러나 코어 그래픽 또는 이미지 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);

컨텍스트에서 사용자 정의 직사각형으로 이미지를 그리기 위한 간단한 솔루션에 관심이 있는 사용자는 다음을 수행할 수:

 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)

}

이미지가 눈금 조정되어 직사각형을 채웁니다.

이미지 정류에서 0이 아닌 원점을 올바르게 처리하는 Swift 5 순수 코어 그래픽 확장을 사용합니다.

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)

잘 모르겠어요.UIImage하지만 이런 행동은 보통 좌표가 뒤집힐 때 발생합니다.대부분의 OS X 좌표계는 Postscript 및 PDF에서와 같이 왼쪽 하단 모서리에 원점이 있습니다.그렇지만CGImage좌표계는 왼쪽 상단 모서리에 원점이 있습니다.

가능한 해결책에는 다음이 포함될 수 있습니다.isFlipped 또는 scaleYBy:-1아핀 변환

쿼츠 코어는 "좌측 하단" 좌표계를 가지고 있고 UIKit은 "좌측 상단" 좌표계를 가지고 있기 때문에 발생합니다.

CGC Context를 확장할 수 있는 경우:

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)

UIImage을 합니다.CGImage확장 및 방향 요인뿐만 아니라 주요 컨텐츠 멤버로 사용할 수 있습니다. 때부터CGImage그리고 그것의 다양한 기능들은 OSX에서 파생되어 아이폰에 비해 거꾸로 된 좌표계를 기대합니다.를 할 때UIImage보정하기 위해 기본적으로 거꾸로 된 방향으로 설정됩니다(변경할 수 있습니다!).를 사용합니다.CGImage 강력한 매우강사에게접수근재있산는할에 수 있는 CGImage기능, 하지만 아이폰 화면 등에 그리는 것이 가장 좋습니다.UIImage방법들.

Swift 코드를 사용한 보충 답변

쿼츠 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)
}

스위프트 3.0 & 4.0

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

변경할 필요 없음

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

동일한 기능을 사용하여 이 문제를 해결할 수 있습니다.

UIGraphicsBeginImageContext(image.size);

UIGraphicsPushContext(context);

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

UIGraphicsPopContext();

UIGraphicsEndImageContext();

Swift 3 코어 그래픽 솔루션

이유가 무엇이든 간에 당신이 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()
}

제 프로젝트가 진행되는 동안 저는 전화기 자체에서 로드되는 이미지에 대해 이 문제를 해결하기 위해 클리프답변에 대한 켄달의 답변에서 뛰어내렸습니다.

결국 저는 대신 다음을 사용하게 되었습니다.

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

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

이것은 당신이 그것을 얻음으로써 얻을 수 있는 오리엔테이션 문제로 고통받지 않습니다.CGImage에서.UIImage그리고 그것은 의 내용으로 사용될 수 있습니다.CALayer순순히

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

@ZpaceZombor의 뛰어난 답변을 바탕으로 한 스위프트 5 답변

UI 이미지가 있는 경우에는

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

CGI 이미지가 있는 경우 아래 범주를 사용합니다.

참고: 일부 다른 답변과 달리, 이 답변은 그릴 정류장에 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)

다음과 같은 방법으로 이 문제를 해결할 수도 있습니다.

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

언급URL : https://stackoverflow.com/questions/506622/cgcontextdrawimage-draws-image-upside-down-when-passed-uiimage-cgimage

반응형