将JSON 64位字符串转换为图像-困难

iszxjhcz  于 2023-02-14  发布在  其他
关注(0)|答案(2)|浏览(168)

我的项目访问一个包含200多个country元素的JSON文件,其中一个名称/值对是flag:包含我认为是Base64加密的内容-示例如下。我已成功包含名称:和:标志。Picker工作正常,显示所选国家/地区,并使用这两个标志更新CoreData & CloudKit(ClientEntity)记录。挑战是调用记录进行显示或编辑。我无法显示标志Image-只有默认值。它在clientFlag字段中存储了一些内容。我希望它存储标志:1920字节的JSON数据-相反(从控制台复制),它存储的是"CD_clientFlag"="{length = 1458,sha256 = c1572719d906e1df50fdf296845b0942ef148060c609d58543477b6276a67e9}";\n
很明显,我的逻辑有问题,或者这个字段包含了不同的数据格式,或者两者都有。任何帮助都将受到欢迎。当然,更好的方法是通过id引用JSON数据:或名称:,但由于缺乏经验,我放弃了这一点,并选择存储这两个名称:并标记
相关代码如下:

    • 视图中成功的选取器代码**
NavigationStack {
            Form {
                VStack(alignment: .leading) {
                    clientNameAddress
                    Group {
                                Picker(selection: $selectedCountry,
                                       label: Text("")) {
                                    ForEach(countryVM.countries) { country in
                                        HStack {
                                            Text(country.name)
                                            if let flagImage = country.flagImage {
                                                Image(uiImage: flagImage)
                                            } else {
                                                Image(systemName: "questionmark")
                                            }
                                        }.tag(country as Country?)//: HSTACK6
                                    }
                                }
                                       .padding(.horizontal, 10)
                                       .pickerStyle(MenuPickerStyle())
                        VStack {
                            Text("Selected Country: \(selectedCountry?.name ?? "No Name")")
                                .foregroundColor(.secondary)
                            if let flagImage = selectedCountry?.flagImage {
                                Image(uiImage: flagImage)
                            }
                        }.padding(.horizontal, 10)
                        }
                    Toggle("Existing Client?", isOn: $clientVM.clientExisting)
                        .toggleStyle(.switch)
                        .foregroundColor(.blue)
                        .padding(.horizontal, 10)
//                    SelectContact()
                    Button(action: {
                        assignFlag()
                        print("AddView \(clientVM.clientHostCountry)")
                        clientVM.addClient(context: viewContext)
                        dismiss()
                    }, label: {
                        if clientVM.clientItem == nil {
                            Text("Add Account")
                                .frame(minWidth: 0, maxWidth: 200)
                        } else {
                            Text("Save Modified Client")
                                .frame(minWidth: 0, maxWidth: 200)
                        }
                    })
                    .tint(.purple)
                    .buttonStyle(.bordered)
                    .buttonBorderShape(.roundedRectangle)
                }
                .navigationTitle(clientVM.clientItem == nil ? "Add Account" : "Edit Account \(clientVM.clientName)")
            }.disableAutocorrection(true)
            #if os(iOS)
                .navigationBarTitle("Add Account")
                .navigationBarTitleDisplayMode(.inline)
            #endif
        }
    • JSON示例**
{
    "id": 2,
    "name": "Albania",
    "isoAlpha2": "AL",
    "isoAlpha3": "ALB",
    "isoNumeric": 8,
    "currency": {
        "code": "ALL",
        "name": "Lek",
        "symbol": "Lek"
    },
    "flag": "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAIAAAAVyRqTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyRDFBRDI0NTE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyRDFBRDI0NjE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjdERDBDNDA4MTc1MzExRTI4NjdDQUE5MUJDOUY2OUNGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjJEMUFEMjQ0MTc2RjExRTI4NjdDQUE5MUJDOUY2OUNGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+GPq/agAAAiRJREFUeNrEVb9rFEEUfm9m9nb3bhNz50UMClopRAsFrUURW1tBrSzsLPwfbPwDbGz8F8QiIkLAKiCkUIKiGBEFwXAhd7fZH7Mz83zZtbC4TdyF4LDF8N7ON9/73jczuN4/A4czBBzaqIUmAA+Q0wjQRzkUCsv4USEHKKs4/0DtWOdAgxLxrUk+mqyHIkLx2eg1k1gA3kwDtYFeFOqVnj5NRwXQip7eGG9+svlPV1wff3mejwuiZ9n2i3zCRWANAta1kaFX9OS1jkdkHdGyCt6blMmel8E3p1OgY6iueL2b/pEtZ5qx5kRCLIhMyK4WMQFt2HzdpEzypZ5OnOVUSoT1gqi6BOvA7ZoDUan5JB3BXxPeOALBahigxloLQO4SFy5hBjMOpuA0zc4ebL4OYExuZl0dxNiRh63MZ4jYXjzJiG77/cuqW8UvqvBO0Ge+jjsplKHmgrCIIeICyke9pXPKZ+kvqPCS1+X6T4vO42iJN/YB22jNIo6cYWN9dfqdya560TxKruKaF32w2abVW2VWtNCa6fRQnpTeD1vcD4anZOdNEa8VCZN9EA6/2+KE9Ob3dUit+XbJHRfqXjBgTZjYhk3nUDAQN/CsDJbDYIfcbvlhU+hqQUpuSo6tcstfYMp8q9z1+7+cyfZMuUe4zZGp/GfLxRm4bbIPu4scYbIJOO6EO+hSVf9y8zLQmGxUKrNDRu7HtSH0n+NHrpr8/1fmtwADAEjB+xzEjgF0AAAAAElFTkSuQmCC"
}
    • 国家视图模型**
import SwiftUI
import Foundation

struct Country: Codable, Identifiable, Comparable, Hashable {

    let id = UUID() // New
    let name: String
    let isoAlpha3: String
    let flag: Data?
    enum CodingKeys: String, CodingKey {
        case name, isoAlpha3, flag
    }

    var flagImage: UIImage? {
        guard let flagData = flag else { return nil }
        return UIImage(data: flagData)
    }

    static func == (lhs: Country, rhs: Country) -> Bool {
        lhs.name == rhs.name
    }

    static func < (lhs: Country, rhs: Country) -> Bool {
        lhs.name < rhs.name
    }

    struct HeadingData: Codable, Identifiable, Hashable {
        let id: Int
        let name: String
        let isoAlpha3: String
        let flag: Data
    }

    struct CurrencyData: Codable, Equatable, Identifiable, Hashable {
        let id: UUID
        let code: String
        let name: String
        let symbol: String
    }
}

class CountryModel: ObservableObject {
    @Published var countries: [Country] = []

    init() {
        self.countries = Bundle.main.decode("Countries.json")
//        let data = self.countries
//        let json = try? JSONSerialization.jsonObject(with: data, options: [])
    }
}
    • 用于解码clientFlag的计算属性**
extension ClientEntity {
    var showFlag: Image {
        let str = clientFlag ?? Data()
        if str.isEmpty {
            let flagImage = Image(systemName: "plus.circle")
            return flagImage
        } else {
            let dataDecoded : Data = Data(base64Encoded: str) ?? Data()
            guard let flagImage = UIImage.init(data: dataDecoded) else { return Image(systemName: "plus.circle") }
            return Image(uiImage: flagImage)
        }
    }
}
    • 客户端视图模型**
import Foundation
import Combine
import CoreData

class ClientViewModel: ObservableObject {
    @Published var clientName = ""
    @Published var clientAddress1 = ""
    @Published var clientAddress2 = ""
    @Published var clientPhoneNumber = ""
    @Published var clientHostCountry = ""
    @Published var clientFlag: Data?
    @Published var clientIndustry = ""
    @Published var clientLogo: Data?
    @Published var clientComments = ""
    @Published var clientExisting = false
    @Published var clientWebSite: URL?
    @Published var clientUpdated: Date = Date()
    @Published var clientCreated: Date = Date()
    @Published var clientItem: ClientEntity!
    @Published var selectedContact: [ContactEntity] = []
    
    func addClient(context: NSManagedObjectContext) {
        if clientItem == nil {
            let client = ClientEntity(context: context)
            client.clientName = clientName
            client.clientAddress1 = clientAddress1
            client.clientAddress2 = clientAddress2
            client.clientPhoneNumber = clientPhoneNumber
            print("clientVM \(clientHostCountry)")
            client.clientHostCountry = clientHostCountry
            client.clientFlag = clientFlag
            client.clientIndustry = clientIndustry
            // client.clientLogo = clientLogo
            client.clientComments = clientComments
            client.clientExisting = clientExisting
            // client.clientWebSite = clientWebSite
            client.clientUpdated = clientUpdated
            client.clientCreated = clientCreated
            print("Selected Contact: \(selectedContact.description)")
            let uniqueContact = Set(selectedContact)
            for contact in uniqueContact {
                client.addToContacts(contact)
            }
        } else {
            clientItem.clientName = clientName
            clientItem.clientAddress1 = clientAddress1
            clientItem.clientAddress2 = clientAddress2
            clientItem.clientPhoneNumber = clientPhoneNumber
            clientItem.clientHostCountry = clientHostCountry
            clientItem.clientFlag = clientFlag
            clientItem.clientIndustry = clientIndustry
            // clientItem.clientLogo = clientLogo
            clientItem.clientComments = clientComments
            clientItem.clientExisting = clientExisting
            // clientItem.clientWebSite = clientWebSite
            clientItem.clientUpdated = clientUpdated
            clientItem.clientCreated = clientCreated
            print("Selected Contact: \(selectedContact.description)")
            let uniqueContact = Set(selectedContact)
            for contact in uniqueContact {
                clientItem.addToContacts(contact)
            }
        }
        save(context: context)
        clientName = ""
        clientAddress1 = ""
        clientAddress2 = ""
        clientPhoneNumber = ""
        clientHostCountry = ""
        clientFlag = Data()
        clientIndustry = ""
        // clientLogo = Data()
        clientComments = ""
        clientExisting = false
        //        clientWebSite = URL(string: "")!
        clientUpdated = Date()
        clientCreated = Date()
        
    }
    
    func editClient(client: ClientEntity) {
        clientItem = client
    }
    
    func delete(client: ClientEntity, context: NSManagedObjectContext) {
        context.delete(client)
        save(context: context)
    }
    
    func save(context: NSManagedObjectContext) {
        do {
            try context.save()
        } catch {
            fatalError("Error saving: \(error.localizedDescription)")
        }
    }
    
    func isExisting(client: ClientEntity, context: NSManagedObjectContext) {
        client.clientExisting.toggle()
        save(context: context)
    }
}

我试着添加. jpeg和. png参数以及成功的picker代码的相反部分。没有运气。

    • 新问题**程序在线程1时崩溃:断点1.2(1)在选取器中的. tag(country as Country)处出现错误(绿色背景?)。将鼠标悬停在"country"属性上显示它包含JSON文件中的第一个国家。"变量"窗口显示:

国家B2Bv5.国家
统一用户标识符uuid(UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8)
名称字符串
_内脏_字符串内脏_对象_字符串对象
_计数和标志位UInt64 13835058055282163723_对象内置桥接对象0x4000600001ef0ec0 isoAlpha3字符串
_内脏_字符串内脏_对象_字符串对象
_计数和标志位UInt64 4671041_对象NSTagged指针字符串"RCp1xmeaxi" 0xe300000000000000标志字符串?一些_guts_字符串Guts_对象_字符串对象
_计数和标志位UInt64 13835058055282165492_对象内置桥接对象0x4000000128065000

    • 国家视图模型**
import SwiftUI

结构国家:可编码、可识别、可比较、可散列{

let id = UUID() // New
let name: String
let isoAlpha3: String
let flag: String?
enum CodingKeys: String, CodingKey {
    case name, isoAlpha3, flag
}

var flagImage: UIImage? {
        if let flagString = flag,
           let data = flagString.data(using: .utf8),
           let decodedData = Data(base64Encoded: data),
           let image = UIImage(data: decodedData) {
            return image
        } else {
            let img = UIImage(systemName: "plus.circle")
            return img == nil ? UIImage() : img!
        }
    }

static func == (lhs: Country, rhs: Country) -> Bool {
    lhs.name == rhs.name
}

static func < (lhs: Country, rhs: Country) -> Bool {
    lhs.name < rhs.name
}

struct HeadingData: Codable, Identifiable, Hashable {
    let id: Int
    let name: String
    let isoAlpha3: String
    let flag: String
}

struct CurrencyData: Codable, Equatable, Identifiable, Hashable {
    let id: UUID
    let code: String
    let name: String
    let symbol: String
}

}
类别国家型号:可观测天体{@已发布变量国家:[国家]=[]

init() {
    self.countries = Bundle.main.decode("Countries.json")
}

}

    • 选取器扩展**
var hostCountry: some View {
    VStack(alignment: .leading) {
        Picker(selection: $clientVM.clientHostCountry,
               label: Text("")) {
            ForEach(countryVM.countries) { country in
                VStack {
                    Text(country.name)
                    Image(uiImage: country.flagImage!)
                }.tag(country as Country)
            }
            .padding(.horizontal, 10)
            .padding()
            .pickerStyle(MenuPickerStyle())
        }.padding(.horizontal)
    }
8yparm6h

8yparm6h1#

您可以尝试这种简单的方法,显示标志的Image,对我来说很有效:
从json数据中可以看出,flag是一个String,所以确保在struct Country中声明let flag: String?,这样就可以在CountryModel中解码json。

struct ContentView: View {

    let flag = "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAIAAAAVyRqTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyRDFBRDI0NTE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyRDFBRDI0NjE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjdERDBDNDA4MTc1MzExRTI4NjdDQUE5MUJDOUY2OUNGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjJEMUFEMjQ0MTc2RjExRTI4NjdDQUE5MUJDOUY2OUNGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+GPq/agAAAiRJREFUeNrEVb9rFEEUfm9m9nb3bhNz50UMClopRAsFrUURW1tBrSzsLPwfbPwDbGz8F8QiIkLAKiCkUIKiGBEFwXAhd7fZH7Mz83zZtbC4TdyF4LDF8N7ON9/73jczuN4/A4czBBzaqIUmAA+Q0wjQRzkUCsv4USEHKKs4/0DtWOdAgxLxrUk+mqyHIkLx2eg1k1gA3kwDtYFeFOqVnj5NRwXQip7eGG9+svlPV1wff3mejwuiZ9n2i3zCRWANAta1kaFX9OS1jkdkHdGyCt6blMmel8E3p1OgY6iueL2b/pEtZ5qx5kRCLIhMyK4WMQFt2HzdpEzypZ5OnOVUSoT1gqi6BOvA7ZoDUan5JB3BXxPeOALBahigxloLQO4SFy5hBjMOpuA0zc4ebL4OYExuZl0dxNiRh63MZ4jYXjzJiG77/cuqW8UvqvBO0Ge+jjsplKHmgrCIIeICyke9pXPKZ+kvqPCS1+X6T4vO42iJN/YB22jNIo6cYWN9dfqdya560TxKruKaF32w2abVW2VWtNCa6fRQnpTeD1vcD4anZOdNEa8VCZN9EA6/2+KE9Ob3dUit+XbJHRfqXjBgTZjYhk3nUDAQN/CsDJbDYIfcbvlhU+hqQUpuSo6tcstfYMp8q9z1+7+cyfZMuUe4zZGp/GfLxRm4bbIPu4scYbIJOO6EO+hSVf9y8zLQmGxUKrNDRu7HtSH0n+NHrpr8/1fmtwADAEjB+xzEjgF0AAAAAElFTkSuQmCC"

    @State var img = UIImage()
    
    var body: some View {
        Image(uiImage: img)
        .onAppear {
            if let data = flag.data(using: .utf8),
               let decodedData = Data(base64Encoded: data),
               let image = UIImage(data: decodedData) {
                img = image
            }
        }
    }
}

编辑-1
在您的模型结构Country中,您可能需要使用以下代码:

struct Country: Codable, Identifiable, Comparable, Hashable {
    let id = UUID()
    let name: String
    let isoAlpha3: String
    let flag: String?   // <--- here
    
    enum CodingKeys: String, CodingKey {
        case name, isoAlpha3, flag
    }
    
    // --- here
    var flagImage: UIImage? {
        if let flagString = flag,
           let data = flagString.data(using: .utf8),
           let decodedData = Data(base64Encoded: data),
           let image = UIImage(data: decodedData) {
            return image
        } else {
            return nil
        }
    }
    
    //....
}

一旦你有了Data的图像,你就可以用它来存储在你的clientFlag中,你的ClientEntity和你的ClientViewModel中。
编辑-2:
在您的Picker中,与其使用if let data = country.flag!.data(using: .utf8),...etc尝试再次解码标志,为什么不使用country.flagImage呢?这正是您使用它的目的。

var flagImage: UIImage {
    if let flagString = flag,
       let data = flagString.data(using: .utf8),
       let decodedData = Data(base64Encoded: data),
       let image = UIImage(data: decodedData) {
        return image
    } else {
        let img = UIImage(systemName: "plus.circle")
        return img == nil ? UIImage() : img!
    }
}

Picker中使用:

VStack {
        Text(country.name)
        Image(uiImage: country.flagImage)
    }
p1iqtdky

p1iqtdky2#

您的标志图像字符串iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAIAAAAVyRqTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw几乎是base64,但不完全是-它缺少Data(base64encoded:)所需的末尾填充字符。
您可以像这样轻松地添加它们:

let str = "iVBOR...AADw" // your clientFlag string from JSON
let pad = String(repeating: "=", count: 4 - (str.count % 4))
let data = Data(base64Encoded: str + pad)

相关问题