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
}
}
Related
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
}
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 }
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
}
I have a textView with images, different text styles etc. I wanna display it on watch. Is there any way to do it?
It is not a code for displaying NSAttributedString on apple watch, but I use it for sending NSAttributedString with images in the form which will be easier to display.
Code may not be a high-quality(I am almost sure it isn't, especially scaling images).
func sendText(stext: NSMutableAttributedString) {
dispatch_async(dispatch_get_main_queue()) {
let range:NSRange = NSMakeRange(0, stext.length)
stext.enumerateAttributesInRange(range, options: NSAttributedStringEnumerationOptions.init(rawValue: 0), usingBlock: { (dic: [String:AnyObject]?, rang:NSRange!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.attachement = dic as NSDictionary!
self.attachement.enumerateKeysAndObjectsUsingBlock({ (key:AnyObject?, obj:AnyObject?, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
let stri = key as! NSString!
if stri == "NSAttachment"{
let att:NSTextAttachment = obj as! NSTextAttachment
if att.image == nil{
print("no image")
}else{
var im:UIImage = att.image!
print("image exists")
if im.size.height > 340 && im.size.width > 272 {
let heightScale: CGFloat = self.textView.frame.size.height / im.size.height
let widthScale: CGFloat = self.textView.frame.size.width / im.size.width
if heightScale < widthScale {
let height = im.size.height * heightScale * 0.7
let width = im.size.width * heightScale * 0.7
UIGraphicsBeginImageContext(CGSizeMake(width, height))
im.drawInRect(CGRectMake(0, 0, width, height))
im = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
} else {
let height = im.size.height * widthScale * 0.7
let width = im.size.width * widthScale * 0.7
UIGraphicsBeginImageContext(CGSizeMake(width, height))
im.drawInRect(CGRectMake(0, 0, width, height))
im = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
self.lastRange = rang.location
self.finalForWatch.append(NSAttributedString(attributedString: stext.attributedSubstringFromRange(NSMakeRange(0, rang.location))))
self.finalForWatch.append(im)
}
}
if self.lastRange == 0 {
self.finalForWatch.append(stext)
} else {
self.finalForWatch.append(NSAttributedString(attributedString: stext.attributedSubstringFromRange(NSMakeRange(1, stext.length-1))))
}
})
})
let data: NSData = NSKeyedArchiver.archivedDataWithRootObject(self.finalForWatch)
let applicationDict = ["done" : data]
let documentDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
let fileDestinationUrl = documentDirectoryURL.URLByAppendingPathComponent("file.txt")
do{
try data.writeToURL(fileDestinationUrl, atomically: true)
} catch let error as NSError {
print("error writing to url \(fileDestinationUrl)")
print(error.localizedDescription)
}
self.session?.transferFile(fileDestinationUrl, metadata: nil)
}
}
I save everything into a file and use a sendFile method because appllicationContext, userInfo and messages always return "too big payloads".
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
}