How to use UIGraphicsBeginImageContextWithOptions to draw non-standard shapes? - ios

I have an image which is a bubble shape, and I wish to add text to the middle of the image, so I tried to use UIGraphicsBeginImageContextWithOptions to redraw the image.
The code is as following:
let imageSize = CGSize(width: 40, height: 40)
// the rect in which the image will be drawn in
let imageRect = CGRect(origin: CGPoint.zero, size: imageSize)
UIGraphicsBeginImageContextWithOptions(imageSize, true, 1.0)
// begining drawing things
// first, we draw the image in the specified rect
image.draw(in: imageRect)
let attributes = [ NSAttributedStringKey.foregroundColor: UIColor.red,
NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 20)]
let text = "55"
let size = text.size(withAttributes: attributes)
let rect = CGRect(x: 20 - size.width / 2, y: 20 - size.height / 2, width: size.width, height: size.height)
text.draw(in: rect, withAttributes: attributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
but I get a square with a black background with the desired image inside:
the blue is the original image, the black is the re-drawn image. Anyone knows how can I draw the image as the original image?
Thanks!

You need to pass false, not true, to the 2nd argument (the opaque parameter) of the call to UIGraphicsBeginImageContextWithOptions function.
UIGraphicsBeginImageContextWithOptions(imageSize, false, 1.0)
You should also pass 0 as the 3rd argument (scale) so the image is scaled to match the current device's screen scale.

Related

UIImage convert to data and back changes size?

I create a picture programmatically, convert it to data and back and get different pictures.
let image1: UIImage = {
let size = CGSize(width: 50, height: 50)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
UIColor.black.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}()
let data = UIImagePNGRepresentation(image1)!
let image2 = UIImage(data: data)!
print(image1.size) // (50.0, 50.0)
print(image2.size) // (100.0, 100.0)
Please explain what happens and how to solve the problem. Thank you!
The "culprit" line:
UIGraphicsBeginImageContextWithOptions(size, false, 0)
Looking at the doc of UIGraphicsBeginImageContextWithOptions(), for the last parameter (scale)
scale The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the
device’s main screen.
If your device is Retina (*2), then the scale factor will be 2.

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)
}

Text drawn over image is too small

I'm trying to draw a resizable textView onto an image kind of like snapchat does but when I draw the label onto the image, the text is significantly smaller and more towards the top left than it should be.
func drawTextToImage(){
let rect = textView.frame
let showText = textView.text
let font = UIFont.boldSystemFont(ofSize: 26)
let attr = [NSFontAttributeName: font, NSForegroundColorAttributeName:UIColor.white]
let image = UIImage(named: "3FactorPostGreen")
//First create the rotated and transparent image with text
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), false, 0)
if let context = UIGraphicsGetCurrentContext() {
context.rotate (by: 45.0 * CGFloat.pi/180.0) //45˚
}
showText?.draw(in: CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: rect.size.height), withAttributes: attr)
let rotatedImageWithText = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
//Then, draw rotated image(with text) onto the background image
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), true, 0)
image?.draw(in: rect)
rotatedImageWithText?.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
self.imageView.image = newImage
}
Then this was the before and after photos
Larger Text:
Smaller Text:
I have no idea what happens when this goes on but if anyone could explain and help that would be awesome.

Draw text onto image at an angle [Swift 3]

I'm trying to make function that will take text from a textfield (textField) and draw it onto an image. The function at the moment can only change the drawing's coordinates x and y, and width and height. What I was wondering is how I can make the text be drawn at an angle (eg 45˚, 18˚, etc...)
Thanks in advance.
func drawText() {
let font = UIFont.boldSystemFont(ofSize: 30)
let showText:NSString = textField.text as! NSString
// setting attr: font name, color...etc.
let attr = [NSFontAttributeName: font, NSForegroundColorAttributeName:UIColor.white]
// getting size
let sizeOfText = showText.size(attributes: attr)
let image = UIImage(named: "image")!
let rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), true, 0)
// drawing our image to the graphics context
image.draw(in: rect)
// drawing text
showText.draw(in: CGRect(x: rect.size.width-sizeOfText.width-10, y: rect.size.height-sizeOfText.height-10, width: rect.size.width, height: rect.size.height), withAttributes: attr)
// getting an image from it
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
self.imageView.image = newImage
}
1.Draw text to an image first, then rotate the image.
2.Draw rotated image(with text) onto the background image.
//First create the rotated and transparent image with text
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), false, 0)
if let context = UIGraphicsGetCurrentContext() {
context.rotate (by: 45.0 * CGFloat.pi/180.0) //45˚
}
showText.draw(in: CGRect(x: 10, y: 10, width: rect.size.width, height: rect.size.height), withAttributes: attr)
let rotatedImageWithText = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
//Then, draw rotated image(with text) onto the background image
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), true, 0)
image.draw(in: rect)
rotatedImageWithText?.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
self.imageView.image = newImage

How to draw text above a UIImage to create a new Image

I'm attempting to create a UIImage using an existing UIImage and a String.
I've been trying to use this code within a playground:
import UIKit
let filter = CIFilter(name: "CIQRCodeGenerator")!
var data = "cat".dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
filter.setValue(data, forKey: "inputMessage")
filter.setValue("Q", forKey: "inputCorrectionLevel")
var image = filter.outputImage!
let scaleX = CGFloat(9.8)
let scaleY = CGFloat(9.8)
let img = UIImage(CIImage: image.imageByApplyingTransform(CGAffineTransformMakeScale(scaleX, scaleY)))
var textColor = UIColor.blackColor()
var textFont = UIFont(name: "Helvetica Bold", size: 12)!
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: img.size.width, height: img.size.height), false, scale)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor
]
img.drawAtPoint(CGPoint(x: 0, y: 100))
var rect = CGRectMake(0, 0, img.size.width, img.size.height)
NSString(string: "cat").drawInRect(rect, withAttributes: textFontAttributes)
var newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
Unfortunately while this does overlay text onto the existing image, since it's a QR image I'm overlaying on I would like to leave some space between the top of the QR image and the text.
I feel like this shouldn't be a difficult thing to achieve, although need some guidance.
Thank you
I realized what I was doing wrong.
The initial space that I created with this line:
UIGraphicsBeginImageContextWithOptions(CGSize(width: img.size.width, height: img.size.height), false, scale)
was limiting the height of the drawable space.
So I tried to then draw the Image 100 y lower using:
img.drawAtPoint(CGPoint(x: 0, y: 100))
although it was getting cut off.
So I then realized I needed to make the initial space taller like this:
UIGraphicsBeginImageContextWithOptions(CGSize(width: img.size.width, height: img.size.height + 100), false, scale)
Thanks!

Resources