Text size is not same when draw text on UIimage - ios

I am working on project where I need to add text to the image which is coming from the textfield.
But when I see the text on the image it shows the font size smaller than the font size of textfield.
I am using following method to draw text on image
func drawText(text: String, inImage image: UIImage, atPoint point: CGPoint, fontName:String, fontSize: String,textColor: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(image.size, true, UIScreen.mainScreen().scale)
UIGraphicsBeginImageContext(image.size)
image.drawInRect(CGRectMake(0, 0, image.size.width, image.size.height))
let rect: CGRect = CGRectMake(point.x, point.y, image.size.width, image.size.height)
// UIColor.whiteColor().set()
// set the font to Helvetica Neue 18
if let sizeFont = NSNumberFormatter().numberFromString(fontSize) {
// TODO: - Need to resolve issue
let originalSize = sizeFont.integerValue
let finalFontSize = CGFloat(originalSize)
let fieldFont = UIFont(name: fontName, size:finalFontSize*1.5)
// set the line spacing to 6
let paraStyle = NSMutableParagraphStyle()
// paraStyle.lineSpacing = 6.0
// set the Obliqueness to 0.1
// let skew = 0.1
let attributes: NSDictionary = [
NSForegroundColorAttributeName: textColor,
// NSParagraphStyleAttributeName: paraStyle,
// NSObliquenessAttributeName: skew,
NSFontAttributeName: fieldFont!
]
NSString(string: text).drawInRect(rect, withAttributes: attributes as? [String : AnyObject])
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
return nil
}
And font size could be 16-60px.
Please let me know what could be the solution.
Thanks

Everything seems fine with your code.
One possible problem is that you don't see the image at full size inside your ImageView because it scales it, so you see the font smaller than what you want.
You could resize the image before drawing the text on it to fit the container it will be displayed on.
Or you can calculate the fontSize multiplying it with 1/scale, with scale = the scale at will the image will be shown
For example if the image is taller than larger and the container (the imageView) is smaller than the image scale will be image.size.height/imageView.frame.size.height.
I think that this could resolve your problem.

As suggested by LorenzOliveto, this could be due to scaling issues. One of the easy workaround would be to add text as a subview of imageView and then convert the imageView to image using this extension.
extension UIView {
/**
Convert UIView to UIImage
*/
func toImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return snapshotImageFromMyView!
}
}

Related

Quality get reduced when convert imageview to image

In photo editor screen , I have imageview and it has background image and on top of imageview I add elements like text (label), stickers(images) etc. , Now for the final image containing all elements added on imageview , I am getting image from below code
clipRect is rect for background image inside imageview, image is aspectfit in imageview
Below is code inside UIView extension which has function to generate image out of view.
self == uiview
let op_format = UIGraphicsImageRendererFormat()
op_format.scale = 1.0
let renderer = UIGraphicsImageRenderer(bounds: CGRect(origin: clipRect!.origin, size: outputSize), format: op_format)
let originalBound = self.bounds
self.bounds = CGRect(origin: clipRect!.origin, size: clipRect!.size)
var finalImage = renderer.image { ctx in
self.drawHierarchy(in: CGRect(origin: self.bounds.origin, size: outputSize), afterScreenUpdates: true)
}
self.bounds = CGRect(origin: originalBound.origin, size: originalBound.size)
Issue here is quality of final image quality is very poor as compared to original background image.
Don't set the scale of your UIGraphicsImageRendererFormat to 1. That forces the output image to #1x (non-retina). For most (all?) iOS devices, that will cause a 2X or 3X loss of resolution. Leave the scale value of the UIGraphicsImageRendererFormat at the default value.
you can take screenshot as well
// Convert a uiview to uiimage
func captureView() -> UIImage {
// Gradually increase the number for high resolution.
let scale = 1.0
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, scale)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

Change the size of UIButton’s imageView

I am working on a subclass of UIButton, let’s call it MyButton. In most cases, buttons of this subclass will have both image and title.
I am having troubles configuring MyButton’s imageView size. The goal is to limit the size of the image, so that larger images are resized and fit into a 32-by-32 square.
For testing purposes, I added a 128-by-128-pixel image, and set imageView’s backgroundColor to green.
Below is what the button looked like when I added the image. Both the imageView and its image had the size of 128 by 128 pixels.
After I overrode MyButton’s intrinsicContentSize with CGSize(width: 160, height: 50) and set the button’s imageView’s contentMode to .scaleAspectFit, the imageView resized, but only in height—it’s still 128 pixels wide, which causes the button’s title to truncate.
I’ve seen a lot of articles on how to resize the image inside the imageView using imageEdgeInsets. This is not what I am looking for since in all those articles the imageView preserves its size and only adds padding around the image.
Changing the imageView’s frame or bounds produces no result.
Any thoughts on how I can resize the button’s imageView?
let customButtonImage = MyButton.currentImage
now you have your button image resize it using #jay's extension for resizing image
let newimage = customButtonImage. resizedImage(size:requiredSize)
Reset image to button
self.setImage(newimage, for: .normal) //normal or what state your want
#jays extension
extension UIImage
{
func resizedImage(Size sizeImage: CGSize) -> UIImage?
{
let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: sizeImage.width, height: sizeImage.height))
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
self.draw(in: frame)
let resizedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.withRenderingMode(.alwaysOriginal)
return resizedImage
}
}
You can resize the image and then ad to button's image. Below you can find resize image code.
extension UIImage
{
func resizedImage(Size sizeImage: CGSize) -> UIImage?
{
let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: sizeImage.width, height: sizeImage.height))
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
self.draw(in: frame)
let resizedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.withRenderingMode(.alwaysOriginal)
return resizedImage
}
}
Button ui extension.
#IBInspectable var sizeImage: CGSize {
get {
return self.imageView?.image?.size ?? CGSize.zero
}
set {
if let image = self.imageView?.image {
let imgUpdate = image.resizedImage(Size: newValue)
self.setImage(imgUpdate, for: .normal)
}
}
}

UIImageJpgRepresentation doubles image resolution

I am trying to save an image coming from the iPhone camera to a file. I use the following code:
try UIImageJPEGRepresentation(toWrite, 0.8)?.write(to: tempURL, options: NSData.WritingOptions.atomicWrite)
This results in a file double the resolution of the toWrite UIImage. I confirmed in the watch expressions that creating a new UIImage from UIImageJPEGRepresentation doubles its resolution
-> toWrite.size CGSize (width = 3264, height = 2448)
-> UIImage(data: UIImageJPEGRepresentation(toWrite, 0.8)).size CGSize? (width = 6528, height = 4896)
Any idea why this would happen, and how to avoid it?
Thanks
Your initial image has scale factor = 2, but when you init your image from data you will get image with scale factor = 1. Your way to solve it is to control the scale and init the image with scale property:
#available(iOS 6.0, *)
public init?(data: Data, scale: CGFloat)
Playground code that represents the way you can set scale
extension UIImage {
class func with(color: UIColor, size: CGSize) -> UIImage? {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(size, true, 2.0)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setFillColor(color.cgColor)
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
let image = UIImage.with(color: UIColor.orange, size: CGSize(width: 100, height: 100))
if let image = image {
let scale = image.scale
if let data = UIImageJPEGRepresentation(image, 0.8) {
if let newImage = UIImage(data: data, scale: scale) {
debugPrint(newImage?.size)
}
}
}

UITextView lags scrolling with added images

I've a UITextView in which I add images to, with ImagePickerController.
If there is only text in it, it is smooth, but after adding 3 or 4 images it becomes laggy on scroll within its content.
I compress the image when adding it, to it's lowest quality, but I must be doing something wrong because it still lags after the third image.
Here's the code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let _image = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
self.dismiss(animated: true, completion: nil)
// Compress the retrieved image
let compressedImage = UIImage(data: _image.lowestQualityJPEGNSData!)
//create and NSTextAttachment and add your image to it.
let attachment = NSTextAttachment()
let oldWidth = compressedImage?.size.width // scales it within the UITextView
let scaleFactor = oldWidth! / (bodyEditText.frame.size.width - 10); // adjusts the desired padding
attachment.image = UIImage(cgImage: (compressedImage?.cgImage!)!, scale: scaleFactor, orientation: .up)
//put your NSTextAttachment into and attributedString
let attString = NSAttributedString(attachment: attachment)
//add this attributed string to the current position.
bodyEditText.textStorage.insert(attString, at: bodyEditText.selectedRange.location)
}
extension UIImage {
var uncompressedPNGData: Data? { return UIImagePNGRepresentation(self) }
var highestQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 1.0) }
var highQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 0.75) }
var mediumQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 0.5) }
var lowQualityJPEGNSData: Data? { return UIImageJPEGRepresentation(self, 0.25) }
var lowestQualityJPEGNSData:Data? { return UIImageJPEGRepresentation(self, 0.0) }
}
What may be causing this issue and any tip how can I overpass this?
Thanks for helping
EDIT
Thanks to Duncan C I've managed to remove the whole lag and increase the performance rendering images A LOT.
By that I've replaced my imagePickerController with the following content:
let size = __CGSizeApplyAffineTransform(_image.size, CGAffineTransform.init(scaleX: 0.3, y: 0.3))
let hasAlpha = false
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
_image.draw(in: CGRect(origin: CGPoint.zero, size: size))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let att = NSTextAttachment()
att.image = scaledImage
//put your NSTextAttachment into and attributedString
let attString = NSAttributedString(attachment: att)
//add this attributed string to the current position.
bodyEditText.textStorage.insert(attString, at: bodyEditText.selectedRange.location)
You're misusing the scale factor. That's intended for handling the 1x, 2x, and 3x scaling of normal, retina, and #3x retina images.
The way you're doing it, the system has to render the full-sized images into your bounds rectangles each time it wants to draw one. If the images are considerably bigger than the size you're displaying them, you waste a bunch of memory and processing time.
First try simply setting your image view's contentMode to .scaleAspectFit and install the original image in image view without mucking around with the scale factor. See how that performs.
If that doesn't give acceptable performance you should render your starting images into an off-screen graphics context that's the target size of your image, and install the re-rendered image into your image views. You can use UIGraphicsBeginImageContextWithOptions() or various other techniques to resize your images for display.
Take a look at this link for information on image scaling and resizing:
http://nshipster.com/image-resizing/
Its not the best practice to do that. UITextViews is meant for text not all views.
you need to make a custom UIView consisting of a 1, textview 2, UICollectionView for numerous images.
In this way you can reuse this custom view at numerous places too throughout the project

Combining Images with Card Flip animation

I'm trying to combine images and flip them using the function:
UIView.transitionFromView(self.frontImageView, toView: self.backImageView, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromLeft, completion: nil)
This is using swift. I have 2 views and it works fine. I would like the backImageView to be a combination of the card which looks like a card with empty white space, and a letter or an image.
I saw several posts on combining images using UIGraphicsGetImageFromCurrentImageContext()
When I do this for letters it slows the app down I think..
Here is this code used (Card is a subclass of UIView)
func combineImages( card: Card ) -> UIImage
{
let bottomImage: UIImage = UIImage( named: "cardFront" )!
var textColor: UIColor = UIColor.blackColor()
var textFont: UIFont = UIFont(name: "Muli", size: 120 )!
UIGraphicsBeginImageContext( bottomImage.size )
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
bottomImage.drawInRect( CGRectMake(0, 0, bottomImage.size.width, bottomImage.size.height) )
var rect: CGRect = CGRectMake( 50, 48, 380, 360 )
var drawText = "\( card.pictureName )"
drawText.drawInRect( rect, withAttributes: textFontAttributes )
// Create a new image out of the images we have created
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
return newImage
}
Question is, is there a better way to do this? Something faster? I believe combining images is probably the slower alternative to something simple which i could be missing.

Resources