Image Upload Fails with Error “Invalid Image Data” [closed]

I am developing an iOS app using Swift that requires users to upload profile images to Firebase Storage. Despite the image selection seemingly working fine, I keep encountering the following error during the upload process:

DEBUG: Profile photo is not correctly loaded.

DEBUG: User upload failed with error: The operation couldn’t be completed. (Flixter.ImageUploaderError error 0.)

Additionally, the following warning appears in the logs:

CGImageProviderGetContentHeadroom: Bad headroom value 0.000000 for SDR, returning 1.0

The image is being loaded with the correct dimensions, but the upload still fails with “Invalid image data”. I have implemented resizing of large images to a more manageable size before uploading, but the issue persists.

Steps to Reproduce:

User selects an image from the photo library.
The image is displayed on the profile setup screen.
Upon confirming the selection, the app attempts to upload the image to Firebase Storage.
The upload fails with the mentioned error.
Relevant Code:

ImagePicker.swift
This file ensures that the image is correctly selected from the user’s photo library.

import SwiftUI
import PhotosUI

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?

    func makeUIViewController(context: Context) -> PHPickerViewController {
        var config = PHPickerConfiguration()
        config.filter = .images
        let picker = PHPickerViewController(configuration: config)
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        let parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)

            guard let provider = results.first?.itemProvider else {
                print("DEBUG: No provider found.")
                return
            }

            if provider.canLoadObject(ofClass: UIImage.self) {
                provider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                    if let error = error {
                        print("DEBUG: Failed to load image with error: (error.localizedDescription)")
                        return
                    }
                    guard let self = self, let uiImage = image as? UIImage else {
                        print("DEBUG: Failed to cast image to UIImage.")
                        return
                    }
                    DispatchQueue.main.async {
                        print("DEBUG: Image loaded with size: (uiImage.size)")
                        self.parent.image = uiImage
                    }
                }
            } else {
                print("DEBUG: Provider cannot load UIImage.")
            }
        }
    }
}

SelectProfileImageView.swift
Ensures the selected image is passed correctly to the OnboardingManager for uploading.

import SwiftUI

struct SelectProfileImageView: View {
    @EnvironmentObject var manager: OnboardingManager
    @State private var showImagePicker = false
    @State private var inputImage: UIImage?

    var body: some View {
        GeometryReader { geometry in
            VStack {
                VStack(alignment: .center, spacing: 15) {
                    Text("PROFILE IMAGE")
                        .font(.custom("samble", size: 34))
                        .padding(.top)
                    Text("Please select a profile image to continue.")
                        .font(.custom("samble", size: 26))
                        .foregroundStyle(ColorUtils.darkPurple)
                }
                .padding(.horizontal)

                Spacer()

                ProfileImageButton(profileImage: $inputImage, showImagePicker: $showImagePicker, geometry: geometry)

                Spacer()

                Button(action: {
                    if let newImage = inputImage {
                        print("DEBUG: New image selected with size: (newImage.size)")
                        manager.profilePhoto = newImage
                        Task {
                            do {
                                let imageUrl = try await manager.service.uploadUserPhoto(newImage)
                                DispatchQueue.main.async {
                                    manager.profileImageURL = imageUrl
                                    print("DEBUG: Image URL: (imageUrl)")
                                    manager.navigate() // Proceed to the next step or complete onboarding
                                }
                            } catch {
                                print("DEBUG: Failed to upload photo with error: (error.localizedDescription)")
                            }
                        }
                    } else {
                        print("DEBUG: No image selected.")
                    }
                }) {
                    NextButton(formIsValid: formIsValid)
                }
                .padding()
            }
            .background(Image(.backgroundAuthView).resizable().edgesIgnoringSafeArea(.all))
        }
        .sheet(isPresented: $showImagePicker) {
            ImagePicker(image: $inputImage)
        }
        .toolbar {
            ToolbarItem(placement: .topBarLeading) {
                BackButton()
            }
        }
    }
}

extension SelectProfileImageView: FormValidatorProtocol {
    var formIsValid: Bool {
        return inputImage != nil
    }
}

#Preview {
    SelectProfileImageView()
}

ImageUploader.swift
Handles the image conversion and upload to Firebase Storage.

import UIKit
import FirebaseStorage

enum ImageUploaderError: Error {
    case invalidData
    case uploadFailed
}

struct ImageUploader {
    // Resize the image to a more manageable size
    private func resizeImage(_ image: UIImage, targetSize: CGSize) -> UIImage {
        let size = image.size

        let widthRatio  = targetSize.width  / size.width
        let heightRatio = targetSize.height / size.height

        // Figure out what our orientation is, and use that to form the rectangle
        var newSize: CGSize
        if(widthRatio > heightRatio) {
            newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
        } else {
            newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
        }

        // This is the rect that we've calculated out and this is what is actually used below
        let rect = CGRect(origin: .zero, size: newSize)

        // Actually do the resizing to the rect using the ImageContext stuff
        UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
        image.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage ?? image
    }

    func uploadImage(_ image: UIImage) async throws -> String {
        print("DEBUG: Original image dimensions - width: (image.size.width), height: (image.size.height)")

        // Resize image if it's too large
        let resizedImage = resizeImage(image, targetSize: CGSize(width: 1024, height: 1024))
        print("DEBUG: Resized image dimensions - width: (resizedImage.size.width), height: (resizedImage.size.height)")

        // Check for both JPEG and PNG data
        guard let imageData = resizedImage.jpegData(compressionQuality: 0.4) ?? resizedImage.pngData() else {
            print("DEBUG: Invalid image data.")
            throw ImageUploaderError.invalidData
        }
        
        let filename = UUID().uuidString + ".jpg"
        let ref = Storage.storage().reference(withPath: "/profile_images/(filename)")

        do {
            print("DEBUG: Uploading image data...")
            let _ = try await ref.putDataAsync(imageData)
            let url = try await ref.downloadURL()
            print("DEBUG: Image uploaded successfully. URL: (url.absoluteString)")
            return url.absoluteString
        } catch {
            print("DEBUG: Image upload failed with error: (error.localizedDescription)")
            throw ImageUploaderError.uploadFailed
        }
    }
}
OnboardingManager.swift
Handles the process of navigating through the onboarding steps and uploading user data.


import Foundation
import SwiftUI
import FirebaseAuth

class OnboardingManager: ObservableObject {
    @Published var navigationPath = [OnboardingSteps]()
    @Published var fullname: String = ""
    @Published var age: Int = 0
    @Published var profilePhoto = UIImage()
    @Published var profileImageURL: String = ""
    @Published var school: String? = nil
    @Published var likedEvents: [Event] = []
    @Published var pendingEvents: [Event] = []
    @Published var email: String = ""
    @Published var birthday: Date = Date()
    @Published var zodiacSign: String? = nil
    @Published var zodiacDescription: String? = nil
    @Published var currentUser: User?
    
    let service: OnboardingService
    
    init(service: OnboardingService) {
        self.service = service
    }

    private var currentStep: OnboardingSteps?

    func start() {
        DispatchQueue.main.async {
            guard let initialStep = OnboardingSteps(rawValue: 0) else { return }
            self.navigationPath.append(initialStep)
        }
    }

    func navigate() {
        self.currentStep = self.navigationPath.last

        guard let index = self.currentStep?.rawValue else { return }
        guard let nextStep = OnboardingSteps(rawValue: index + 1) else {
            Task { await uploadUserData() }
            return
        }

        self.navigationPath.append(nextStep)
    }
    
    func uploadUserData() async {
        do {
            guard let id = Auth.auth().currentUser?.uid,
                  let email = Auth.auth().currentUser?.email else { return }
            
            let ageComponents = Calendar.current.dateComponents([.year], from: birthday, to: Date())
            guard let age = ageComponents.year else { return }
            
            // Check if the profilePhoto is correctly loaded
            if profilePhoto.size.width == 0 || profilePhoto.size.height == 0 {
                print("DEBUG: Profile photo is not correctly loaded.")
                throw ImageUploaderError.invalidData
            }
            
            // Upload the profile photo and get the URL
            print("DEBUG: Uploading user photo...")
            let profileImageURL = try await service.uploadUserPhoto(profilePhoto)
            
            let user = User(
                id: id,
                fullname: fullname,
                age: age,
                profileImageURL: profileImageURL,
                school: school ?? "",
                email: email
            )
            
            // Upload the user data
            print("DEBUG: Uploading user data...")
            self.currentUser = try await service.uploadUserData(user, photo: profilePhoto)
            
            DispatchQueue.main.async {
                // Navigate to MainTabView
                if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                    if let window = windowScene.windows.first {
                        window.rootViewController = UIHostingController(rootView: MainTabView())
                        window.makeKeyAndVisible()
                    }
                }
            }
        } catch {
            print("DEBUG: User upload failed with error: (error.localizedDescription)")
        }
    }
}

Question:

What could be causing the Invalid image data error, and how can I fix the issue to successfully upload the selected image to Firebase Storage? Any insights or suggestions on handling large image uploads in Swift would be greatly appreciated.

Recognized by Google Cloud Collective

New contributor

Alkis Toutziaridis is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật