You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:48:30