SwiftUI调用相机/相册获取图片后转Base64用于API提交的方法
实现需求
- 点击按钮唤起相机拍照,拍摄完成后自动将图片转换为Base64格式字符串,用于后续向服务端发起POST请求
- 支持从系统相册选取图片,选取后完成相同的Base64转换操作
现有已完成模块
- 遵循
UIViewControllerRepresentable协议封装的ImagePicker图片选择组件 - 实现UIImage与Base64字符串互转逻辑的
ImageConverter工具类 ProfileView个人资料页基础UI结构
缺失功能补全代码
1. 补全ImagePicker组件的选中回调
原有封装缺少图片选择完成后的回调传递,补全后代码如下:
import UIKit import SwiftUI struct ImagePicker: UIViewControllerRepresentable { // 图片来源:相机/系统相册 let sourceType: UIImagePickerController.SourceType // 图片选择完成回调,返回选中的UIImage实例,取消选择返回nil let onImagePicked: (UIImage?) -> Void func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = sourceType picker.allowsEditing = true picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { private let parent: ImagePicker init(parent: ImagePicker) { self.parent = parent } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { // 优先取编辑裁剪后的图片,无编辑内容则取原图 let selectedImage = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage parent.onImagePicked(selectedImage) } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { parent.onImagePicked(nil) } } }
2. 对齐ImageConverter工具类方法
如果你的工具类方法和下面逻辑不一致可以直接替换,支持直接生成接口可用的Base64字符串:
class ImageConverter { static let shared = ImageConverter() private init() {} /// UIImage转Base64字符串 /// - Parameters: /// - image: 待转换图片 /// - compressionQuality: JPEG压缩质量,取值0~1,数值越小压缩率越高、图片体积越小 /// - withPrefix: 是否带data URI前缀,带前缀可直接用于web端img标签展示,纯接口传参可设为false /// - Returns: 转换后的Base64字符串 func convertToBase64(_ image: UIImage, compressionQuality: CGFloat = 0.7, withPrefix: Bool = true) -> String? { guard let imageData = image.jpegData(compressionQuality: compressionQuality) else { return nil } let base64Str = imageData.base64EncodedString() return withPrefix ? "data:image/jpeg;base64,\(base64Str)" : base64Str } /// Base64字符串转UIImage func base64ToImage(_ base64Str: String) -> UIImage? { var pureStr = base64Str if let range = base64Str.range(of: "base64,") { pureStr = String(base64Str[range.upperBound...]) } guard let data = Data(base64Encoded: pureStr) else { return nil } return UIImage(data: data) } }
3. ProfileView中补全选择后自动转码、存储逻辑
在个人资料页中添加状态存储、回调处理、弹出逻辑即可:
struct ProfileView: View { // 存储转换完成的Base64字符串,可直接作为POST请求参数 @State private var avatarBase64Str: String = "" // 控制图片选择器弹出、记录当前选择的来源类型 @State private var showImagePicker = false @State private var pickerSource: UIImagePickerController.SourceType = .camera var body: some View { VStack(spacing: 24) { // 头像预览区域(替换为你原有UI即可) if let previewImg = ImageConverter.shared.base64ToImage(avatarBase64Str) { Image(uiImage: previewImg) .resizable() .scaledToFill() .frame(width: 100, height: 100) .clipShape(Circle()) } else { Circle() .fill(Color.gray.opacity(0.2)) .frame(width: 100, height: 100) } // 操作按钮组 HStack(spacing: 16) { Button("拍照上传") { pickerSource = .camera showImagePicker = true } .buttonStyle(.borderedProminent) Button("相册选择") { pickerSource = .photoLibrary showImagePicker = true } .buttonStyle(.bordered) } } .sheet(isPresented: $showImagePicker) { ImagePicker(sourceType: pickerSource) { selectedImage in // 关闭选择器 showImagePicker = false guard let img = selectedImage else { return } // 自动触发Base64转换并存储 if let base64 = ImageConverter.shared.convertToBase64(img) { avatarBase64Str = base64 // 此处可直接调用上传接口,将avatarBase64Str作为参数传入POST请求即可 } } } } }
注意事项
- 必须在项目Info.plist中添加对应权限描述,否则调用相机/相册会直接崩溃:
- 添加
NSCameraUsageDescription字段,值为应用需要相机权限的说明,比如“用于拍摄个人头像” - 添加
NSPhotoLibraryUsageDescription字段,值为应用需要相册权限的说明,比如“用于选取个人头像”
- 添加
- 如果服务端要求无损图片,可以将转码方法中的
jpegData替换为pngData,对应前缀修改为data:image/png;base64,即可 - 如果转换后的Base64字符串体积过大导致请求慢,可以适当调低
compressionQuality参数值,一般0.5~0.8的压缩质量可以在清晰度和体积间取得较好平衡
内容的提问来源于stack exchange,提问作者Rakha Fatih
相关产品推荐
相关产品推荐

