【问题标题】:Rotate NSImage in Swift, Cocoa, Mac OSX在 Swift、Cocoa、Mac OSX 中旋转 NSImage
【发布时间】:2015-07-29 11:30:39
【问题描述】:

有没有一种简单的方法可以在 Mac OSX 应用程序中旋转 NSImage?或者只是使用 Swift 将方向从纵向设置为横向?

我正在玩 CATransform3DMakeAffineTransform 但我无法让它工作。

CATransform3DMakeAffineTransform(CGAffineTransformMakeRotation(CGFloat(M_PI) * 90/180))

这是我第一次使用转换。所以请耐心等待我 :) 也许我正在研究错误的方法......

有人可以帮帮我吗?

谢谢!

【问题讨论】:

    标签: swift cocoa image-rotation nsimage affinetransform


    【解决方案1】:
    public extension NSImage {
    public func imageRotatedByDegreess(degrees:CGFloat) -> NSImage {
    
        var imageBounds = NSZeroRect ; imageBounds.size = self.size
        let pathBounds = NSBezierPath(rect: imageBounds)
        var transform = NSAffineTransform()
        transform.rotateByDegrees(degrees)
        pathBounds.transformUsingAffineTransform(transform)
        let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y, pathBounds.bounds.size.width, pathBounds.bounds.size.height )
        let rotatedImage = NSImage(size: rotatedBounds.size)
    
        //Center the image within the rotated bounds
        imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2)
        imageBounds.origin.y  = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
    
        // Start a new transform
        transform = NSAffineTransform()
        // Move coordinate system to the center (since we want to rotate around the center)
        transform.translateXBy(+(NSWidth(rotatedBounds) / 2 ), yBy: +(NSHeight(rotatedBounds) / 2))
        transform.rotateByDegrees(degrees)
        // Move the coordinate system bak to normal 
        transform.translateXBy(-(NSWidth(rotatedBounds) / 2 ), yBy: -(NSHeight(rotatedBounds) / 2))
        // Draw the original image, rotated, into the new image
        rotatedImage.lockFocus()
        transform.concat()
        self.drawInRect(imageBounds, fromRect: NSZeroRect, operation: NSCompositingOperation.CompositeCopy, fraction: 1.0)
        rotatedImage.unlockFocus()
    
        return rotatedImage
    }
    
    
    var image = NSImage(named:"test.png")!.imageRotatedByDegreess(CGFloat(90))  //use only this values 90, 180, or 270
    }
    

    为 Swift 3 更新:

    public extension NSImage {
    public func imageRotatedByDegreess(degrees:CGFloat) -> NSImage {
    
        var imageBounds = NSZeroRect ; imageBounds.size = self.size
        let pathBounds = NSBezierPath(rect: imageBounds)
        var transform = NSAffineTransform()
        transform.rotate(byDegrees: degrees)
        pathBounds.transform(using: transform as AffineTransform)
        let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y, pathBounds.bounds.size.width, pathBounds.bounds.size.height )
        let rotatedImage = NSImage(size: rotatedBounds.size)
    
        //Center the image within the rotated bounds
        imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2)
        imageBounds.origin.y  = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
    
        // Start a new transform
        transform = NSAffineTransform()
        // Move coordinate system to the center (since we want to rotate around the center)
        transform.translateX(by: +(NSWidth(rotatedBounds) / 2 ), yBy: +(NSHeight(rotatedBounds) / 2))
        transform.rotate(byDegrees: degrees)
        // Move the coordinate system bak to normal
        transform.translateX(by: -(NSWidth(rotatedBounds) / 2 ), yBy: -(NSHeight(rotatedBounds) / 2))
        // Draw the original image, rotated, into the new image
        rotatedImage.lockFocus()
        transform.concat()
        self.draw(in: imageBounds, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
        rotatedImage.unlockFocus()
    
        return rotatedImage
        }
    }
    
    class SomeClass: NSViewController {
           var image = NSImage(named:"test.png")!.imageRotatedByDegreess(degrees: CGFloat(90))  //use only this values 90, 180, or 270
    }
    

    【讨论】:

    • 非常感谢。那是完美的:)
    • 不幸的是,它不起作用,因为您没有在任何地方使用转换后的pathBounds(请参阅下面的答案)。
    • 这个解决方案也适用于我,但不幸的是旋转图像质量很差:/
    【解决方案2】:

    感谢这个解决方案,但它对我来说并不完美。 您可能已经注意到 pathBounds 不在任何地方使用。在我看来必须像这样使用:

    let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y , pathBounds.bounds.size.width, pathBounds.bounds.size.height )
    

    否则图像将被旋转但被裁剪为方形边界。

    【讨论】:

    • 您能具体说明您的解决方案是如何使用的吗?这本身不会旋转图像。
    【解决方案3】:

    让 IKImageView 完成繁重的工作:

    import Quartz
    
    extension NSImage {
        func imageRotated(by degrees: CGFloat) -> NSImage {
            let imageRotator = IKImageView()
            var imageRect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
            let cgImage = self.cgImage(forProposedRect: &imageRect, context: nil, hints: nil)
            imageRotator.setImage(cgImage, imageProperties: [:])
            imageRotator.rotationAngle = CGFloat(-(degrees / 180) * CGFloat(M_PI))
            let rotatedCGImage = imageRotator.image().takeUnretainedValue()
            return NSImage(cgImage: rotatedCGImage, size: NSSize.zero)
        }
    }
    

    【讨论】:

    • 知道如何使它与rotateImageLeft / rotateImageRight 一起工作吗?我猜这两个不会做任何真正的旋转,而是更新一些方向标签。
    【解决方案4】:

    这是一个简单的 Swift (4+) 解决方案,用于绘制围绕中心旋转的图像:

    extension NSImage {
        /// Rotates the image by the specified degrees around the center.
        /// Note that if the angle is not a multiple of 90°, parts of the rotated image may be drawn outside the image bounds.
        func rotated(by angle: CGFloat) -> NSImage {
            let img = NSImage(size: self.size, flipped: false, drawingHandler: { (rect) -> Bool in
                let (width, height) = (rect.size.width, rect.size.height)
                let transform = NSAffineTransform()
                transform.translateX(by: width / 2, yBy: height / 2)
                transform.rotate(byDegrees: angle)
                transform.translateX(by: -width / 2, yBy: -height / 2)
                transform.concat()
                self.draw(in: rect)
                return true
            })
            img.isTemplate = self.isTemplate // preserve the underlying image's template setting
            return img
        }
    }
    

    【讨论】:

    • 谢谢,这很好,但只适用于方形图像。矩形的会被裁剪。
    【解决方案5】:

    这也适用于非方形图像,Swift 5。

    extension NSImage {
        func rotated(by degrees : CGFloat) -> NSImage {
            var imageBounds = NSRect(x: 0, y: 0, width: size.width, height: size.height)
            let rotatedSize = AffineTransform(rotationByDegrees: degrees).transform(size)
            let newSize = CGSize(width: abs(rotatedSize.width), height: abs(rotatedSize.height))
            let rotatedImage = NSImage(size: newSize)
    
            imageBounds.origin = CGPoint(x: newSize.width / 2 - imageBounds.width / 2, y: newSize.height / 2 - imageBounds.height / 2)
    
            let otherTransform = NSAffineTransform()
            otherTransform.translateX(by: newSize.width / 2, yBy: newSize.height / 2)
            otherTransform.rotate(byDegrees: degrees)
            otherTransform.translateX(by: -newSize.width / 2, yBy: -newSize.height / 2)
    
            rotatedImage.lockFocus()
            otherTransform.concat()
            draw(in: imageBounds, from: CGRect.zero, operation: NSCompositingOperation.copy, fraction: 1.0)
            rotatedImage.unlockFocus()
    
            return rotatedImage
        }
    }
    

    【讨论】:

    • 不错的代码,但它实际上在一个方向上裁剪,而在另一个方向上正确延伸。问题是 AffineTransform() 旋转。
    【解决方案6】:

    基于@FrankByte.com 的代码,此版本应在任何图像和任何旋转上的 x 和 y 上正确扩展。

    extension NSImage {
        func rotated(by degrees: CGFloat) -> NSImage {
            let sinDegrees = abs(sin(degrees * CGFloat.pi / 180.0))
            let cosDegrees = abs(cos(degrees * CGFloat.pi / 180.0))
            let newSize = CGSize(width: size.height * sinDegrees + size.width * cosDegrees,
                                 height: size.width * sinDegrees + size.height * cosDegrees)
    
            let imageBounds = NSRect(x: (newSize.width - size.width) / 2,
                                     y: (newSize.height - size.height) / 2,
                                     width: size.width, height: size.height)
    
            let otherTransform = NSAffineTransform()
            otherTransform.translateX(by: newSize.width / 2, yBy: newSize.height / 2)
            otherTransform.rotate(byDegrees: degrees)
            otherTransform.translateX(by: -newSize.width / 2, yBy: -newSize.height / 2)
    
            let rotatedImage = NSImage(size: newSize)
            rotatedImage.lockFocus()
            otherTransform.concat()
            draw(in: imageBounds, from: CGRect.zero, operation: NSCompositingOperation.copy, fraction: 1.0)
            rotatedImage.unlockFocus()
    
            return rotatedImage
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多