Can not get info out of generated QRCode - ios

I am trying to generate QRCode with multiple strings. It is working, however the generated image QRCode is too small inside the imageView so it is impossible to read it in(At least I think that is why I can't get info out of it).
This is how it looks:
And like this I generate it:
func generateQRWithInfo(){
var aggregateData = [String: NSData]()
if let firstName = firstName?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(firstName as NSData, forKey: "firstName")
}
if let lastName = lastName?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(lastName as NSData, forKey: "lastName")
}
if let job = job?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(job as NSData, forKey: "job")
}
if let organization = organization?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(organization as NSData, forKey: "organization")
}
if let mobilePhone = mobilePhone?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(mobilePhone as NSData, forKey: "mobilePhone")
}
if let workPhone = workPhone?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(workPhone as NSData, forKey: "workPhone")
}
if let email = email?.data(using: String.Encoding.isoLatin1, allowLossyConversion: false) {
aggregateData.updateValue(email as NSData, forKey: "email")
}
let archived = NSKeyedArchiver.archivedData(withRootObject: aggregateData)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(archived, forKey: "inputMessage")
filter?.setValue("Q", forKey: "inputCorrectionLevel")
let qrCodeImage = filter?.outputImage
let context = CIContext(options: nil)
//let cgImage = context.createCGImage(qrCodeImage!, from: (qrCodeImage?.extent)!)
let transform = CGAffineTransform(scaleX: 50,y: 50)
let output = filter?.outputImage?.applying(transform)
let newImage = UIImage(ciImage: output!)
qrImageView.image = newImage
}
I do not know if it is how it should be but I can't get info out of it. What I am doing wrong?

QR Codes holds lots of data based on these parameters.
Data type
Size a.k.a pixels
Error correction level
Data type can be Numeric, Alphanumeric and Binary.
Error correction level can be categorised as Type L,M,Q and H based on loss recovery possible.
so as per your case you want to generate 30*30 alphanumeric so obviously you cant store more then allowed values. So make it bigger or reduce the data. To make a note all the QR code readers are not same.
For more info check this table

Related

storing background images in userdefaults

I need to be able to set the background image for this button. I need to store this so after the app closes the background image is the same.
eventsFirstButton.backgroundColor = UIColor(patternImage: UIImage(named: "events")!)
You could just save the state:
Correct answer:
UserDefaults.standard.set(true, forKey: "TestAnswer1")
//If the answer is incorrect set to false
On load:
if UserDefaults.standard.bool(forKey: "TestAnswer1") {
view.backgroundColor = UIColor.green
// or any other logic
} else {
view.backgroundColor = UIColor.red
// or any other logic
}
It's better to save it as base64string, you don't want to store large value to UserDefaults.
To encode UIImage use this:
let image = UIImage()
let data = image.pngData()
let imageBase64String = data?.base64EncodedString()
UserDefaults.standard.set(imageBase64String, forKey: "encodedImage")
And for decoding and retrieving UIImage use this:
if let imageBase64String = UserDefaults.standard.value(forKey: "encodedImage"),
let url = URL(string: String(format:"data:application/octet-stream;base64,%#",imageBase64String))
{
do
{
let data = try Data(contentsOf: url)
let image = UIImage(data: data)
}
catch let error
{
print("Error decoding image")
}
}
If you really need to save the PNG, JPEG images locally, use CoreData to store them on the device.
You can use UserDefaults to save your image
Save
if let image = eventsFirstButton.imageView?.image {
let imageData = image.pngData()
UserDefaults.standard.set(imageData, forKey: "imageData")
}
Retrieve
if let imageData = UserDefaults.standard.data(forKey: "imageData") {
print("IMG data: ", imageData)
// your code here
}

Why am I getting Incorrect argument label in call

Getting "Incorrect argument label in call (have 'rest:', expected 'restaurant:')" error. Here is the code. The parameter is correct and I am passing the correct type? Is this because they are class methods?
class func save(restaurant: Restaurant, toCloud: Bool) -> Bool {
var rest:RestaurantMO
var saved:Bool = false
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
rest = RestaurantMO(context: appDelegate.persistentContainer.viewContext)
rest.name = restaurant.name
rest.item = restaurant.item
rest.location = restaurant.location
rest.isVisited = restaurant.isVisited
// Core Data Exercise - Solution
rest.phone = restaurant.phone
let entity =
NSEntityDescription.entity(forEntityName: "Restaurant",
in: appDelegate.persistentContainer.viewContext)!
_ = NSManagedObject(entity: entity,
insertInto: appDelegate.persistentContainer.viewContext)
print("Saving data to context ...")
appDelegate.saveContext()
saved = true
}
if toCloud {
saveRecordToCloud(rest:RestaurantMO) <--- ERROR: Incorrect argument label in call (have 'rest:', expected 'restaurant:')
}
}
class func saveRecordToCloud(restaurant:RestaurantMO!) -> Void {
// Prepare the record to save
let record = CKRecord(recordType: "Restaurant")
record.setValue(restaurant.name, forKey: "name")
record.setValue(restaurant.item, forKey: "item")
record.setValue(restaurant.location, forKey: "location")
record.setValue(restaurant.phone, forKey: "phone")
let imageData = restaurant.image! as Data
// Resize the image
let originalImage = UIImage(data: imageData)!
let scalingFactor = (originalImage.size.width > 1024) ? 1024 / originalImage.size.width : 1.0
let scaledImage = UIImage(data: imageData, scale: scalingFactor)!
// Write the image to local file for temporary use
let imageFilePath = NSTemporaryDirectory() + restaurant.name!
let imageFileURL = URL(fileURLWithPath: imageFilePath)
try? UIImageJPEGRepresentation(scaledImage, 0.8)?.write(to: imageFileURL)
// Create image asset for upload
let imageAsset = CKAsset(fileURL: imageFileURL)
record.setValue(imageAsset, forKey: "image")
// Get the Public iCloud Database
let publicDatabase = CKContainer.default().publicCloudDatabase
// Save the record to iCloud
publicDatabase.save(record, completionHandler: { (record, error) -> Void in
// Remove temp file
try? FileManager.default.removeItem(at: imageFileURL)
})
}
The parameter is correct and I am passing the correct type
No, both are wrong.
The method is declared as
class func saveRecordToCloud(restaurant:RestaurantMO!)
The parameter label is restaurant rather than rest (stated clearly by the error message)
The parameter type is RestaurantMO rather than RestaurantMO.type (an instance is expected)
The correct syntax is
saveRecordToCloud(restaurant: rest)
Note: As the parameter is non-optional remove the exclamation mark in the method declaration:
func saveRecordToCloud(restaurant:RestaurantMO)

Swift 3 - Saving images to Core Data

For some reason I can't figure out how to save images to core data and fetch them again. I have a feeling it's something about my types but have a look:
I get my data from an api call to my server. It returns a base64 string.
Here is where I get the data:
updateAccessTokenOnly(newAccessToken: aToken!)
saveImageToDB(brandName: imageBrandName, image: data! )
Here I save it to my DB:
func saveImageToDB(brandName: String, image: Data) {
dropImages(){tableDropped in
let managedContext = getContext()
let entity = NSEntityDescription.entity(forEntityName: "CoffeeShopImage", in: managedContext)!
let CSI = NSManagedObject(entity: entity, insertInto: managedContext)
CSI.setValue(image, forKey: "image")
CSI.setValue(brandName, forKey: "brandName")
do {
try managedContext.save()
print("saved!")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
then to fetch it:
func getImageFromDB(callback: #escaping (_ image: UIImage)-> ()) {
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: "CoffeeShopImage")
do {
let searchResults = try getContext().fetch(fetchRequest)
for images in searchResults {
print("vi når her ned i get image")
if (images.value(forKey: "brandName")! as! String == "Baresso"){
print(images.value(forKey: "brandName")! as! String)
let image: Data = images.value(forKey: "image")! as! Data
let decodedimage = UIImage(data: image)
callback(decodedimage!)
}
}
} catch {
print("Error with request: \(error)")
}
}
Full error log:
https://docs.google.com/document/d/1gSXE64Sxtzo81eBSjv4bnBjBnnmG4MX2tuvNtnuJDIM/edit?usp=sharing
Hope someone can help. Thanks in advance!
UPDATED
So I uninstalled the app and then the code above worked. However the pictures come out blue? (yes I've checked that the pictures sent from the database are correct).
Any solution?
replace
let image: Data = images.value(forKey: "image")! as! Data
let dataDecoded : Data = Data(base64Encoded: image, options: [])!
let decodedimage = UIImage(data: dataDecoded)
with
let image: Data = images.value(forKey: "image")! as! Data
let decodedimage = UIImage(data: image)
Base64 is a way to to convert data to a string. There is no reason to use it here. You already have the data from the database you just want to convert it to a UIImage.
also change
let image = data?.base64EncodedData()
saveImageToDB(brandName: imageBrandName, image: image!)
to
saveImageToDB(brandName: imageBrandName, image: data!)
base64EncodedData is turning the data from image data into a utf-8 encoded based64encoded string. There is no reason for that.
You should get the base64 encoded string from server, convert it to data and then you never need base64 again. Read and write data to your database, and after you read it convert it to a UIImage. Base64 is an encoding method to transfer data. If you are not talking to the server there is no reason to use base64.
After the suggested corrections from Jon Rose all I needed was to add
.withRenderingMode(.alwaysOriginal)
to where I was showing my picture and the code worked.
Saving Image:
guard let managedObjectContext = managedObjectContext else { return }
// Create User
let user = User(context: managedObjectContext)
// Configure User
user.name = "name"
user.about = "about"
user.address = "Address"
user.age = 30
if let img = UIImage(named: "dog.png") {
let data = img.pngData() as NSData?
user.image = data
}
Fetching Image:
// Create Fetch Request
let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let users = try! managedContext.fetch(fetchRequest)
let user: User = users.first as! User
if let imageData = user?.image {
imgView.image = UIImage(data: imageData as Data)
}

Adding Multiple Key-Value Pairs to QR Code

I'm creating QR Codes in my app and I'm wanting to know if it's possible to add a second key-value pair. Right now I have a 12 digit number for the "inputMessage" key and I'm wanting to have some other data for another key. For example, using another string for a new key called "gym".
Here is my function for creating the QR Code:
func generateCode() {
let gymData = gymName.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
let codeNumberData = generateRandomNumber(12).dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(codeNumberData, forKey: "inputMessage")
// filter?.setValue(gymData, forKey: "gym")
filter?.setValue("Q", forKey: "inputCorrectionLevel")
let qrCodeImage = filter?.outputImage
let context = CIContext(options: nil)
let cgImage = context.createCGImage(qrCodeImage!, fromRect: (qrCodeImage?.extent)!)
let image = UIImage(CGImage: cgImage, scale: 1.0, orientation: .Up)
let resized = resizeImage(image, withQuality: CGInterpolationQuality.None, rate: 5.0)
codeImageView.image = resized
}
The CIFilter is only expecting to generate the QR code from inputMessage, so you need to create a single aggregate inputMessage and pass that to the filter. One fairly straight forward way of doing this is to create a Dictionary from your inputs, serialize it into a NSData blob using the NSKeyedArchiver, and then set the result as your inputMessage.
func generateCode() {
var aggregateData = [String: NSData]()
if let gymData = gymName.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false) {
aggregateData.updateValue(gymData, forKey: "gymData")
}
if let codeNumberData = generateRandomNumber(12).dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false) {
aggregateData.updateValue(codeNumberData, forKey: "codeNumberData")
}
let archived = NSKeyedArchiver.archivedDataWithRootObject(aggregateData)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(archived, forKey: "inputMessage")
filter?.setValue("Q", forKey: "inputCorrectionLevel")
let qrCodeImage = filter?.outputImage
let context = CIContext(options: nil)
let cgImage = context.createCGImage(qrCodeImage!, fromRect: (qrCodeImage?.extent)!)
let image = UIImage(CGImage: cgImage, scale: 1.0, orientation: .Up)
let resized = resizeImage(image, withQuality: CGInterpolationQuality.None, rate: 5.0)
codeImageView.image = resized
}
Of course this means that on the receiving end, you'll need to expect the payload to be a dictionary, and access the individual components by their keys. Should look something like this.
guard let inputData = scannedQrString.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false),
dictionary = NSKeyedUnarchiver.unarchiveObjectWithData(inputData) as? [String: NSData] else {
return
}
let gymData = dictionary["gymData"]
let codeNumberData = dictionary["codeNumberData"]

How to generate a EAN13 barcode?

I'm trying to create a simple EAN13 image to show a barcode from a String.
I tried with this code but it can only generate a code128. What can I use to generate a EAN13?
class Barcode {
class func fromString(string : String) -> UIImage? {
let data = string.dataUsingEncoding(NSASCIIStringEncoding)
let filter = CIFilter(name: "CICode128BarcodeGenerator")
filter.setValue(data, forKey: "inputMessage")
return UIImage(CIImage: filter.outputImage)
}
}
let img = Barcode.fromString("1234567890123")
you can try this EAN13BarcodeGenerator
Usage is pretty simple:
BarCodeView *barCodeView = [[BarCodeView alloc] initWithFrame:kBarCodeFrame];
[self.view addSubview:barCodeView];
[barCodeView setBarCode:GetNewRandomEAN13BarCode()];
my two cents for osx..
func barCodeFromString(string : String, destSize: NSSize) -> NSImage? {
let data = string.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else{
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage : CIImage = filter.outputImage else{
return nil
}
let c_size = ciImage.extent.size
let w_ratio = destSize.width/c_size.width
let h_ratio = destSize.height/c_size.height
let ratio = w_ratio>h_ratio ? h_ratio : w_ratio
let transform = CGAffineTransform(scaleX: ratio, y: ratio)
let scaled = ciImage.transformed(by: transform)
let rep = NSCIImageRep(ciImage: scaled)
let nsImage = NSImage(size: rep.size)
nsImage.addRepresentation(rep)
return nsImage
}

Resources