• Xcode11.3
  • Swift 5
  • iOS12と13でテストした
  • jpegの再エンコードが発生しないので、各ピクセルの値は変化しない
import Foundation  
import ImageIO.CGImageDestination  
import ImageIO.CGImageProperties  
import ImageIO.CGImageSource  
import MobileCoreServices.UTCoreTypes  
import UIKit.UIImage  

public extension NSData {  
    @objc(jpegDataByApplyingImageOrientation:)  
    func jpegDataByApplying(_ imageOrientation: UIImage.Orientation) -> NSData? {  
        return (self as Data).jpegDataByApplying(imageOrientation) as NSData?  
    }  
}  

public extension Data {  
    func jpegDataByApplying(_ imageOrientation: UIImage.Orientation) -> Data? {  
        let sourceOptions: [String: Any] = [kCGImageSourceTypeIdentifierHint as String: kUTTypeJPEG as String,  
                                            kCGImageSourceShouldCache as String: kCFBooleanFalse!]  
        guard let source = CGImageSourceCreateWithData(self as CFData,  
                                                       sourceOptions as CFDictionary) else {  
            return nil  
        }  
        return source.jpegDataByApplying(imageOrientation.cgImagePropertyOrientation)  
    }  
}  

extension CGImageSource {  
    func jpegDataByApplying(_ orientation: CGImagePropertyOrientation) -> Data? {  
        guard let cfData = CFDataCreateMutable(nil, 0),  
            let dest = CGImageDestinationCreateWithData(cfData, kUTTypeJPEG, 1, nil) else {  
            return nil  
        }  
        let copyOptions: [String: Any] = [kCGImageDestinationOrientation as String: NSNumber(value: orientation.rawValue)]  
        guard CGImageDestinationCopyImageSource(dest,  
                                                self,  
                                                copyOptions as CFDictionary,  
                                                nil) else {  
            return nil  
        }  
        return cfData as Data  
    }  
}  

extension UIImage.Orientation {  
    var cgImagePropertyOrientation: CGImagePropertyOrientation {  
        switch self {  
        case .up:  
            return .up  
        case .down:  
            return .down  
        case .left:  
            return .left  
        case .right:  
            return .right  
        case .upMirrored:  
            return .upMirrored  
        case .downMirrored:  
            return .downMirrored  
        case .leftMirrored:  
            return .leftMirrored  
        case .rightMirrored:  
            return .rightMirrored  
        @unknown default:  
            fatalError()  
        }  
    }  
}