Search code examples
iosswift3bmp

How to convert UIImage to BMP and save as Data (not JPG or PNG)


I am syncing BMP images between my iOS app (Swift 3) and an app (on MS Windows) that supports only BMP format.

BMP images created on the MS Windows app are downloaded as base64 strings, saved as Data and displayed quite easily using some lines of code like:

let imageData = Data(base64Encoded: value)
let image = UIImage(data: imageData)

This is generating a UIImage from downloaded BMP image and works perfectly because I cas display the image.

But I also need to create BMP images (drawn signatures) from the iOS app and for that, I'm using this library https://github.com/felipesantolim/SHFSignature, thanks to Felipe.

This library generates a UIImage which I save as Data and I can display it on my iOS app.

But when I send it as base64 string the problem is that se MS Windows app can't display it (format not supported, only BMP image).

Can anybody help me generate a real BMP image from a UIImage or directly from the SHFSignature image function?

Thanks


Solution

  • I needed to do the same thing - take a UIImage from iOS and save it out into a usable Windows .bmp file. I actually used it on an Adafruit PyPortal IoT device, not a Windows machine, but the technique below worked fine. Saved the data to Firebase Storage and was able to use it in the PyPortal.

    I found a helpful extension here: Convert UIImage to NSData and convert back to UIImage in Swift?

    I used this extension: // Note you'll need to import MobileCoreServices for the k values to be recognized

    import MobileCoreServices
    
    extension UIImage {
    
        func toJpegData (compressionQuality: CGFloat, hasAlpha: Bool = true, orientation: Int = 6) -> Data? {
            guard cgImage != nil else { return nil }
            let options: NSDictionary =     [
                kCGImagePropertyOrientation: orientation,
                kCGImagePropertyHasAlpha: hasAlpha,
                kCGImageDestinationLossyCompressionQuality: compressionQuality
            ]
            return toData(options: options, type: .jpeg)
        }
    
        func toData (options: NSDictionary, type: ImageType) -> Data? {
            guard cgImage != nil else { return nil }
            return toData(options: options, type: type.value)
        }
    
        // about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage
        func toData (options: NSDictionary, type: CFString) -> Data? {
            guard let cgImage = cgImage else { return nil }
            return autoreleasepool { () -> Data? in
                let data = NSMutableData()
                guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil }
                CGImageDestinationAddImage(imageDestination, cgImage, options)
                CGImageDestinationFinalize(imageDestination)
                return data as Data
            }
        }
    
        // https://developer.apple.com/documentation/mobilecoreservices/uttype/uti_image_content_types
        enum ImageType {
            case image // abstract image data
            case jpeg                       // JPEG image
            case jpeg2000                   // JPEG-2000 image
            case tiff                       // TIFF image
            case pict                       // Quickdraw PICT format
            case gif                        // GIF image
            case png                        // PNG image
            case quickTimeImage             // QuickTime image format (OSType 'qtif')
            case appleICNS                  // Apple icon data
            case bmp                        // Windows bitmap
            case ico                        // Windows icon data
            case rawImage                   // base type for raw image data (.raw)
            case scalableVectorGraphics     // SVG image
            case livePhoto                  // Live Photo
    
            var value: CFString {
                switch self {
                case .image: return kUTTypeImage
                case .jpeg: return kUTTypeJPEG
                case .jpeg2000: return kUTTypeJPEG2000
                case .tiff: return kUTTypeTIFF
                case .pict: return kUTTypePICT
                case .gif: return kUTTypeGIF
                case .png: return kUTTypePNG
                case .quickTimeImage: return kUTTypeQuickTimeImage
                case .appleICNS: return kUTTypeAppleICNS
                case .bmp: return kUTTypeBMP
                case .ico: return kUTTypeICO
                case .rawImage: return kUTTypeRawImage
                case .scalableVectorGraphics: return kUTTypeScalableVectorGraphics
                case .livePhoto: return kUTTypeLivePhoto
                }
            }
        }
    }
    

    And I called it in my code like this:

    (the image I was converting was a UIImage value named backgroundImage that is a property of the class where the code below resides).

    let options: NSDictionary =     [:]
    let convertToBmp = self.backgroundImage.toData(options: options, type: .bmp)
    guard let bmpData = convertToBmp else {
        print("😡 ERROR: could not convert image to a bitmap bmpData var.")
        return
    }
    

    Cheers!