保存照片从相机(不是从图书馆)到服务器



我有一个关于如何保存刚刚拍摄的照片到服务器的问题。

我已经用相机创建了一个视图(你可以打开它并拍照并保存到你的相机卷)和第二个视图(你可以从相机卷上传到服务器的图像)

但是我怎样才能把它们连接起来呢?

我的代码从图库中选择照片:

PictureView

import SwiftUI
struct PictureView: View {

// show image picker
@State var showImagePicker: Bool = false

// show selected image
@State var selectedImage: Image? = Image("")

var body: some View {
VStack {
// create button to select image
Button(action: {
self.showImagePicker.toggle()
}, label: {
Text("Select image")
})

// show image
self.selectedImage?.resizable().scaledToFit()

// show button to upload image
Button(action: {
// convert image into base 64

let uiImage: UIImage = self.selectedImage.asUIImage()
let imageData: Data = uiImage.jpegData(compressionQuality: 0.1) ?? Data()
let imageStr: String = imageData.base64EncodedString()

// send request to server
guard let url: URL = URL(string:
"gs://lalala-af09c.appspot.com/swiftui-save-image.php") else {
print("invalid URL")
return
}

// create parameters
let paramStr: String = "image=(imageStr)"
let paramData: Data = paramStr.data(using: .utf8) ?? Data()

var urlRequest: URLRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = paramData

// required for sending large data
urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

// send the request
URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
guard let data = data else {
print("invalid data")
return
}

// show response in string
let responseStr: String = String(data: data, encoding: .utf8) ?? ""
print(responseStr)
})
.resume()

}, label: {
Text("Upload image")
})
}
.sheet(isPresented: $showImagePicker, content: {
ImagePicker(image: self.$selectedImage)
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
PictureView()
}
}

image picker

import Foundation
import SwiftUI
extension View {
public func asUIImage() -> UIImage {
let controller = UIHostingController(rootView: self)

controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)

let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
controller.view.bounds = CGRect(origin: .zero, size: size)
controller.view.sizeToFit()

// here is the call to the function that converts UIView to UIImage: `.asImage()`
let image = controller.view.asUIImage()
controller.view.removeFromSuperview()
return image
}
}
extension UIView {
// This is the function to convert UIView to UIImage
public func asUIImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
struct ImagePicker: UIViewControllerRepresentable {
@Environment(.presentationMode)
var presentationMode
@Binding var image: Image?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@Binding var presentationMode: PresentationMode
@Binding var image: Image?
init(presentationMode: Binding<PresentationMode>, image: Binding<Image?>) {
_presentationMode = presentationMode
_image = image
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
image = Image(uiImage: uiImage)
presentationMode.dismiss()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
presentationMode.dismiss()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentationMode: presentationMode, image: $image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}

且打开摄像头的解决方案为:CameraView

import SwiftUI
import AVFoundation
struct CameraView: View {
@StateObject var camera = CameraModel()
var body: some View {
ZStack{
//    Color.black
CameraPreview(camera: camera)
.ignoresSafeArea()
VStack{

if camera.isTaken{
HStack{
Spacer()
Button(action: camera.reTake, label: {
Image(systemName: "arrow.triangle.2.circlepath.camera")
.foregroundColor(.black)
.padding()
.background(Color.white)
.clipShape(Circle())

}).padding(.trailing,10)
}
Spacer()
}
Spacer()
HStack{
if camera.isTaken{
Button(action: {
if !camera.isSaved{
camera.savePic()
}
}, label: {
Text(camera.isSaved ? "Saved" : "Save")
.foregroundColor(.black)
.fontWeight(.semibold)
.padding(.vertical,10)
.padding(.horizontal,20)
.background(Color.white)
.clipShape(Capsule())
}).padding(.leading)
Spacer()

}else{
Button(action: camera.takePic, label: {
ZStack{
Circle()
.fill(Color.white)
.frame(width: 65, height: 65, alignment: .center)
Circle()
.stroke(Color.white,lineWidth: 2)
.frame(width: 75, height: 75, alignment: .center)
}
})
}
}.frame(height: 75)
}
}.onAppear(perform: {
camera.check()
}).alert(isPresented: $camera.alert){
Alert(title: Text("Enable camera"))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
CameraView()
}
}

class CameraModel : NSObject, ObservableObject, AVCapturePhotoCaptureDelegate{
@Published var isTaken = false
@Published var session = AVCaptureSession()
@Published var alert = false
@Published var output = AVCapturePhotoOutput()

@Published var preview : AVCaptureVideoPreviewLayer!

@Published var isSaved=false
@Published var picData = Data(count:0)
func check(){

switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
setUp()
return
case .notDetermined :
AVCaptureDevice.requestAccess(for: .video) { (status) in
if status{
self.setUp()
}
}
case .denied:
self.alert.toggle()
return

default:
return
}
}

func setUp(){
do{
self.session.beginConfiguration()

guard let device: AVCaptureDevice = AVCaptureDevice.default(.builtInWideAngleCamera,
for: .video, position: .back) else {
return
}
let input = try AVCaptureDeviceInput(device: device)
if self.session.canAddInput(input){
print("input taken")
self.session.addInput(input)
}else{
print("input not  taken")
}
if self.session.canAddOutput(output){
print("output taken")
self.session.addOutput(output)
}
self.session.commitConfiguration()
}catch{
print(error.localizedDescription)
}
}

func takePic(){
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
DispatchQueue.global(qos: .background).async {
self.session.stopRunning()
DispatchQueue.main.async {
withAnimation{
self.isTaken.toggle()

}
}
}
}

func reTake(){

DispatchQueue.global(qos: .background).async {
self.session.startRunning()
DispatchQueue.main.async {
withAnimation{
self.isTaken.toggle()

}
self.isSaved=false
self.picData=Data(count: 0)

}
}
}

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error != nil{
return
}
print("picture taken")
guard let imageData = photo.fileDataRepresentation() else {
return
}
self.picData = imageData
}

func savePic(){
guard let image = UIImage(data: self.picData) else{return}
//saving image
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
self.isSaved=true
print("pic saved")
}

}
struct CameraPreview : UIViewRepresentable{
@ObservedObject var camera : CameraModel
func makeUIView(context:Context) -> UIView {
let view = UIView(frame:UIScreen.main.bounds)
camera .preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
self.camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIView, context: Context) {

}
}

Thank you very much

上传图片…

  1. get image from Camera

  2. 接受图像的Api

  3. 使用URLSession上传图片到服务器

    3.1使用Alamofire上传图片,这是一种更简单的上传方式图片

最新更新