Search code examples
iosswiftswiftuiuikit

How to convert the image to base64 after take a photo from camera or library


I want to make a button that when pressed will take a photo, after I take a photo I can directly convert the photo to base64 and will be used to post to the API

This is my code :)

import SwiftUI
import UIKit


struct ImagePicker: UIViewControllerRepresentable {
    
    @Binding var selectedImage: UIImage
    @Environment(\.presentationMode) private var presentationMode
    var sourceType: UIImagePickerController.SourceType = .photoLibrary
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        
        let imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = false
        imagePicker.sourceType = sourceType
        imagePicker.delegate = context.coordinator
        
        return imagePicker
        
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
        //leave alone for right now
    }
    
    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
     
        var parent: ImagePicker
     
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
    
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
     
            if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
                parent.selectedImage = image
                
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
}

class ImageConverter {

    func base64ToImage(_ base64String: String) -> UIImage? {
        guard let imageData = Data(base64Encoded: base64String) else { return nil }
        return UIImage(data: imageData)
    }

    func imageToBase64(_ image: UIImage) -> String? {
        return image.jpegData(compressionQuality: 1)?.base64EncodedString()
    }

}

This is some of my view, I want when I press the button it will direct me to the camera and when I take a photo it will convert it to base64 and save it in a string.

import SwiftUI

struct ProfileView: View {
    let imageManager = ImageConverter()
    
    @State var changeProfileImage = false
    @State var openCameraRoll = false
    @State var imageSelected = UIImage()
    
    var body: some View {
        ZStack(alignment: .bottomTrailing) {
            Button(action: {
                changeProfileImage = true
                openCameraRoll = true
                
            }, label: {
                if changeProfileImage {
                    Image(uiImage: imageSelected)
                        .profileImageMod()
                } else {
                    Image("AddProfileImage")
                        .profileImageMod()
                }
        })
            
            Image(systemName: "plus")
                .frame(width: 30, height: 30)
                .foregroundColor(.white)
                .background(Color.gray)
                .clipShape(Circle())
            
        }.sheet(isPresented: $openCameraRoll) {
            ImagePicker(selectedImage: $imageSelected, sourceType: .camera)
            
        }.onAppear {
            
        }
    }
}

UPDATE this is my Imagepicker

import SwiftUI
import UIKit


struct ImagePicker: UIViewControllerRepresentable {
    
    @Binding var selectedImage: UIImage
    @Environment(\.presentationMode) private var presentationMode
    var sourceType: UIImagePickerController.SourceType = .photoLibrary
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        
        let imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = false
        imagePicker.sourceType = sourceType
        imagePicker.delegate = context.coordinator
        
        return imagePicker
        
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
        //leave alone for right now
    }
    
    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
     
        var parent: ImagePicker
     
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
    
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
     
            if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
                parent.selectedImage = image
                
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
}

class ImageConverter {

    func base64ToImage(_ base64String: String) -> UIImage? {
        guard let imageData = Data(base64Encoded: base64String) else { return nil }
        return UIImage(data: imageData)
    }

    func imageToBase64(_ image: UIImage) -> String? {
        return image.jpegData(compressionQuality: 1)?.base64EncodedString()
    }

}

Solution

  • you could use something like this approach, using the .onDismiss() to then convert your imageSelected to base64 string using your ImageConverter.

    In ProfileView,

     .sheet(isPresented: $openCameraRoll, onDismiss: didDismiss) {
        ImagePicker(selectedImage: $imageSelected, sourceType: .camera)
     }
     
     func didDismiss() {
         let b64Str = imageManager.imageToBase64(imageSelected)
         print("\n---> b64Str: \(b64Str?.count) \n")
     }
    

    Also remove the ZStack, or replace it by a VStack

    EDIT-1: here some example code that works for me:

    struct ProfileView: View {
        let imageManager = ImageConverter()
        
        @State var changeProfileImage = false
        @State var openCameraRoll = false
        @State var imageSelected = UIImage()
        
        var body: some View {
            VStack {
                Button(action: {
                    openCameraRoll = true
                }, label: {
                    Image(systemName: "plus")
                    //  .profileImageMod()
                })
                if changeProfileImage {
                    Image(uiImage: imageSelected)
                        .resizable() // <-- here
                        .frame(width: 222, height: 222)
                        .foregroundColor(.white)
                        .background(Color.gray)
                        .clipShape(Circle())
                } else {
                    Image(systemName: "questionmark")
                        .frame(width: 222, height: 222)
                        .foregroundColor(.white)
                        .background(Color.gray)
                        .clipShape(Circle())
                }
            }
            .sheet(isPresented: $openCameraRoll, onDismiss: didDismiss) {
                ImagePicker(selectedImage: $imageSelected, sourceType: .camera)
            }
        }
        
        func didDismiss() {
            changeProfileImage = true
            let b64Str = imageManager.imageToBase64(imageSelected)
            print("\n---> b64Str: \(b64Str?.count) \n")
        }
    }