Combining Images with Card Flip animation - ios

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.

Related

Constructing a png file out of multiple images and labels

I have a few UIImageViews and UILabels that you can drag around the screen in an editor.
The images are png's with a very high resolution (>2400px ) but on screen they might appear smaller.
I would like to produce a png file out of that screen ( which includes labels and images at certain positions), which will hold the actual sizes of these images (>2400px) .
If I just capture the screen programmatically (render), he will produce an image in the size of the screen, and it will not be transparent.
How can I construct the png file by my self by placing images and texts in whatever sizes and positions I want?
This for example :
if let image = UIImage(named: "example.png") {
if let data = UIImagePNGRepresentation(image) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
will not let you specify locations or add multiple images and texts to the file
Found a pretty simple and sweet way to do so, first you save in a dictionary all your screen elements, then you can simply add them to a file with :
let font = UIFont.boldSystemFont(ofSize: 160)
let showText:NSString = "hello world"
// setting attr: font name, color...etc.
let attr = [NSFontAttributeName: font, NSForegroundColorAttributeName:UIColor.blue]
// getting size
let sizeOfText = showText.size(attributes: attr)
let image = UIImage(named: "image.png")
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), false, 0)
// drawing our image to the graphics context
image?.draw(in: rect)
// drawing text
showText.draw(in: CGRect(x: rect.size.width/2.0, y: rect.size.height/2.0, width: rect.size.width, height: rect.size.height), withAttributes: attr)
// getting an image from it
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()

How to add multiple text to different positions on picture?

I'm currently making a camera app and I can add single text from the text field on picture.
What I want is, I want to put multiple different text to the picture. So I add 4 text field to the storyboard and now I need to change something on view controller. I tried something but couldn't solve.
I have tried with this code but it's not working.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
ImageDisplay.image = textToImage(CustomerTextBox.text!, inImage: image, atPoint: CGPoint( x: 400, y: 100)
ImageDisplay.image = textToImage(ResponsibleTextBox.text!, inImage: image, atPoint: CGPoint( x: 400, y: 200)
ImageDisplay.image = textToImage(LocationTextBox.text!, inImage: image, atPoint: CGPoint( x: 400, y: 300)
ImageDisplay.image = textToImage(DescriptionTextBox.text!, inImage: image, atPoint: CGPoint( x: 400, y: 300)
}
dismissViewControllerAnimated(true, completion: nil)
This is my screen:
and This is my working code with single textbox:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var PhotoLibrary: UIButton!
#IBOutlet weak var Camera: UIButton!
#IBOutlet weak var ImageDisplay: UIImageView!
#IBOutlet weak var CustomerTextBox: UITextField!
#IBOutlet weak var ResponsibleTextBox: UITextField!
#IBOutlet weak var LocationTextBox: UITextField!
#IBOutlet weak var DescriptionTextBox: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func PhotoLibraryAction(sender: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .PhotoLibrary
presentViewController(picker, animated: true, completion: nil)
}
#IBAction func CameraAction(sender: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .Camera
presentViewController(picker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
ImageDisplay.image = textToImage(CustomerTextBox.text!, inImage: image, atPoint: CGPoint( x: 400, y: 100))
}
dismissViewControllerAnimated(true, completion: nil)
}
func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
let textColor: UIColor = UIColor.blackColor()
let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 200)!
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Creating a point within the space that is as bit as the image.
let rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
//Now Draw the text into an image.
drawText.drawInRect(rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
}
}
In your code you are adding the text one by one and returning the full image. The process you followed is not like draw the text in the space required for text, it wrote the text on image and return the full image.
Hence modify your method to pass all the text at a time and draw all text on image and return the full image .
I am showing you the code here where i have taken static points, you can put according to your requirement.
Here is the modified code :
func textToImage(drawText: NSString, drawText1: NSString, drawText2: NSString, drawText3: NSString, inImage: UIImage, atPoint:CGPoint, atPoint1:CGPoint, atPoint2:CGPoint, atPoint3:CGPoint)->UIImage{
// Setup the font specific variables
let textColor: UIColor = UIColor.redColor();
let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 200)!
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: UIColor.redColor(),
]
let textFontAttributes1 = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: UIColor.greenColor(),
]
let textFontAttributes2 = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: UIColor.purpleColor(),
]
let textFontAttributes3 = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: UIColor.yellowColor(),
]
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Creating a point within the space that is as bit as the image.
let rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
//Now Draw the text into an image.
drawText.drawInRect(rect, withAttributes: textFontAttributes)
//text 1
let rect1: CGRect = CGRectMake(atPoint1.x, atPoint1.y, inImage.size.width, inImage.size.height)
drawText1.drawInRect(rect1, withAttributes: textFontAttributes1)
//text 2
let rect2: CGRect = CGRectMake(atPoint2.x, atPoint2.y, inImage.size.width, inImage.size.height)
drawText2.drawInRect(rect2, withAttributes: textFontAttributes2)
//text 3
let rect3: CGRect = CGRectMake(atPoint3.x, atPoint3.y, inImage.size.width, inImage.size.height)
drawText3.drawInRect(rect3, withAttributes: textFontAttributes3)
// Create a new image out of the images we have created
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
}
And call the method from the same place where are you doing it currently, but like this
ImageDisplay.image = textToImage(CustomerTextBox.placeholder!, drawText1: ResponsibleTextBox.placeholder!, drawText2: LocationTextBox.placeholder!, drawText3: DescriptionTextBox.placeholder!, inImage: image, atPoint: CGPoint( x: 400, y: 100), atPoint1: CGPoint( x: 600, y: 300), atPoint2: CGPoint( x: 400, y: 600), atPoint3: CGPoint( x: 600, y: 1000));
Here the points are static for test, change it according to you.
Output :
Hope it helps.
Happy coding ...

Text size is not same when draw text on UIimage

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

Take a photo on iPhone and overlay text permanently before saving in Swift

I have just started with programming. I am trying to overlay text on an image taken with the iPhone prior to saving the image. I have found bits of code that look promising but nothing that does the job specifically, and no posts that answer the question specifically. This is my code to take an image. Without the attempt at overlaying the text I know it takes a photo.
#IBAction func handleShutterButton(sender: UIButton) {
cameraController.captureStillImage { (image, metadata) -> Void in
self.view.layer.contents = image
var project = "ProjectX"
var camNumber = "c01"
let timestamp = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .MediumStyle, timeStyle: .ShortStyle)
let overlay = "\(project) \(camNumber) \(timestamp)"
self.overlayText(overlay, inImage: UIImage(named: image)!, atPoint: CGPointMake(20, 20)) // This is where it fails
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
And this is the function I'm using for overlaying the text.
func overlayText(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
let textColor: UIColor = UIColor.whiteColor()
let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 12)!
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
//Setups up the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Creating a point within the space that is as big as the image.
let rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
//Now Draw the text into an image.
drawText.drawInRect(rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
}
Any help would be appreciated.
I have made changes in your code.. Try this..
#IBAction func handleShutterButton(sender: UIButton) {
cameraController.captureStillImage { (image, metadata) -> Void in
self.view.layer.contents = image
var project = "ProjectX"
var camNumber = "c01"
let timestamp = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .MediumStyle, timeStyle: .ShortStyle)
let overlay = "\(project) \(camNumber) \(timestamp)"
var changedImage : UIImage = self.overlayText(overlay, inImage: image, atPoint: CGPointMake(20, 20)) // This is where it fails
UIImageWriteToSavedPhotosAlbum(changedImage, nil, nil, nil);
}
}

Swift - Playground - Core Graphics / Core Text / Custom View

Question
I'm attempting to make a custom UIView component in swift playground. I've been able to figure out how to do everything except for render text correctly. I'm not sure if i'm supposed to do this via Core Graphics or Core Text or exactly how to get it working correctly.
As you can see in the image below I want to render text both upside down and right side up on either side of my custom View Component
I've tried various ways to get the text to work but I keep running aground. If somebody would be able to show me how to modify my playground to add a few text rendering that would be awesome.
Playground Code
// Playground - noun: a place where people can play
import Foundation
import UIKit
class RunwayView : UIView {
var northText : String?
var southText : String?
///Draws the "runway"
override func drawRect(rect: CGRect) {
// Setup graphics context
var ctx = UIGraphicsGetCurrentContext()
// clear context
CGContextClearRect(ctx, rect)
let parentVieBounds = self.bounds
let width = CGRectGetWidth(parentVieBounds)
let height = CGRectGetHeight(parentVieBounds)
// Setup the heights
let endZoneHeight : CGFloat = 40
/* Remember y is negative and 0,0 is upper left*/
//Create EndZones
CGContextSetRGBFillColor(ctx, 0.8, 0.8, 0.8, 1)
CGContextFillRect(ctx, CGRectMake(0, 0, width, endZoneHeight))
CGContextFillRect(ctx, CGRectMake(0, height-endZoneHeight, width, endZoneHeight))
var northString = NSMutableAttributedString(string: "36")
var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(16.0)]
var gString = NSMutableAttributedString(string:"g", attributes:attrs);
var line = CTLineCreateWithAttributedString(gString)
CGContextSetTextPosition(ctx, 10, 50);
CTLineDraw(line, ctx);
// Clean up
}
}
var outerFrame : UIView = UIView(frame: CGRectMake(20,20,400,400))
var runway1 : RunwayView = RunwayView(frame: CGRectMake(0,0,30,260))
var runway2 : RunwayView = RunwayView(frame: CGRectMake(80,0,30,340))
runway1.transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(20, 200),
CGAffineTransformMakeRotation(-0.785398163))
outerFrame.addSubview(runway1)
runway2.transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(120, 140),
CGAffineTransformMakeRotation(-0.585398163))
outerFrame.addSubview(runway2)
outerFrame.backgroundColor = UIColor.yellowColor()
outerFrame.clipsToBounds = true
// View these elements
runway1
outerFrame
runway1
I wrote a utility function for my app to draw text using CoreText.
It returns the text size for further processing:
func drawText(context: CGContextRef, text: NSString, attributes: [String: AnyObject], x: CGFloat, y: CGFloat) -> CGSize {
let font = attributes[NSFontAttributeName] as UIFont
let attributedString = NSAttributedString(string: text, attributes: attributes)
let textSize = text.sizeWithAttributes(attributes)
// y: Add font.descender (its a negative value) to align the text at the baseline
let textPath = CGPathCreateWithRect(CGRect(x: x, y: y + font.descender, width: ceil(textSize.width), height: ceil(textSize.height)), nil)
let frameSetter = CTFramesetterCreateWithAttributedString(attributedString)
let frame = CTFramesetterCreateFrame(frameSetter, CFRange(location: 0, length: attributedString.length), textPath, nil)
CTFrameDraw(frame, context)
return textSize
}
Call it like so:
var textAttributes: [String: AnyObject] = [
NSForegroundColorAttributeName : UIColor(white: 1.0, alpha: 1.0).CGColor,
NSFontAttributeName : UIFont.systemFontOfSize(17)
]
drawText(ctx, text: "Hello, World!", attributes: textAttributes, x: 50, y: 50)
Hope that helps you.

Resources