How to set image convert from base64 string width and height? - ios

I have a question about UIImage convert to base64 String.
And I already resize my image width and height (1024 x 768).
Then I convert this image to base64 String.
But when I use this base64 String to UIImage and look image width and height not I resize before(2304.0 x 3072.0).
How to make my base64 String image size correctly?
guard let image = image else { return }
print("image => \(image)")
//image => <UIImage:0x283cce7f0 anonymous {768, 1024}>
guard let base64ImageString = image.toBase64(format: .jpeg(0.2)) else { return }
let dataDecoded : Data = Data(base64Encoded: base64ImageString, options: .ignoreUnknownCharacters)!
let decodedimage = UIImage(data: dataDecoded)
let height = decodedimage?.size.height
let width = decodedimage?.size.width
print("====) \(String(describing: width)) / \(String(describing: height))")
//====) Optional(2304.0) / Optional(3072.0)
public enum ImageFormat {
case png
case jpeg(CGFloat)
}
extension UIImage {
public func toBase64(format: ImageFormat) -> String? {
var imageData: Data?
switch format {
case .png:
imageData = self.pngData()
case .jpeg(let compression):
imageData = self.jpegData(compressionQuality: compression)
}
return imageData?.base64EncodedString()
}
}

Try this way, the below code resizes your image, and should be added before you change it to base64.
guard let image = image else { return }
print("image => \(image)")
//image => <UIImage:0x283cce7f0 anonymous {768, 1024}>
let desiredSize = CGSize(width: 768, height: 1024)
UIGraphicsBeginImageContextWithOptions(desiredSize, false, 1.0)
image.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width:
desiredSize.width, height: desiredSize.height)))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let base64ImageString = resizedImage.toBase64(format: .jpeg(0.2)) else { return }

Related

How to get thumbnail and Original image from UIImagePickerViewcontroller?

After captured photo from camera, I was doing image compression For (400kb and 1 Mb), it look almost 3 seconds in iPhone 6 and less than a second in iPhone 6s.
Is there any way to get thumbnail and original image without doing manual compression?
Code used for image compression
Extension for UIImage
extension UIImage {
// MARK: - UIImage+Resize
func compressTo(_ expectedSizeInMb:Int) -> Data? {
let sizeInBytes = expectedSizeInMb * 1024 * 1024
var needCompress:Bool = true
var imgData:Data?
var compressingValue:CGFloat = 1.0
while (needCompress && compressingValue > 0.0) {
if let data:Data = jpegData(compressionQuality: compressingValue) {
if data.count < sizeInBytes {
needCompress = false
imgData = data
} else {
compressingValue -= 0.1
}
}
}
if let data = imgData {
if (data.count < sizeInBytes) {
return data
}
}
return nil
}
}
usage:
if let imageData = image.compressTo(1) {
print(imageData)
}
For images saved in Photos Library :
Try :
let phAsset = info[UIImagePickerController.InfoKey.phAsset] as! PHAsset
let options = PHImageRequestOptions()
options.deliveryMode = .fastFormat
options.isSynchronous = false
// you can change your target size to CGSize(width: Int , height: Int) any number you want.
PHImageManager.default().requestImage(for: phAsset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: options, resultHandler: { image , _ in
let thumbnail = image
// use your thumbnail
})
For Captured images from Camera, you can get image pixels without recalculating data count :
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
// pixels are the same on each device’s camera
let widthPixels = image.size.width * image.scale
let heightPixels = image.size.height * image.scale
let sizeInBytes = 1024 * 1024
var thumbnail : UIImage! = nil
if Int(widthPixels * heightPixels) > sizeInBytes {
// assign custom width and height you need
let rect = CGRect(x: 0.0, y: 0.0, width: 100, height: 100)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 1)
let context = UIGraphicsGetCurrentContext()
context?.interpolationQuality = .low
image.draw(in: rect)
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
thumbnail = resizedImage
} else {
thumbnail = image
}

Converting Image Data to Varbinary

I'm trying to upload image file on iOS device to remote SQL Server's VARBINARY(MAX) column but having difficulties.
Basically i need to convert UIImage to whatever i need to insert into:
INSERT INTO table (ImageColumn) VALUES ('byteString here')
Column type is: VARBINARY(MAX) and I can print string via:
let imageData = UIImagePNGRepresentation(value)
let base64String = imageData?.base64EncodedString()
imageBase64 = base64String!
print(imageBase64) // this prints all the string
this even writes 8-9mb of data to the column but it's always corrupted. I don't know if my sql query string is totally wrong or not
EDIT: quick fix
let value_resized = value.resizedTo1MB()
let imageData = UIImageJPEGRepresentation(value_resized!, 0)
let strBase64 = imageData?.base64EncodedString(options: .lineLength64Characters)
imageBase64 = strBase64!
// i can insert imageBase64 to sql as a string
extension UIImage {
func resized(withPercentage percentage: CGFloat) -> UIImage? {
let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: canvasSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
func resizedTo1MB() -> UIImage? {
guard let imageData = UIImagePNGRepresentation(self) else { return nil }
var resizingImage = self
var imageSizeKB = Double(imageData.count) / 1000.0
while imageSizeKB > 1000 {
guard let resizedImage = resizingImage.resized(withPercentage: 0.9),
let imageData = UIImagePNGRepresentation(resizedImage)
else { return nil }
resizingImage = resizedImage
imageSizeKB = Double(imageData.count) / 1000.0
}
return resizingImage
}
}

Image data rotating 45 degrees after resizing

I have a snippet of code that utilizes the ImageIO library to resize an image to make it smaller when uploading to Parse. Upon uploading, the picture becomes rotated 45 degrees counterclockwise.
let imageBytes = UIImageJPEGRepresentation(imageView.image, 1.0)
let size = CGSizeMake(1024, 1024)
if let imageSource = CGImageSourceCreateWithData(imageBytes, nil) {
let options: [NSString: AnyObject] = [
kCGImageSourceThumbnailMaxPixelSize: NSNumber(double: Double(max(size.width, size.height)) / 2.0),
kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
kCGImageSourceCreateThumbnailWithTransform: false
]
//2. Recreate the Image that has been scaled
let scaledImage = UIImage(CGImage: CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options))
let scaledImageBytes = UIImageJPEGRepresentation(scaledImage, 1.0)
let metaData = [
"imageBytes": scaledImageBytes, //for some reason, scaledImageBytes causes a 90 degree rotation on the picture. Using unscaled image for now.
]
//3. upload the image to Parse
PFCloud.callFunctionInBackground("uploadImage", withParameters: metaData) { message, error in
if let error = error {
println("error uploading: \(error)")
} else if let message = message as? String {
println("success: \(message)")
}
}
}
How can I resolve that problem?
check this function to normalize your image
func normalizeImage(raw: UIImage) -> UIImage {
if raw.imageOrientation == UIImageOrientation.Up {
return raw
}
UIGraphicsBeginImageContextWithOptions(raw.size, false, raw.scale)
raw.drawInRect(CGRect(origin: CGPointZero, size: raw.size))
var normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return normalizedImage
}

OSX UIGraphicsBeginImageContext

I have an iOS app that I am now creating for Mac OSX. I have the code below that converts the image to a size of 1024 and works out the width based on the aspect ratio of the image. This works on iOS but obviously does not on OSX. I am not sure how to create a PNG representation of the NSImage or what I should be using instead of UIGraphicsBeginImageContext. Any suggestions?
Thanks.
var image = myImageView.image
let imageData = UIImagePNGRepresentation(image)
let imageWidth = image?.size.width
let calculationNumber:CGFloat = imageWidth! / 1024.0
let imageHeight = image?.size.height
let newImageHeight = imageHeight! / calculationNumber
UIGraphicsBeginImageContext(CGSizeMake(1024.0, newImageHeight))
image?.drawInRect(CGRectMake(0, 0, 1024.0, newImageHeight))
var resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let imageData = UIImagePNGRepresentation(resizedImage)
let theImageData:NSData = UIImagePNGRepresentation(resizedImage)
imageFile = PFFile(data: theImageData)
You can use:
let image = NSImage(size: newSize)
image.lockFocus()
//draw your stuff here
image.unlockFocus()
if let data = image?.TIFFRepresentation {
let imageRep = NSBitmapImageRep(data: data)
let imageData = imageRep?.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
//do something with your PNG data here
}
my two cents...
a quick extension to draw an image with a partially overlapped image:
extension NSImage {
func mergeWith(anotherImage: NSImage) -> NSImage {
self.lockFocus()
//draw your stuff here
self.draw(in: CGRect(origin: .zero, size: size))
let frame2 = CGRect(x: 4, y: 4, width: size.width/3, height: size.height/3)
anotherImage.draw(in: frame2)
self.unlockFocus()
return self
}
}
final effect:

How can I generate a barcode from a string in Swift?

I am a new iOS developer. I was wondering how can I generate a barcode in Swift.
I have the code already, there are multiple resources from where to learn how to read a barcode, but I didn't find any that talks about generating one from a string.
Thanks a lot!
P.S. I know there is a similar question about this, but it's for Objective-C. I don't know Obj-C and I find it difficult coming from .NET.
You could use a CoreImage (import CoreImage) filter to do that!
class Barcode {
class func fromString(string : String) -> UIImage? {
let data = string.data(using: .ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
if let outputCIImage = filter.outputImage {
return UIImage(ciImage: outputCIImage)
}
}
return nil
}
}
let img = Barcode.fromString("whateva")
A newer version, with guard and failable initialiser:
extension UIImage {
convenience init?(barcode: String) {
let data = barcode.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage = filter.outputImage else {
return nil
}
self.init(ciImage: ciImage)
}
}
Usage:
let barcode = UIImage(barcode: "some text") // yields UIImage?
According to the docs :
Generates an output image representing the input data according to the
ISO/IEC 15417:2007 standard. The width of each module (vertical line)
of the barcode in the output image is one pixel. The height of the
barcode is 32 pixels. To create a barcode from a string or URL,
convert it to an NSData object using the NSASCIIStringEncoding string
encoding.
Improved code:
Barcode scaling
Set barcode image margin
Convert the UIImage to NSData (for some reason it wasn't possible with the code above).
It won't fail when sharing the barcode image (probably because of the same bug)
Swift 3
func generateBarcode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setDefaults()
//Margin
filter.setValue(7.00, forKey: "inputQuietSpace")
filter.setValue(data, forKey: "inputMessage")
//Scaling
let transform = CGAffineTransform(scaleX: 3, y: 3)
if let output = filter.outputImage?.applying(transform) {
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
let rawImage:UIImage = UIImage.init(cgImage: cgImage)
//Refinement code to allow conversion to NSData or share UIImage. Code here:
//http://stackoverflow.com/questions/2240395/uiimage-created-from-cgimageref-fails-with-uiimagepngrepresentation
let cgimage: CGImage = (rawImage.cgImage)!
let cropZone = CGRect(x: 0, y: 0, width: Int(rawImage.size.width), height: Int(rawImage.size.height))
let cWidth: size_t = size_t(cropZone.size.width)
let cHeight: size_t = size_t(cropZone.size.height)
let bitsPerComponent: size_t = cgimage.bitsPerComponent
//THE OPERATIONS ORDER COULD BE FLIPPED, ALTHOUGH, IT DOESN'T AFFECT THE RESULT
let bytesPerRow = (cgimage.bytesPerRow) / (cgimage.width * cWidth)
let context2: CGContext = CGContext(data: nil, width: cWidth, height: cHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: cgimage.bitmapInfo.rawValue)!
context2.draw(cgimage, in: cropZone)
let result: CGImage = context2.makeImage()!
let finalImage = UIImage(cgImage: result)
return finalImage
}
}
return nil
}
If your deployment target is at least iOS 8, you can use Core Image. Here is my BarcodeGenerator class (you need to import CoreImage):
class BarcodeGenerator {
enum Descriptor: String {
case code128 = "CICode128BarcodeGenerator"
case pdf417 = "CIPDF417BarcodeGenerator"
case aztec = "CIAztecCodeGenerator"
case qr = "CIQRCodeGenerator"
}
class func generate(from string: String,
descriptor: Descriptor,
size: CGSize) -> CIImage? {
let filterName = descriptor.rawValue
guard let data = string.data(using: .ascii),
let filter = CIFilter(name: filterName) else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let image = filter.outputImage else {
return nil
}
let imageSize = image.extent.size
let transform = CGAffineTransform(scaleX: size.width / imageSize.width,
y: size.height / imageSize.height)
let scaledImage = image.transformed(by: transform)
return scaledImage
}
}
It can be used like this
BarcodeGenerator.generate(from: "barcode-string",
descriptor: .code128,
size: CGSize(width: 800, height: 300))
Use like this,
func createBarcodeFromString(barcode:String)->UIImage?{
let data = self.data(using: .isoLatin1)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
filter.setValue(7.0, forKey:"inputQuietSpace")
guard var ciImage = filter.outputImage else {
return nil
}
let imageSize = ciImage.extent.integral
let outputSize = CGSize(width:320, height: 60)
ciImage = ciImage.transformed(by:CGAffineTransform(scaleX: outputSize.width/imageSize.width, y: outputSize.height/imageSize.height))
let image = convertCIImageToUIImage(ciimage: ciImage)
return image
}
func convertCIImageToUIImage(ciimage:CIImage)->UIImage{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(ciimage, from: ciimage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}

Resources