Add text to a point in image swift - ios

I am using UITapGestureRecognizer to get coordinates in a UIImageView, then use that coordinates as a position where to add text to image. The problem the text was not added exactly to where I touched on UIImageView
Could you help me to solve problem or give me some suggest
#IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
imageView.image = UIImage(named: documentsPath + "/bach.jpg")
let imageViewTapped = UITapGestureRecognizer(target: self, action: #selector(self.tapAction(_:)))
imageViewTapped.numberOfTouchesRequired = 1
imageViewTapped.delegate = self
imageView.addGestureRecognizer(imageViewTapped)
}
func tapAction(_ sender: UITapGestureRecognizer) {
let point = sender.location(in: self.imageView)
print("x \(point.x) y \(point.y) ")
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let image = UIImage(named: documentsPath + "/bach.jpg")!
let newImage = textToImage(drawText: "㊗️Hello", inImage: image, atPoint: CGPoint(x: point.x, y: point.y))
imageView.image = newImage
}
// Add text to image
func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 300)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
] as [String : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
text.draw(at: point, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}

class ViewController1: UIViewController {
let lblNew = UILabel()
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
imageView.image = UIImage(named: documentsPath + "/bach.jpg")
imageView.isUserInteractionEnabled = true
let imageViewTapped = UITapGestureRecognizer(target: self, action: #selector(self.tapAction(_:)))
imageViewTapped.numberOfTouchesRequired = 1
imageViewTapped.delegate = self as? UIGestureRecognizerDelegate
imageView.addGestureRecognizer(imageViewTapped)
}
func tapAction(_ sender: UITapGestureRecognizer) {
let point = sender.location(in: self.imageView)
print("x \(point.x) y \(point.y) ")
textToImage(drawText: "㊗️Hello", atPoint: CGPoint(x: point.x, y: point.y))
}
// Add text to image
func textToImage(drawText text: NSString, atPoint point: CGPoint) {
lblNew.frame = CGRect(x: point.x, y: point.y, width: 200.0, height: 10)
lblNew.textAlignment = .left
lblNew.text = text as String
lblNew.textColor = UIColor.white
imageView.addSubview(lblNew)
}
}

Code to save image in document directly in png format. If you want to save it in jpeg formate then just change that UIImagePNGRepresentation line into UIImageJPEGRepresentation(image, 0.9).
func saveImage()
{
if let image = UIImage(named: "test.png") {
if let data = UIImagePNGRepresentation(image) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}

Replace your saveImage method with the following code snippet.
func saveImage()
{
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, UIScreen.main.scale)
imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let data = UIImagePNGRepresentation(image!) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}

Related

How i can export WebView to PDF full screen swift iOS

I'm working on webView and there is a challenging part for me capture the full screen depending on webView content.File exported successfully but not capture the whole screen data. Webview screen contains the large data like scrollable content.Can any one guide me how I can export full screen data depending on content.See my code below.
#IBAction func exportPDF(_ sender: UIButton) {
self.webview?.exportAsPdfFromWebView()
}
extension WKWebView {
// Call this function when WKWebView finish loading
func exportAsPdfFromWebView() -> String {
let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter())
return self.saveWebViewPdf(data: pdfData)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData {
let originalBounds = self.bounds
self.bounds = CGRect(x: originalBounds.origin.x, y: bounds.origin.y, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect")
printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect")
self.bounds = originalBounds
return printPageRenderer.generatePdfData()
}
// Save pdf file in document directory
func saveWebViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("\(UUID().uuidString).pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
extension UIPrintPageRenderer {
func generatePdfData() -> NSMutableData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let printRect = UIGraphicsGetPDFContextBounds()
for pdfPage in 0 ..< self.numberOfPages {
UIGraphicsBeginPDFPage()
self.drawPage(at: pdfPage, in: printRect)
}
UIGraphicsEndPDFContext()
return pdfData
}
}

UIGraphicsBeginPDFContextToData does not show image after pdf creation

I am working on the HtmltoPDF creation. It is working fine when some image URL but not working with my server image URL.
Working URL downloaded from the google
Issue in the server image URL
I have put here my code for the pdf generation. Please find it
func exportHTMLContentToPDF(HTMLContent: String) -> String {
let printPageRenderer = IPPrintPageRenderer()
let printFormatter = UIMarkupTextPrintFormatter(markupText: HTMLContent)
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
let pdfData = drawPDFUsingPrintPageRenderer(printPageRenderer: printPageRenderer)
let str = "\(Global.kretriveUserData().firstName!.firstCharacter!)\(Global.kretriveUserData().Name!.firstCharacter!)".uppercased()
pdfFilename = "\(getDocDir())/\(str + invoiceNumber!).pdf"
pdfData?.write(toFile: pdfFilename, atomically: true)
print(pdfFilename)
return pdfFilename
}
func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, CGRect.zero, nil)
for i in 0..<printPageRenderer.numberOfPages {
UIGraphicsBeginPDFPage()
printPageRenderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
return data
}
func getDocDir() -> String {
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
}
You can find a full demo here.
Thanks,
To generate a pdf from a webView you need to prepare your HTML code, create the WebView and inject the HTML code inside the webView and in webView didFinishLoading print the HTML content inside the pdf using the same width and height of the webView.
func webViewDidFinishLoad(_ webView: UIWebView) {
let render = UIPrintPageRenderer()
render.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0);
let page = CGRect(x: 0, y: 10, width: webView.frame.size.width, height: webView.frame.size.height) // take the size of the webView
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// 4. Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(documentsPath)
pdfData.write(toFile: "\(documentsPath)/pdfName.pdf", atomically: true)
self.pdfPath = "\(documentsPath)/pdfName.pdf"
self.pdfTitle = "pdfName"
self.performSegue(withIdentifier: "showPDFSegue", sender: nil)
webView.removeFromSuperview()
self.loadingScreenViewController.view.removeFromSuperview()
}
Happy coding:)

How do I generate a PDF containing views with dimensions larger than device screen?

I have several UIViews with clear background color, and black border outlines that all resize based on values I enter in length, width, and height text fields. These views are subviews of a UIScrollView. After the views resize I create a PDF from the contents of the scroll view resulting in vectorized outlines that I can use and manipulate in Adobe Illustrator.
This process works fine when I use small dimensions for the views (i.e. 15 x 15), but when I use more ideal dimensions for my purpose (i.e. 3000 x 3000) the views extend off the bounds of the screen and the resulting PDF generated contains only a small portion of the views.
Ideally I need to be able to create much larger views and still be able to generate a PDF containing them. I'm envisioning a canvas that resizes (zooms out?) based on its contents and retains the scale of its subviews so that the resulting views in the PDF will be to-scale when viewed in Adobe Illustrator. This is my code so far:
override func viewDidLoad() {
super.viewDidLoad()
lengthTextField.delegate = self
widthTextField.delegate = self
heightTextField.delegate = self
scrollView.delegate = self
scrollView.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth,UIView.AutoresizingMask.flexibleHeight]
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 50
scrollView.zoomScale = 1
self.setupGestureRecognizer()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: 5000, height: 5000)
}
func setupGestureRecognizer() {
}
#IBAction func viewPDF(_ sender: Any) {
createPDFfrom(aView: self.scrollView.subviews[0], saveToDocumentsWithFileName: "MC.pdf")
// Create and add a PDFView to the view hierarchy.
let pdfView = PDFView(frame: self.scrollView.subviews[0].bounds)
pdfView.autoScales = true
view.addSubview(pdfView)
// Create a PDFDocument object and set it as PDFView's document to load the document in that view.
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = (documentsDirectory as NSString).appendingPathComponent("MC.pdf") as String
let pdfDocument = PDFDocument(url: URL(fileURLWithPath: filePath))!
pdfView.document = pdfDocument
let document = NSData(contentsOfFile: filePath)
let vc = UIActivityViewController(activityItems: [document as Any], applicationActivities: nil)
self.present(vc, animated: true, completion: nil)
}
func createPDFfrom(aView: UIView, saveToDocumentsWithFileName fileName: String)
{
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
aView.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + fileName
debugPrint(documentsFileName)
pdfData.write(toFile: documentsFileName, atomically: true)
}
}
#IBAction func updateDimensions(_ sender: Any) {
guard let length = NumberFormatter().number(from:
lengthTextField.text ?? "") else { return }
guard let width = NumberFormatter().number(from:
widthTextField.text ?? "") else { return }
guard let height = NumberFormatter().number(from:
heightTextField.text ?? "") else { return }
let flapHeight = CGFloat(truncating: width)/2
let lengthFloat = CGFloat(truncating: length)
let widthFloat = CGFloat(truncating: width)
let heightFloat = CGFloat(truncating: height)
UIView.animate(withDuration: 0.3) {
self.faceAWidthConstraint.constant = lengthFloat
self.faceAHeightConstraint.constant = heightFloat
self.faceBWidthConstraint.constant = widthFloat
self.faceA1HeightConstraint.constant = flapHeight
self.view.layoutIfNeeded()
}
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return scrollView.subviews[0]
}
}
I think if you use UIGraphicsPDFRenderer this might work better:
let url = URL(fileURLWithPath: filePath)
let pdfGenerator = UIGraphicsPDFRenderer(bounds: .init(x: 0, y: 0, width: 612, height: 792))
pdfGenerator.writePDF(to: url) { context in
let cgContext = context.cgContext
aView.layer.render(in: cgContext)
}
If the views are still extending outside of the PDF's bounds then you could scale the context:
cgContext.scaleBy(x: 0.25, y:0.25)

Add text to image in loop swift

I am adding text to an array of images using swift. Below is my code for the loop:
var holderClass = HolderClass()
var newImages = [UIImage]()
var counter = 0
for (index, oldImage) in holderClass.oldImages.enumerated(){
let newImage = drawTextAtLoaction(text: "testing", image: oldImage)
newImages[index] = newImage
counter+=1
if(counter == self.storyModule.getImageCount()){
completionHandler(newImages)
}
}
Here is the adding text function:
func drawTextAtLoaction(text: String, image: UIImage) -> UIImage{
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 12)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
] as [NSAttributedString.Key : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if newImage != nil{
return newImage!
}else{
return image
}
}
Intuitively this loop should take constant storage, however, as shown by the following image it takes linear storage and causes memory errors with larger numbers of images.
How can I use constant memory for such an operation?
edit: I think that I may have oversimplified this a bit. The oldImages array is really an array of images inside an object. So the initialization of old images looks as so.
class HolderClass{
private var oldImages: [UIImage]!
init(){
oldImages = [UIImage(), UIImage()]
}
}
edit 2:
This is how the image data is loaded. The following code is in viewDidLoad.
var holderClass = HolderClass()
DispatchQueue.global(qos: .background).async {
var dataIntermediate = [StoryData]()
let dataRequest:NSFetchRequest<StoryData> = StoryData.fetchRequest()
do {
dataIntermediate = try self.managedObjectContext.fetch(dataRequest)
for storyData in dataIntermediate{
var retrievedImageArray = [UIImage]()
if let loadedImage = DocumentSaveManager.loadImageFromPath(imageId: Int(storyData.id)){
retrievedImageArray.append(loadedImage)
}
holderData.oldImages = retrievedImageArray
}
}catch{
print("Failed to load data \(error.localizedDescription)")
}
}
This is the DocumentSaveManager class.
static func documentDirectoryURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
static func saveInDocumentsDirectory(foldername:String, filename: String) -> URL {
let fileURL = documentDirectoryURL().appendingPathComponent(foldername).appendingPathComponent(filename)
return fileURL
}
static func loadImageFromPath(moduleId: Int, imageId: Int) -> UIImage? {
let path = saveInDocumentsDirectory(foldername: String(describing: moduleId), filename: String(describing: imageId)).path
let image = UIImage(contentsOfFile: path)
if image == nil {
return nil // Remember to alert user
}
return image
}

How to add Image to video using GPUImage in Swift

I have some codes to add image to video using GPUImage, but somehow it doesn't work as I thought. I have searched some solution, and still have this problem.
I'm trying to merge image when a recoding is done. Now the output is just a video not with image.
Here's my code.
override func viewDidLoad(){
super.viewDidLoad
setupCamera()
}
func setupCamera(){
let myBoundSize: CGSize = UIScreen.mainScreen().bounds.size
cameraSubPreview = GPUImageView(frame: CGRectMake(0, 0, myBoundSize.width, myBoundSize.height))
cameraInput = GPUImageVideoCamera(sessionPreset: AVCaptureSessionPreset1280x720, cameraPosition: .Front)
cameraInput.horizontallyMirrorFrontFacingCamera = true
cameraInput.outputImageOrientation = .Portrait
cameraInput.addTarget(mainVideoFilter)
mainVideoFilter.addTarget(cameraSubPreview)
cameraPreview.addSubview(cameraSubPreview)
cameraInput.startCameraCapture()
}
func setupFilter(){
let logoImageForGPU = GPUImagePicture(image: logoImageView.image)
logoImageForGPU.addTarget(transformFilter)
logoImageForGPU.processImage()
// apply transform to filter
let tx: CGFloat = logoImageView.frame.size.width
let ty: CGFloat = logoImageView.frame.size.height
print("tx and ty: \(tx), \(ty)")
let t: CGAffineTransform = CGAffineTransformMakeScale(tx, ty);
transformFilter.affineTransform = t
transformFilter.addTarget(mainVideoFilter, atTextureLocation: 1)
}
func startRecordingVideo(sender: AnyObject) {
if(sender.state == UIGestureRecognizerState.Began) {
if !self.isRecording {
setupFilter()
let ud = NSUserDefaults.standardUserDefaults()
var IntForFilePath : Int? = ud.objectForKey("IntForFilePath") as? Int
if IntForFilePath == nil{
IntForFilePath = 10000
}
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0]
IntForFilePath = IntForFilePath! + 1
let filePath : String? = "\(documentsDirectory)/temp\(IntForFilePath!).mp4"
ud.setObject(IntForFilePath, forKey: "IntForFilePath")
// URL.
let fileURL : NSURL = NSURL(fileURLWithPath: filePath!)
//print(filePath)
self.delegate.filePathForVideo = filePath!
movieWriter = GPUImageMovieWriter(movieURL: fileURL, size: CGSize(width: 480, height: 800))
movieWriter.shouldPassthroughAudio = true
//cameraInput.addTarget(stillImageFilter)
//print("sif: \()")
stillImageFilter.addTarget(movieWriter)
cameraInput.audioEncodingTarget = movieWriter
// start recording
movieWriter.startRecording()
circle.hidden = false
drawCircleAnimation("strokeEnd", animeName: "updateGageAnimation", fromValue: 0.0, toValue: 1.0, duration: 10.0, repeat: 1, flag: false)
self.isRecording = true
}
} else if (sender.state == UIGestureRecognizerState.Ended) {
if self.isRecording {
//stop recording
movieWriter.finishRecording()
stopCircleAnimation()
self.isRecording = false
self.moveToVideoSaveView()
}
}
}
If you have any ideas could solve this, please let me know.
Thanks in advance.

Resources