Converting a UIImage into a data URI
Asked Answered
G

4

5

Suppose I have a UIImage instance that I would like to convert into a data URI and inject into a UIWebView.

I know I can convert the UIImage to PNG/JPEG NSData using PNGRepresentation/JPEGRepresentation methods. But then how do I make sure that the conversion is base64? And then how do I create a string with the actual URI and headers present?

Gherardi answered 19/6, 2013 at 3:11 Comment(0)
A
1

Creating NSData out of it won't encode in base 64. NSData a binary data (bytes, in the range 0-255); base 64 encoding is a text encoding that uses a subset of ASCII to represent byte values. What you'll want to do is create the NSData, then use a conversion routine to encode it into a base 64 string; there's lots of references for doing that. Once you have the base64 string, use the standard methodology for inserting image data into HTML.

Adjustment answered 19/6, 2013 at 4:32 Comment(0)
G
10

Here is a category on UIImage I use to do just that:

- (BOOL)hasAlpha
{
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
    return (alpha == kCGImageAlphaFirst ||
            alpha == kCGImageAlphaLast ||
            alpha == kCGImageAlphaPremultipliedFirst ||
            alpha == kCGImageAlphaPremultipliedLast);
}

- (NSString *)dataURL
{
    NSData *imageData = nil;
    NSString *mimeType = nil;

    if (self.hasAlpha) {
        imageData = UIImagePNGRepresentation(self);
        mimeType = @"image/png";
    } else {
        imageData = UIImageJPEGRepresentation(self, 1.0);
        mimeType = @"image/jpeg";
    }

    return [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [imageData base64EncodedStringWithOptions:0]];
}

This requires iOS 7 to encode the data as base64, but there are third party libraries to do the same thing.

Globigerina answered 26/8, 2014 at 22:39 Comment(0)
N
2

Here's the Swift 5 version of @David Beck's answer in case if somebody need it:

extension UIImage {

func hasAlpha() -> Bool {
    guard let cgImage = cgImage else {
        return false
    }
    let alpha = cgImage.alphaInfo
    return alpha == .first || alpha == .last || alpha == .premultipliedFirst || alpha == .premultipliedLast
}

func dataURL() -> String? {
    var imageData: Data? = nil
    var mimeType: String? = nil

    if hasAlpha() {
        imageData = self.pngData()
        mimeType = "image/png"
    } else {
        imageData = self.jpegData(compressionQuality: 1.0)
        mimeType = "image/jpeg"
    }

    return "data:\(mimeType ?? "");base64,\(imageData?.base64EncodedString(options: []) ?? "")"
}

}

Nester answered 1/8, 2019 at 14:14 Comment(0)
A
1

Creating NSData out of it won't encode in base 64. NSData a binary data (bytes, in the range 0-255); base 64 encoding is a text encoding that uses a subset of ASCII to represent byte values. What you'll want to do is create the NSData, then use a conversion routine to encode it into a base 64 string; there's lots of references for doing that. Once you have the base64 string, use the standard methodology for inserting image data into HTML.

Adjustment answered 19/6, 2013 at 4:32 Comment(0)
B
1

Here's an adaptation of @David Beck's answer, using Swift 4 / XCode 10.1 / iOS 12:

extension UIImage {
    func hasAlpha() -> Bool {
        let noAlphaCases: [CGImageAlphaInfo] = [.none, .noneSkipLast, .noneSkipFirst]
        if let alphaInfo = cgImage?.alphaInfo {
            return !noAlphaCases.contains(alphaInfo)
        } else {
            return false
        }
    }

    func dataURI() -> String? {
        var mimeType: String = ""
        var imageData: Data
        if hasAlpha(), let png = pngData() {
            imageData = png
            mimeType = "image/png"
        } else if let jpg = jpegData(compressionQuality: 1.0) {
            imageData = jpg
            mimeType = "image/jpeg"
        } else {
            return nil
        }

        return "data:\(mimeType);base64,\(imageData.base64EncodedString())"
    }
}
Birddog answered 25/4, 2019 at 21:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.