Draw text in image right corner - ios

I want to draw a text in the top or bottom right corner of an UIImage.
I have an extension which works great to draw the text but the problem is to positioned the text at the right of the screen (because text is cut).
Here is the extension :
extension UIImage {
func addText(drawText: NSString, atPoint: CGPoint, textColor: UIColor?, textFont: UIFont?) -> UIImage{
// Setup the font specific variables
var _textColor: UIColor
if textColor == nil {
_textColor = UIColor.white
} else {
_textColor = textColor!
}
var _textFont: UIFont
if textFont == nil {
_textFont = UIFont.systemFont(ofSize: 50)
} else {
_textFont = textFont!
}
// Setup the image context using the passed image
UIGraphicsBeginImageContext(size)
// Setup the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: _textFont,
NSForegroundColorAttributeName: _textColor,
] as [String : Any]
// Put the image into a rectangle as large as the original image
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
// Create a point within the space that is as bit as the image
let rect = CGRect(x: atPoint.x, y: atPoint.y, width: size.width, height: size.height)
// Draw the text into an image
drawText.draw(in: rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage!
}
}
Problem is if the text is too long or too big it will be out of the screen. I would need to change the origin point to write the text from the right to the left so it will take space only on the left and not on the right out of the screen. How could I do that ?

There is a simple function call to get the "bounding box" for a string. You can use that to position where the text should be drawn into the image:
// get the bounding-box for the string
let stringSize = drawText.size(attributes: textFontAttributes)
// position the bounding-box at the bottom-right corner of the image
let x = self.size.width - ceil(stringSize.width)
let y = self.size.height - ceil(stringSize.height)
let rect = CGRect(x: x, y: y, width: stringSize.width, height: stringSize.height)
// Draw the text into an image
drawText.draw(in: rect, withAttributes: textFontAttributes)
Note that this sample code positions the text at bottom-right corner - ignoring the atPoint parameter. You would likely change that to a whichCorner type parameter, and then calculate the x and y position appropriately.
By the way... drawText is a terrible name for a variable - it sounds like a function. Much more readable to use something like textToDraw.
Here is a modified function, using a atCorner parameter, where the values are:
+-----------+
| 0 1 |
| |
| |
| 3 2 |
+-----------+
Edit: Using right-aligned paragraph style (as suggested by Thilina Chamin Hewagama) has some advantages. This edited version will even handle text with "\n" embedded line breaks.
extension UIImage {
func addText(textToDraw: NSString, atCorner: Int, textColor: UIColor?, textFont: UIFont?) -> UIImage {
// Setup the font specific variables
var _textColor: UIColor
if textColor == nil {
_textColor = UIColor.white
} else {
_textColor = textColor!
}
var _textFont: UIFont
if textFont == nil {
_textFont = UIFont.systemFont(ofSize: 50)
} else {
_textFont = textFont!
}
// Setup the image context using the passed image
UIGraphicsBeginImageContext(size)
// Put the image into a rectangle as large as the original image
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let titleParagraphStyle = NSMutableParagraphStyle()
// Setup the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: _textFont,
NSForegroundColorAttributeName: _textColor,
NSParagraphStyleAttributeName: titleParagraphStyle
] as [String : Any]
// get the bounding-box for the string
var stringSize = textToDraw.size(attributes: textFontAttributes)
// draw in rect functions like whole numbers
stringSize.width = ceil(stringSize.width)
stringSize.height = ceil(stringSize.height)
var rect = CGRect(origin: CGPoint.zero, size: self.size)
switch atCorner {
case 1:
// top-right
titleParagraphStyle.alignment = .right
case 2:
// bottom-right
rect.origin.y = self.size.height - stringSize.height
titleParagraphStyle.alignment = .right
case 3:
// bottom-left
rect.origin.y = self.size.height - stringSize.height
default:
// top-left
// don't need to change anything here
break
}
// Draw the text into an image
textToDraw.draw(in: rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage!
}
}

Related

Merge UIImage with UILabel into one UIImage, Swift

I am trying to "merge" an UIImage with a UILabel into one UIImage, for that I wrote a function everything works fine except that the Label does not get added to the Current Graphics Context. I would appreciate your help!
func textToImage(drawText: String, inImage: UIImage, atPoint: CGPoint) -> UIImage{
// Setup the image context using the passed image
UIGraphicsBeginImageContext(inImage.size)
// Put the image into a rectangle as large as the original image
inImage.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: inImage.size.width, height: inImage.size.height)))
// Create a point within the space that is as bit as the image
let rectPos = CGPoint(x: atPoint.x, y: atPoint.y)
let rectSize = CGSize(width: inImage.size.width, height: inImage.size.height)
let rect = CGRect(origin: rectPos, size: rectSize)
// Draw the text into an image
let label = UILabel()
label.text = drawText
label.textColor = .white
label.font = UIFont(name: "Helvetica Bold", size: 12)!
label.drawText(in: rect)
// Create a new image out of the images we have created
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage!
}
Are u sure that you trying to draw label in correct position? Is rect which you compute as CGRect(origin: CGPoint.zero, size: CGSize(width: inImage.size.width, height: inImage.size.height)) contains atPoint?
The problem seems to be here UIGraphicsBeginImageContext(inImage.size)
The context you are creating is the size of your image. You need to create the context to the size of Image + label height. Then you can add the label accordingly and will be able to see the label inside the image appended.
Also specify the label's frame let label = UILabel().
Suppose you want to append the label at the bottom of the image.
Let the image size be 300 * 400, and you want to put the label at the bottom.
The concept is to create a context with the height of 400 + label height (suppose 40).
Then you set the label frame to be a y of CGRect(0,imagesize.height,100,40).
Hope it helps
Problem with your code is that UIKit (UILabel usage) tries to draw stuff in its own context. You need to draw text + image in same context to get the desired result.
Try this to receive the resulting image:
func textToImage(drawText text: NSString, inImage image: UIImage) -> UIImage
{
UIGraphicsBeginImageContext(image.size)
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
let font=UIFont(name: "Helvetica-Bold", size: 8)!
let paraStyle=NSMutableParagraphStyle()
paraStyle.alignment=NSTextAlignment.center
let attributes = [NSAttributedStringKey.foregroundColor:UIColor.red, NSAttributedStringKey.font:font, NSAttributedStringKey.paragraphStyle:paraStyle]
let height = font.lineHeight
let y = (image.size.height-height) / 2
let strRect = CGRect(x: 0, y: y, width: image.size.width, height: height)
text.draw(in: strRect.integral, withAttributes: attributes)
let result=UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result!
}
#IBAction func touchTest(_ sender: Any)
{
let button = sender as! UIButton
let image = self.textToImage(drawText: "my text", inImage: UIImage.init(named: "circle")!)
button.setBackgroundImage(image, for: UIControlState.normal)
}

How to get a screenshot of the View (Drawing View) used for drawing using UIBezeir path

I have a Drawing View which is on a Scroll View. After drawing is completed I need a screenshot of the drawing which I will be uploading to the server.
I am using UIBezeir path to draw on the view.
let path = UIBezierPath()
for i in self.drawView.path{
path.append(i)
}
self.drawView.path is an NSArray with all the bezeir paths of the drawing.
But when I use the bounding box of this path and get max and min values of coordinates and try to capture a screenshot I get this
var rect:CGRect = CGRect(x: path.bounds.minX, y: path.bounds.minY, width: path.bounds.maxX, height: path.bounds.maxY)
I also tried to give the bounds of the path itself
let rect:CGRect = CGRect(x: path.bounds.origin.x - 5, y: path.bounds.origin.y - 5, width: path.bounds.size.width + 5, height: path.bounds.size.height + 5)
Just for reference I tried using this rect and create a view (clear color with border layer) and placed it over the Drawing, it work pretty fine but when I try to capture an image it goes out of bounds
This is the function I am using to capture the screen
func imgScreenShot(bounds:CGRect) -> UIImage{
let rect: CGRect = bounds
self.drawView.isOpaque = false
self.drawView.backgroundColor = UIColor.clear
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
var context: CGContext? = UIGraphicsGetCurrentContext()
if let aContext = context {
self.drawView.layer.render(in: aContext)
}
var capturedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//let finalImage = scaleImage(image: capturedImage)
return capturedImage!
}
I am also tried getting a UIView with this function
let vw = self.drawView.resizableSnapshotView(from: rect, afterScreenUpdates: true, withCapInsets: UIEdgeInsets.zero)
This gives me a perfect UIView with the drawing in that, but again when I try to convert the UIView to UIImage using the function giving the views bounds, I get a blank image.
Can anyone suggest what I am doing wrong or any other solution for how I can get this, bounds of image starting right exactly at the bounds of the drawing
let vw = self.drawView.resizableSnapshotView(from: rect2, afterScreenUpdates: true, withCapInsets: UIEdgeInsets.zero)
vw?.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
vw?.layer.borderColor = UIColor.red.cgColor
vw?.layer.borderWidth = 1
self.drawView.addSubview(vw!)
let image = vw?.snapshotImage
let imgView = UIImageView(frame: CGRect(x: 250, y: 50, width: 100, height: 100))
imgView.layer.borderColor = UIColor.gray.cgColor
imgView.layer.borderWidth = 1
self.drawView.addSubview(imgView)
Make an extension of UIView and UIImage , so in whole application lifecycle you can use those methods(which one i will be describe at below) for capture the screenshort of any perticular UIView and resize the existing image(if needed).
Here is the extension of UIView :-
extension UIView {
var snapshotImage : UIImage? {
var snapShotImage:UIImage?
UIGraphicsBeginImageContext(self.frame.size)
if let context = UIGraphicsGetCurrentContext() {
self.layer.render(in: context)
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
snapShotImage = image
}
}
return snapShotImage
}
}
Here is the extension of UIImage :-
extension UIImage {
func resizeImage(newSize:CGSize) -> UIImage? {
var newImage:UIImage?
let horizontalRatio = newSize.width / size.width
let verticalRatio = newSize.height / size.height
let ratio = max(horizontalRatio, verticalRatio)
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
UIGraphicsBeginImageContext(newSize)
if let _ = UIGraphicsGetCurrentContext() {
draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
newImage = image
}
}
return newImage
}
}
How to use those functions in our desired class ?
if let snapImage = yourUIView.snapshotImage {
///... snapImage is the desired image you want and its dataType is `UIImage`.
///... Now resize the snapImage into desired size by using this one
if let resizableImage = snapImage.resizeImage(newSize: CGSize(width: 150.0, height: 150.0)) {
print(resizableImage)
}
}
here yourUIView means , the one you have taken for drawing some inputs. it can be IBOutlet as well as your UIView (which you have taken programmatically)

iOS swift: Image from label in TabBarItem

I'm trying to create a gray circle with name initials indie of it. And use it as tabBarItem image.
This is the function that I use to create the circle, and it almost works, as you can see in the image below, but it's a square not a circle:
static func createAvatarWithInitials(name: String, surname: String, size: CGFloat) -> UIImage {
let initialsLabel = UILabel()
initialsLabel.frame.size = CGSize(width: size, height: size)
initialsLabel.textColor = UIColor.white
initialsLabel.text = "\(name.characters.first!)\(surname.characters.first!)"
initialsLabel.textAlignment = .center
initialsLabel.backgroundColor = UIColor(red: 74.0/255, green: 77.0/255, blue: 78.0/255, alpha: 1.0)
initialsLabel.layer.cornerRadius = size/2
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(initialsLabel.frame.size, false, scale)
initialsLabel.layer.render(in: UIGraphicsGetCurrentContext()!)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
image.withRenderingMode(.alwaysOriginal)
return image
}
and this is how I call it inside the viewDidLoad of the tabBarController:
if index == positionForProfileItem {
tabBarItem.image = UIImage.createAvatarWithInitials(name: "John", surname: "Doe", size: CGFloat(20))
}
but I got an empty squared rectangle in the tab bar.. And I can't figure it out the reason, any help?
The UIImage withRenderingMode method returns a new image. It does not modify the sender.
Change the last two lines to just one:
return image.withRenderingMode(.alwaysOriginal)
But that is not what you wish to do. Since you want a template image of a circle with the text in the middle, you need to do the following:
static func createAvatarWithInitials(name: String, surname: String, size: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), false, 0)
let ctx = UIGraphicsGetCurrentContext()!
// Draw an opague circle
UIColor.white.setFill()
let circle = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: size, height: size))
circle.fill()
// Setup text
let font = UIFont.systemFont(ofSize: 17)
let text = "\(name.characters.first!)\(surname.characters.first!)"
let textSize = (text as NSString).size(withAttributes: [ .font: font ])
// Erase text
ctx.setBlendMode(.clear)
let textRect = CGRect(x: (size - textSize.width) / 2, y: (size - textSize.height) / 2, width: textSize.width, height: textSize.height)
(text as NSString).draw(in: textRect, withAttributes: [ .font: font ])
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
You have to add clipsToBounds=YES on your label for cornerRadius to have efect on your screen shoot, and also try to increase a little bit the size of your image from 20 to 30.

google maps iOS SDK: custom icons to be used as markers

The Android API has a very convenient class for this, IconGenerator. Using the IconGenerator in my Android app, I can easily make a marker that:
is a simple rectangle with the color of my choosing.
resizes to hold text of any length.
is NOT an info window - I'd like the marker itself to contain the text as shown in the image below from the android version.
// Android - problem solved with IconGenerator
IconGenerator iconGenerator = new IconGenerator(context);
iconGenerator.setStyle(IconGenerator.STYLE_GREEN); // or any other color
Bitmap iconBitmap = iconGenerator.makeIcon(myString);
Marker m = new MarkerOptions().icon(BitmapDescriptorFactory.fromBitmap(iconBitmap))
.position(myLatLng);
map.addMarker(m); // map is a com.google.android.gms.maps.GoogleMap
Is there a way to do something as simple as this in iOS using Swift?
There has been a recent release of the iOS api that allows "marker customization", but I don't see how to apply it to this use case.
// iOS (Swift) - I don't know how to create the icon as in code above
let marker = GMSMarker(position: myLatLng)
marker.icon = // How can I set to a rectangle with color/text of my choosing?
marker.map = map // map is a GMSMapView
Here is what I have done
let marker = GMSMarker()
// I have taken a pin image which is a custom image
let markerImage = UIImage(named: "mapMarker")!.withRenderingMode(.alwaysTemplate)
//creating a marker view
let markerView = UIImageView(image: markerImage)
//changing the tint color of the image
markerView.tintColor = UIColor.red
marker.position = CLLocationCoordinate2D(latitude: 28.7041, longitude: 77.1025)
marker.iconView = markerView
marker.title = "New Delhi"
marker.snippet = "India"
marker.map = mapView
//comment this line if you don't wish to put a callout bubble
mapView.selectedMarker = marker
The output is
And my marker image was
You can change your color as per your need. Also if you want something in rectange, you can just create a simple small rectangular image and use it like I did above and change the color of your need.
Or if you want a rectangle with text within it, you can just create a small UIView with some label and then convert that UIView in UIImage and can do the same thing.
//function to convert the given UIView into a UIImage
func imageWithView(view:UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
Hope it helps!!
Here is what i have done for solving the same issue, that you are facing.
I have added below image in my image assets,
Now i added below method in my code:
-(UIImage*)drawText:(NSString*)text inImage:(UIImage*)image
{
UIFont *font = [UIFont boldSystemFontOfSize:11];
CGSize size = image.size;
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
NSDictionary *attributes = #{
NSFontAttributeName : font,
NSParagraphStyleAttributeName : paragraphStyle,
NSForegroundColorAttributeName : [UIColor redColor]
};
CGSize textSize = [text sizeWithAttributes:attributes];
CGRect textRect = CGRectMake((rect.size.width-textSize.width)/2, (rect.size.height-textSize.height)/2 - 2, textSize.width, textSize.height);
[text drawInRect:CGRectIntegral(textRect) withAttributes:attributes];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Now, I called this method, while assigning icon to GMSMarker, like this:
marker.icon = [self drawText:#"$33.6" inImage:[UIImage imageNamed:#"icon-marker"]];
It will generate the image icon like below:
Here, I kept the background Image size fixed, as i needed. You can still customize it to adjust it according to text size, as well as multiple lines.
UPDATE
Updated code in Swift:
func drawText(text:NSString, inImage:UIImage) -> UIImage? {
let font = UIFont.systemFont(ofSize: 11)
let size = inImage.size
//UIGraphicsBeginImageContext(size)
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(inImage.size, false, scale)
inImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let style : NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
style.alignment = .center
let attributes:NSDictionary = [ NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.foregroundColor : UIColor.black ]
let textSize = text.size(withAttributes: attributes as? [NSAttributedString.Key : Any])
let rect = CGRect(x: 0, y: 0, width: inImage.size.width, height: inImage.size.height)
let textRect = CGRect(x: (rect.size.width - textSize.width)/2, y: (rect.size.height - textSize.height)/2 - 2, width: textSize.width, height: textSize.height)
text.draw(in: textRect.integral, withAttributes: attributes as? [NSAttributedString.Key : Any])
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
You can simply add a custom view as marker in Google Map.
let marker = GMSMarker(position: coordinate)
marker.iconView = view // Your Custom view here
You can use imageView (for containing that orange color box) and label (for text) above it
I tried to rewrite Mehul Thakkar answer to Swift 3. Hope it will work for you. But it really easier to make custom view as Dari said.
func drawText(text:NSString, inImage:UIImage) -> UIImage? {
let font = UIFont.systemFont(ofSize: 11)
let size = inImage.size
UIGraphicsBeginImageContext(size)
inImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let style : NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
style.alignment = .center
let attributes:NSDictionary = [ NSFontAttributeName : font, NSParagraphStyleAttributeName : style, NSForegroundColorAttributeName : UIColor.red ]
let textSize = text.size(attributes: attributes as? [String : Any])
let rect = CGRect(x: 0, y: 0, width: inImage.size.width, height: inImage.size.height)
let textRect = CGRect(x: (rect.size.width - textSize.width)/2, y: (rect.size.height - textSize.height)/2 - 2, width: textSize.width, height: textSize.height)
text.draw(in: textRect.integral, withAttributes: attributes as? [String : Any])
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
Here a Swift 5 version of Eridana's Swift conversion of Mehul Thakkar's answer.
func drawTextT(text:NSString, inImage:UIImage) -> UIImage? {
let font = UIFont.systemFont(ofSize: 11)
let size = inImage.size
UIGraphicsBeginImageContext(size)
inImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let style : NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
style.alignment = .center
let attributes:NSDictionary = [ NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.foregroundColor : UIColor.red ]
//let textSize = text.size(attributes: attributes as? [String : Any])
let textSize = text.size(withAttributes: attributes as? [NSAttributedString.Key : Any] )
let rect = CGRect(x: 0, y: 0, width: inImage.size.width, height: inImage.size.height)
let textRect = CGRect(x: (rect.size.width - textSize.width)/2, y: (rect.size.height - textSize.height)/2 - 2, width: textSize.width, height: textSize.height)
text.draw(in: textRect.integral, withAttributes: attributes as? [NSAttributedString.Key : Any] )
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
Simplest way to achieve if you have just 1 image :
marker.icon = #imageLiteral(resourceName: "fault_marker")
1) In latest XCode write marker.icon = "imageLiteral".
2) Double click the dummy image icon appeared just now.
3) select desired image.
//func to get Image view
// Url String :- Your image coming from server
//image :- Background image
func drawImageWithProfilePic(urlString:String, image: UIImage) -> UIImageView {
let imgView = UIImageView(image: image)
imgView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
let picImgView = UIImageView()
picImgView.sd_setImage(with:URL(string: urlString))
picImgView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
imgView.addSubview(picImgView)
picImgView.center.x = imgView.center.x
picImgView.center.y = imgView.center.y-10
picImgView.layer.cornerRadius = picImgView.frame.width/2
picImgView.clipsToBounds = true
imgView.setNeedsLayout()
picImgView.setNeedsLayout()
// let newImage = imageWithView(view: imgView)
// return newImage
return imgView
}
//SHOW ON MAP
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
marker.iconView = self.drawImageWithProfilePic(urlString:getProviderImage,image: UIImage.init(named: "red")!)
Simple and easiest way to change icon. just replace these 3 icon (default marker.png) to your icon (1x,2x,3x).
In Google Cluster there was a problem with marker (icon) change.

Add border to UIImage inside of a UITextView

I am trying to add a border to a UIImage I have, not UIImageView.
Here is my code:
let textView = UITextView(frame: CGRectMake(10, 20, self.view.frame.width - 20, self.view.frame.height - 20))
let attributedString = NSMutableAttributedString(string: "")
let image1 = NSTextAttachment()
image1.image = UIImage(named: "image.jpg")
let oldWidth1 = image1.image!.size.width;
//I'm subtracting 10px to make the image display nicely, accounting
//for the padding inside the textView
let scaleFactor1 = oldWidth1 / (textView.frame.size.width - 10 )
image1.image = UIImage(CGImage: image1.image!.CGImage!, scale: scaleFactor1, orientation: .Up)
let attrStringWithImage1 = NSAttributedString(attachment: image1)
attributedString.replaceCharactersInRange(NSMakeRange(0, 0), withAttributedString: attrStringWithImage1)
textView.attributedText = attributedString;
self.view.addSubview(textView)
I have that UIImage which is displaying nicely in a textView, but now I would like to add a border or some padding to the image so that the text is not so close to the image!
You could easily use Core Graphics to do this
You just have to re-draw the image in a bigger context to account for the border width – and offset the image by the border width.
Something like this should do the trick:
extension UIImage {
func imageWithBorder(borderWidth:CGFloat) -> UIImage {
// the bigger size to account for the border width
let newSize = CGSize(width: size.width+borderWidth*2.0, height: size.height+borderWidth*2.0)
// create new image context
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
// draw image with offset of the border width
self.drawInRect(CGRect(x: borderWidth, y: borderWidth, width: size.width, height: size.height))
// get image and end context
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
}
If you want to give the border a fill color, you can always do that by setting the fill color, and filling the context before drawing the image.
You can then use it like this:
image1.image = UIImage(named: "image.jpg")?.imageWithBorder(10)
Side Note
You seem to be force unwrapping optionals quite a bit. Please don't. Please always safely unwrap them. My answer here might be useful for that.

Resources