Proper way of Encoding image as base64String - ios

Currently, I am trying to send image to backend to upload an image in my project. I have seen all possible answer on stack overflow and elsewhere but can not successfully send the data to backend . Even if I send,due to some problem(most probably due to white spaces as I feel), image decoded in backend side is not being in proper format.
Code to encode -
let imageData1 : NSData = UIImageJPEGRepresentation(slctdImage, 0.1)!
let base64StringNew1 = imageData1.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
Now the intresting part -
When I decode that using SWIFT code locally, I get the image and I am being able to display it in an image View. But same string when I convert in any online bse64 converter, I don't get the result .
code used for decoding -
let decodedData = NSData(base64EncodedString:base64StringNew1, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
So what might be my problem . Can any one please suggest the correct way to upload images to backend using base64String?

Try with this
func encodeImage(dataImage:UIImage) -> String{
let imageData = UIImagePNGRepresentation(dataImage)
return imageData!.base64EncodedStringWithOptions([])
}
Checked in http://codebeautify.org/base64-to-image-converter and works

Below code for image encoding.
let image: UIImage = imgProfilePic.image!
let size = CGSizeApplyAffineTransform(image.size, CGAffineTransformMakeScale(0.3, 0.3))
let hasAlpha = false
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
image.drawInRect(CGRect(origin: CGPointZero, size: size))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
var imageData = UIImageJPEGRepresentation(scaledImage, 0.9)
var base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) // encode the image
var cd = CoreDataUser(pstrContext: "this")
var params = "strUsername=" + cd.getUsername()
params = params + "&strPassword=" + cd.getPassword()
params = params + "&blbProfilePic=" + base64String
PHP code where the base64 string is being decoded and displayed in the browser.
if ($rows) {
foreach ($rows as $row) {
$data = base64_decode($row["fblbProfilePic"]);
$image = imagecreatefromstring($data);
header('Content-Type: Image/jpeg');
imagejpeg($image);
//file_put_contents("test.jpg", $data);
//var_dump($data);
//echo base64_decode($row["fblbPicture"]);
/ /echo '<img src="data:image/jpg;base64,' . $row["fblbPicture"] . '" />';
}

Related

How to convert DynamicImage to Base64?

I can convert a Base64 string to a DynamicImage using the image and base64 crates but I can not convert the image back to a Base64 string.
What I am doing wrong here? How to achieve this?
extern crate base64;
extern crate image;
fn main() {
/*
Base64 to image
let img_buffer = base64::decode("qwerty...").unwrap();
let mut base_img = image::load_from_memory(img_buffer.as_slice()).unwrap();
*/
let mut base_img = image::open("player.png").unwrap();
base_img.invert();
// base_img.save("player1.png").unwrap();
// image to Base64
let res_base64 = base64::encode(base_img.raw_pixels().as_slice());
println!("{}", res_base64)
}
Base64 value of original image
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR42uydd5hlRZn/v1Un3dzdt/P0pJ6enANxGKISFEQkg4ur6667uquuCiKCIJKUpAj7U3cN66orWVERVxBmmDxMYHLOM90znfvGk6rq98e9ICoo0Kf73u5+P8+DjPBwZrpO1Xm...
Base64 value of Gimp inverted image
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH4wgMCCwxQF4N2QAAIABJREFUeNrsvXmc3FWZ7...
The response I am getting not the proper Base64 value:
////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///...
The Base64 values of the original and Gimp images represent PNG-encoded images. The response you're getting represents raw pixel data. You will need to convert the data to PNG before encoding as Base64. This should do it:
let mut buf = vec![[]];
base_img.write_to(&mut buf, image::ImageOutputFormat::PNG);
let res_base64 = base64::encode(&buf);
My 2022 solution is:
#Cargo.toml
[dependencies]
base64 = "0.13"
image = "0.24"
use image::{DynamicImage, ImageOutputFormat};
use std::io::Cursor;
fn image_to_base64(img: &DynamicImage) -> String {
let mut image_data: Vec<u8> = Vec::new();
img.write_to(&mut Cursor::new(&mut image_data), ImageOutputFormat::Png)
.unwrap();
let res_base64 = base64::encode(image_data);
format!("data:image/png;base64,{}", res_base64)
}
let img = image::load_from_memory(&data.clone()).unwrap();
println!("{}", image_to_base64(&img));
You can use this string for html tag <img src="..." />.

Read (custom) EXIF data from png file

For an app I'm trying to parse a vcf-File with all of the colleagues of my firm. Some of them have no real photo and instead automatically get a dummy photo inserted. Now in order to make the app future proof, I don't want to check for a resolution of 500x500 which right now would work. The idea by the department responsible for the vcf generation was to add a comment to the dummy photo base file they always use. I tried reading that in Swift, but have no luck as you can see in my test playground code:
import UIKit
import ImageIO
let photo = UIImage(named: "bild")!
let photoData = UIImagePNGRepresentation(photo)!
let base64String = photoData.base64EncodedString()
let photoSource = CGImageSourceCreateWithData(photoData as CFData, nil)!
for (key, value) in CGImageSourceCopyPropertiesAtIndex(photoSource, 0, nil) as! [String : Any] {
print("\(key): \(value)")
}
Output:
PixelWidth: 500
Depth: 8
ProfileName: sRGB IEC61966-2.1
HasAlpha: 1
ColorModel: RGB
{PNG}: {
Chromaticities = (
"0.3127",
"0.329",
"0.64",
"0.33",
"0.3",
"0.6000000000000001",
"0.15",
"0.06"
);
Gamma = "0.45455";
InterlaceType = 0;
sRGBIntent = 0;
}
PixelHeight: 500
The output of exiftool in Terminal meanwhile shows this on the same image (see especially User Comment and Document Name (Custom Field):
➔ exiftool bild.png
ExifTool Version Number : 10.50
File Name : bild.png
Directory : .
File Size : 4.2 kB
File Modification Date/Time : 2017:05:06 12:51:23+02:00
File Access Date/Time : 2017:05:06 12:51:24+02:00
File Inode Change Date/Time : 2017:05:06 12:51:23+02:00
File Permissions : rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 500
Image Height : 500
Bit Depth : 8
Color Type : Palette
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Palette : (Binary data 477 bytes, use -b option to extract)
Transparency : 0
Background Color : 0
Pixels Per Unit X : 2835
Pixels Per Unit Y : 2835
Pixel Units : meters
Modify Date : 2017:05:05 08:04:36
Exif Byte Order : Big-endian (Motorola, MM)
Document Name : dummy
X Resolution : 72
Y Resolution : 72
Resolution Unit : inches
Y Cb Cr Positioning : Centered
Exif Version : 0231
Components Configuration : Y, Cb, Cr, -
User Comment : dummy
Flashpix Version : 0100
Color Space : Uncalibrated
Image Size : 500x500
Megapixels : 0.250
I already tried accessing the User Comment by using kCGImagePropertyExifUserComment, but this returns nil and I guess it would only return some value, if the above code also worked as expected:
let userComment = dict[kCGImagePropertyExifUserComment as String] // User Comment is set --> but this returns nil
let pixelWidth = dict[kCGImagePropertyPixelWidth as String] // As a reference that this does normally work --> shows 500 as expected
Do you have any suggestions how to add a comment to the image that is readable with Swift code?
Here is a complete example showing how to create an image, save it as a PNG with metadata, then retrieve that metadata from the file. You should be able to paste this into an iOS Playground.
//: Playground - noun: a place where people can play
import UIKit
import ImageIO
import MobileCoreServices
var str = "Hello, playground"
if let image = createImage() {
let pngDictionary : NSDictionary = [
kCGImagePropertyPNGTitle : "Smile for the Camera",
kCGImagePropertyPNGAuthor : "Smiles-R-Us",
kCGImagePropertyPNGCopyright : "©2017 Smiles-R-Us",
kCGImagePropertyPNGCreationTime : String(describing: Date()),
kCGImagePropertyPNGDescription : "Have a Nice Day!"
]
let imageMetadata : NSDictionary = [ kCGImagePropertyPNGDictionary : pngDictionary ]
let tempURL = FileManager.default.temporaryDirectory
let filePath = tempURL.appendingPathComponent("Smile.png") as NSURL
let imageDestination = CGImageDestinationCreateWithURL(filePath, kUTTypePNG, 1, nil)
if let destination = imageDestination {
CGImageDestinationAddImage(destination, image.cgImage!, imageMetadata)
CGImageDestinationFinalize(destination)
}
if let imageSource = CGImageSourceCreateWithURL(filePath, nil) {
print (CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil))
}
print(filePath)
}
func createImage() -> UIImage? {
let bounds = CGRect(x: 0, y: 0, width: 200, height: 200)
UIGraphicsBeginImageContext(bounds.size)
if let cgContext = UIGraphicsGetCurrentContext() {
let inset = bounds.insetBy(dx: 20, dy: 20)
cgContext.clear(bounds)
cgContext.saveGState()
cgContext.setStrokeColor(UIColor.black.cgColor)
cgContext.setFillColor(UIColor.black.cgColor)
cgContext.setLineWidth(2.0)
cgContext.strokeEllipse(in: inset)
let eyeLevel = inset.maxY - (inset.height * 0.618)
cgContext.fillEllipse(in: CGRect(x: inset.minX + inset.width * 0.3,
y: eyeLevel, width: 10, height: 10))
cgContext.fillEllipse(in: CGRect(x: inset.minX + inset.width * 0.6,
y: eyeLevel, width: 10, height: 10))
cgContext.addArc(center: CGPoint(x:inset.midX, y:inset.midY), radius: (inset.width/2.0 - 20), startAngle: 2.61, endAngle: 0.52, clockwise: true)
cgContext.strokePath()
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

Put a string before a certain string inside a text in Swift 3

I'm dealing with an issue here, I have a URL of an image which is like this
http://example.com/image/test.jpg
Which is a string.
And I would like to insert before .jpg a certain text like -40x40
Is there any way to analyze the URL string and somehow to add this text so the final string should be
http://example.com/image/text-40x40.jpg
What i've tried till now is this
var finalImage = "http://example.com/image/test.jpg"
finalImage.insert("-40x40" as Character, at: finalImage.endIndex - 4)
but i get 2 errors.
1) i cant add more than 1 character and 2) i cant do the math ad endIndex.
But i can't add more than one character there.
Thanks a lot!
Try this. It uses NSURL, which exists so that path manipulations are easy and legal! The documentation is really quite good.
let s1 = "http://example.com/image/test.jpg"
let u = URL(fileURLWithPath: s1)
let exExt = u.deletingPathExtension()
let s2 = exExt.absoluteString + "-40x40.jpg"
Another ways.
The code shown in the question, fixed:
var finalImage = "http://example.com/image/test.jpg"
let extIndex = finalImage.index(finalImage.endIndex, offsetBy: -4)
finalImage.insert(contentsOf: "-40x40".characters, at: extIndex)
Using NSRegularExpression:
let origImage = "http://example.com/image/test.jpg"
let regex = try! NSRegularExpression(pattern: "(\\.jpg)$", options: .caseInsensitive)
let finalImage = regex.stringByReplacingMatches(in: origImage, range: NSRange(0..<origImage.utf16.count), withTemplate: "-40x40$0")
As a complement to the neat accepted answer by #Grimxn: Foundation's URL has various more methods that allows for more separation "of concerns" in case you'd like to apply some more complex modification of the image (file) name, while not really worrying about the image (file) name extension.
let s1 = "http://example.com/something.cgi/image/test.jpg"
let u = URL(fileURLWithPath: s1)
// separate into (String) components of interest
let prefixUrl = u.deletingLastPathComponent().absoluteString
// "http://example.com/something.cgi/image/"
let fileName = u.deletingPathExtension().lastPathComponent
// "test"
let fileExtension = "." + u.pathExtension
// ".jpg"
// ... some methods that implements your possibly more
// complex filename modification
func modify(fileName fName: String) -> String {
// ...
return fName + "-40x40"
}
// reconstruct url with modified filename
let s2 = prefixUrl + modify(fileName: fileName) + fileExtension
print(s2) // http:/example.com/something.cgi/image/test-40x40.jpg
Grimxn's solution is probably the best fit for this problem, but for more complex manipulation of URLs, take a look at the NSURLComponents class. You can convert an NSURL to NSURLComponents, then use the various methods of NSURLComponents to manipulate your URL, and then finally convert the NSURLComponents back to an NSURL
As noted in a comment by #dfri, Swift 3 (and later) includes a native URLComponents class, which follows Swift naming and calling conventions. Going forward you should use that instead of the Objective-C/Swift 2 NSURLComponents class.
if let url = NSURL(string: "http://example.com/image/test.jpg"),withoutExt = url.URLByDeletingPathExtension
{
let finalstring : NSString = withoutExt.absoluteString + "-40x40.jpg"
print(finalstring)
}
Very simply with one line...
let newURL = oldURL.stringByReplacingOccurrencesOfString(".jpg", withString: "-40x40.jpg", options: NSStringCompareOptions.LiteralSearch, range: nil)

How to convert Base64 string to NSData?

I have an iOS application (written in Swift) that retrieves data from a wcf service in JSON format. One of the data is an image stored as a base64string. However, I was not able to convert the base64string to NSData.
My main purpose is to convert base64string all the way to blob so that I could save that in the database. On the other hand, if you know at least part of it such as from base64string to NSData would be helpful.
Following code would give you the idea of my table
let ItemsDB = Table("Items")
let idDB = Expression<String>("ID")
let nameDB = Expression<String>("Name")
let catDB = Expression<String>("Category")
let uomDB = Expression<String>("UOM")
let priceDB = Expression<Double>("Price")
let imageDB = Expression<Blob>("Image")
let actDB = Expression<Bool>("Active")
To convert from Base64 string to NSData
let nsd: NSData = NSData(base64EncodedString: Image, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)!
To Convert to Blob
nsd.datatypeValue
This works:
Swift 3, 4 & 5:
var data = Data(base64Encoded: recording_base64, options: .ignoreUnknownCharacters)
Swift 2:
var data = NSData(base64EncodedString: recording_base64, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
There are lot of example you can find online but most of them are in Objective-c. For example, Converting between NSData and base64 strings
It is pretty straight forward for you to use
NSData(base64EncodedString: String, options: NSDataBase64DecodingOptions)

Swift - how to count bytes and convert them to megabytes?

I try to add bytes with bytes in order to get space that will be occupied by photos which i retrieve from internet.
I have following code, it gets sizes in bytes for each id in array of id
var diskSpace:Int64 = 0
for var i = 0; i < array.count; i++ {
let id = array[i]
let urlString = "urlToFetchData"
if let url = NSURL(string: urlString) {
if let data = try? NSData(contentsOfURL: url, options: []) {
let json = JSON(data: data)
let size = Int64(json["size"].stringValue)
diskSpace = diskSpace + size!
}
}
}
var diskSpaceInMb = diskSpace / 1024 / 1024
print("diskSpaceInMb is \(diskSpaceInMb)")
for example, I try to get size of three elements, which have following size in bytes (these sizes in bytes I receive in json)
3223653
5855382
8948976
when the code above is executed i receive result of
diskSpaceInMb is 8
which is obviously not try
How to convert bytes to megabytes correctly ?
let fileSizeWithUnit = ByteCountFormatter.string(fromByteCount: diskSpace, countStyle: .file)
print("File Size: \(fileSizeWithUnit)")
The problem is obviously in the for loop. Maybe the JSON is not as you expect.
Another reason why this might fail is the you use the try? keyword, which in this context it means that it gives you a value if it succeeds, but otherwise it returns nil. In your case, it may silently fail. If you want to check if it fails, you could add an else branch.

Resources