in 1 function take 2 screenshots of different size images - swift

I want my swift code below to take 2 screenshots. One screen shot should be the entire view from the top to 20 percent and the other from 20 percent to 100 percent of the height. I created a image that displays what exactly I am looking for. The images should have different ratios. I dont really know what else to add.
var drawbox = Canvas()
#objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
#objc func saving(){
let vex = self.view.screenshot(for: drawbox.frame, clipToBounds: true)
UIImageWriteToSavedPhotosAlbum(vex, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
extension UIView {
/// Takes a screenshot of a UIView, with an option to clip to view bounds and place a waterwark image
/// - Parameter rect: offset and size of the screenshot to take
/// - Parameter clipToBounds: Bool to check where self.bounds and rect intersect and adjust size so there is no empty space
/// - Parameter watermark: UIImage of the watermark to place on top
func screenshot(for rect: CGRect, clipToBounds: Bool = true, with watermark: UIImage? = nil) -> UIImage {
var imageRect = rect
if clipToBounds {
imageRect = bounds.intersection(rect)
}
return UIGraphicsImageRenderer(bounds: imageRect).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
watermark?.draw(in: CGRect(origin: imageRect.origin, size: CGSize(width: 32, height: 32))) // update origin to place watermark where you want, with this update it will place it in top left or screenshot.
}
}
}

you can split the image after saving it I use this function to split the image into two half you can change the ratio
extension UIImage {
func topHalf(pers:CGFloat)-> UIImage? {
guard let image = cgImage?
.cropping(to: CGRect(origin: .zero,
size: CGSize(width: size.width * scale,
height: (size.height * scale) * pers )))
else { return nil }
return UIImage(cgImage: image, scale: 1, orientation: imageOrientation)
}
func bottomHalf(pers:CGFloat)-> UIImage? {
let scaledHight = (size.height * scale)
guard let image = cgImage?
.cropping(to: CGRect(origin: CGPoint(x: 0,
y: scaledHight - (scaledHight * pers).rounded()),
size: CGSize(width: size.width * scale,
height: scaledHight)))
else {
print("Null")
return nil }
return UIImage(cgImage: image)
}
func save(_ name: String) {
// let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let path = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = URL(fileURLWithPath: path.path).appendingPathComponent(name)
try! self.pngData()?.write(to: url)
print("saved image at \(url)")
}
}
you can use it like this
let vex = self.view.screenshot(for: self.view.frame, clipToBounds: true)
vex .save("full.png")
let top = vex.topHalf(pers: 0.2)
top?.save("Top.png")
let bottom = vex.bottomHalf(pers: 0.8)
bottom?.save("bottom.png")

Related

PDF Thumbnail Generator Always Returning Nil | Swift/Xcode

Would someone please explain to me why this pdf generator I'm attempting to use is always returning nil? I'm attempting to get a thumbnail to display in a UITableView alongside the filename of the PDF. Unfortunately, out of the four or so thumbnail generators I've tried, none of them have returned anything other than nil.
func uploadPDF() {
let types = UTType.types(tag: "pdf",
tagClass: UTTagClass.filenameExtension,
conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: types)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 0)
self.modelController.bidPDFUploadThumbnails.append(thumbnail!)
}
tableView.reloadData()
}
func thumbnailFromPdf(withUrl url:URL, pageNumber:Int, width: CGFloat = 240) -> UIImage? {
guard let pdf = CGPDFDocument(url as CFURL),
let page = pdf.page(at: pageNumber)
else {
return nil
}
var pageRect = page.getBoxRect(.mediaBox)
let pdfScale = width / pageRect.size.width
pageRect.size = CGSize(width: pageRect.size.width*pdfScale, height: pageRect.size.height*pdfScale)
pageRect.origin = .zero
UIGraphicsBeginImageContext(pageRect.size)
let context = UIGraphicsGetCurrentContext()!
// White BG
context.setFillColor(UIColor.white.cgColor)
context.fill(pageRect)
context.saveGState()
// Next 3 lines makes the rotations so that the page look in the right direction
context.translateBy(x: 0.0, y: pageRect.size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.concatenate(page.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true))
context.drawPDFPage(page)
context.restoreGState()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
Generator source: Thumbnail Generator
the pdf document starts from page 1 not 0 because its not an array.
so simple is
let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 1)
you'll get it
rather than using page number you can direct access the thumbnail of by default first page as follow:
import PDFKit
func generatePdfThumbnail(of thumbnailSize: CGSize , for documentUrl: URL, atPage pageIndex: Int) -> UIImage? {
let pdfDocument = PDFDocument(url: documentUrl)
let pdfDocumentPage = pdfDocument?.page(at: pageIndex)
return pdfDocumentPage?.thumbnail(of: thumbnailSize, for: PDFDisplayBox.trimBox)
}

Turn AsyncImage to UIImage

I got an AsyncImage and want to use UIImageWriteToSavedPhotosAlbum for save my AsyncImage to user library.
I used Paul Hudson course for find what to do but it downloads an empty white picture on library on my iPhone and on simulator.
Here's the code:
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .blue
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}`
On the view:
`Button("Save to image") {
let image = AstronomyImageView(astronomy: article) //AsyncImage
let uiImage: UIImage = image.snapshot()
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}```

Vision – Face recognition performed but correct coordinates cannot be obtained

Swift 5, Xcode 11, iOS 13.0.
In the code below, we will get the face from the image 'test', recognize the left eye, and display 'num' at its coordinates.
However, the coordinates of the nose are not displayed at the correct position.
I'm in trouble because I don't know the solution. I would be grateful if you could tell me.
import Vision
import Foundation
import SwiftUI
struct ContentView: View {
#ObservedObject var faceGet = test()
#State var uiimage : UIImage? = nil
var body: some View {
VStack{
if uiimage != nil {
Image(uiImage: uiimage!).resizable().scaledToFit()
}
Divider()
Button(action: {
self.uiimage = self.faceGet.faceCheck()
}){
Text("Tap image to see result")
}
}
}
}
class test :ObservableObject{
private var originalImage = UIImage(named: "test3")
func faceCheck() -> UIImage?{
var drawnImage : UIImage? = originalImage
let request = VNDetectFaceLandmarksRequest { (request, error) in
for observation in request.results as! [VNFaceObservation] {
if let landmark = observation.landmarks?.nose{
for i in 0...landmark.pointCount - 1 {
drawnImage = self.drawText(
image: drawnImage!,
point: landmark.pointsInImage(imageSize: self.originalImage!.size) [i] ,
num: i)
}
}
}
}
if let cgImage = self.originalImage?.cgImage {
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
try? handler.perform([request])
}
return drawnImage
}
func drawText(image :UIImage , point:CGPoint , num:Int ) ->UIImage
{
let text = num.description
var newImage : UIImage? = nil
let fontSize = image.size.height / image.size.width * 10
let font = UIFont.boldSystemFont(ofSize: fontSize)
let textWidth = CGFloat(round(text.widthOfString(usingFont: font)))
let textHeight = CGFloat(round(text.heightOfString(usingFont: font)))
let imageRect = CGRect(origin: .zero, size: image.size)
UIGraphicsBeginImageContext(image.size);
image.draw(in: imageRect)
let rePoint :CGPoint = CGPoint(x:imageRect.maxX - CGFloat(round(point.x)),
y:imageRect.maxY - CGFloat(round(point.y)))
let textRect = CGRect(origin: rePoint, size: CGSize(width: textWidth , height: textHeight ))
let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
let textFontAttributes = [
NSAttributedString.Key.font: font,
NSAttributedString.Key.foregroundColor: UIColor.red,
NSAttributedString.Key.paragraphStyle: textStyle
]
text.draw(in: textRect, withAttributes: textFontAttributes)
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
return newImage!
}
}
extension String {
public func widthOfString(usingFont font: UIFont) -> CGFloat {
let attributes = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: attributes)
return size.width
}
public func heightOfString(usingFont font: UIFont) -> CGFloat {
let attributes = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: attributes)
return size.height
}
}

ScreenShot issue in ARKit in swift

i have application that uses ARSCNView. i'm trying to take a screenshot on click of a button and saved that image in the gallery. But when i take a screenshot it does not show the content on that screen. Just show that image, i have some labels on it but it does not show that in an image. This is my code,
#IBAction func captureImage(_ sender: Any) {
image = sceneView.snapshot()
UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
}
How can i show that labels and buttons on ARSCView in a screenshot?
snapshot() will only take screenshot of Scene.
To take screenshot of Scene with Labels and Buttons use below method:
func snapshot(of rect: CGRect? = nil) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.isOpaque, 0)
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true)
let fullImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let image = fullImage, let rect = rect else { return fullImage }
let scale = image.scale
let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale)
guard let cgImage = image.cgImage?.cropping(to: scaledRect) else { return nil }
return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}
To Take Screenshot:
#IBAction func takeScreenShotTapped(_ sender: Any) {
let screenShot = snapshot(of: CGRect(x: 80, y: 80, width: 100, height: 100))
}
If you want to take screenshot of fullscreen then just call snapshot().
Hope this will help you :)

How to crop image swift

in my project i have a UIImageView with square format for the image of the user profile, but when i add an image for example from the library, it appears shapeless. I have finded a code to crop the images to square format but i don't understand where to insert it in my code to crop the selected image from library or a new photo. Can you help me?
Here the code:
ImageUtil.swift
import UIKit
class ImageUtil: NSObject {
func cropToSquare(image originalImage: UIImage) -> UIImage {
// Create a copy of the image without the imageOrientation property so it is in its native orientation (landscape)
let contextImage: UIImage = UIImage(CGImage: originalImage.CGImage)!
// Get the size of the contextImage
let contextSize: CGSize = contextImage.size
let posX: CGFloat
let posY: CGFloat
let width: CGFloat
let height: CGFloat
// Check to see which length is the longest and create the offset based on that length, then set the width and height of our rect
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
posY = 0
width = contextSize.height
height = contextSize.height
} else {
posX = 0
posY = ((contextSize.height - contextSize.width) / 2)
width = contextSize.width
height = contextSize.width
}
let rect: CGRect = CGRectMake(posX, posY, width, height)
// Create bitmap image from context using the rect
let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, rect)
// Create a new image based on the imageRef and rotate back to the original orientation
let image: UIImage = UIImage(CGImage: imageRef, scale: originalImage.scale, orientation: originalImage.imageOrientation)!
return image
}
}
AddController.swift
import UIKit
class AddController: UIViewController, UITextFieldDelegate, CameraManagerDelegate {
#IBOutlet var immagine: UIImageView!
#IBOutlet var fieldNome: UITextField!
var immagineSelezionata : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.navigationBar.barStyle = UIBarStyle.BlackTranslucent
navigationController!.navigationBar.tintColor = UIColor.whiteColor()
navigationController!.navigationBar.barTintColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
//navigationItem.titleView = UIImageView(image: UIImage(named: "logo"))
//tableView.backgroundColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)
let singleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "selezionaFoto:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
self.immagine.addGestureRecognizer(singleTap)
self.immagine.userInteractionEnabled = true
fieldNome.delegate = self
CameraManager.sharedInstance.delegate = self
var keyboardToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.bounds.size.width, 44))
keyboardToolbar.barStyle = UIBarStyle.BlackTranslucent
keyboardToolbar.backgroundColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
keyboardToolbar.tintColor = UIColor.whiteColor()
var flex = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
var save = UIBarButtonItem(title: NSLocalizedString("Done", comment: ""),
style: UIBarButtonItemStyle.Done,
target: fieldNome,
action: "resignFirstResponder")
keyboardToolbar.setItems([flex, save], animated: false)
fieldNome.inputAccessoryView = keyboardToolbar
}
func myUIImageViewTapped(recognizer: UITapGestureRecognizer) {
if(recognizer.state == UIGestureRecognizerState.Ended){
println("myUIImageView has been tapped by the user.")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func annulla(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func salva(sender: UIBarButtonItem) {
if fieldNome.text.isEmpty
{
return
}
var profilo = ProfiloModel(nomeIn: fieldNome.text,
immagineIn: UIImage(named:"icon-profile")!)
if let img = immagineSelezionata {
profilo.immagine = img
}
//DataManager.sharedInstance.storage.insert(profilo, atIndex: 0)
DataManager.sharedInstance.storage.append(profilo)
DataManager.sharedInstance.salvaArray()
DataManager.sharedInstance.master.tableView.reloadData()
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func selezionaFoto(sender: UITapGestureRecognizer) {
fieldNome.resignFirstResponder()
func selezionaLibreria(action : UIAlertAction!) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true)
CameraManager.sharedInstance.newImageFromLibraryForController(self, editing: false)
}
func scattaFoto(action : UIAlertAction!) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true)
var circle = UIImageView(frame: UIScreen.mainScreen().bounds)
circle.image = UIImage(named: "overlay")
CameraManager.sharedInstance.newImageShootForController(self, editing: false, overlay:circle)
}
var myActionSheet = UIAlertController(title: NSLocalizedString("ACTION_IMAGE_TITLE", comment: ""),
message: NSLocalizedString("ACTION_IMAGE_TEXT", comment: ""),
preferredStyle: UIAlertControllerStyle.ActionSheet)
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_LIBRARY", comment: ""),
style: UIAlertActionStyle.Default,
handler: selezionaLibreria))
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_SHOOT", comment: ""),
style: UIAlertActionStyle.Default,
handler: scattaFoto))
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_CANCEL", comment: ""),
style: UIAlertActionStyle.Cancel,
handler: nil))
self.presentViewController(myActionSheet, animated: true, completion: nil)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder() // chiudere la tastiera nei campi di testo
return true
}
func incomingImage(image: UIImage) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
immagine.image = image
immagineSelezionata = image
}
func cancelImageSelection() {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
}
}
I Found a link can help you
CGBitmapContextCreate & CGContextDrawImage
Core Graphics / Quartz 2D offers a lower-level set of APIs that allow for more advanced configuration. Given a CGImage, a temporary bitmap context is used to render the scaled image, using CGBitmapContextCreate() and
CGBitmapContextCreateImage():
let image = UIImage(contentsOfFile: self.URL.absoluteString!).CGImage
let width = CGImageGetWidth(image) / 2.0
let height = CGImageGetHeight(image) / 2.0
let bitsPerComponent = CGImageGetBitsPerComponent(image)
let bytesPerRow = CGImageGetBytesPerRow(image)
let colorSpace = CGImageGetColorSpace(image)
let bitmapInfo = CGImageGetBitmapInfo(image)
let context = CGBitmapContextCreate(nil, width, height,
bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)
CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
CGContextDrawImage(context, CGRect(origin: CGPointZero, size: CGSize(width: CGFloat(width), height: CGFloat(height))), image)
let scaledImage = UIImage(CGImage: CGBitmapContextCreateImage(context))
CGBitmapContextCreate takes several arguments to construct a context with desired dimensions and amount of memory for each channel within a given colorspace. In the example, these values are fetched from the CGImage. Next, CGContextSetInterpolationQuality allows for the context to interpolate pixels at various levels of fidelity. In this case, kCGInterpolationHigh is passed for best results. CGContextDrawImage allows for the image to be drawn at a given size and position, allowing for the image to be cropped on a particular edge or to fit a set of image features, such as faces. Finally, CGBitmapContextCreateImage creates a CGImage from the context.
Font Image Resizing Techiniques
See Image-Cropper.
Excerpt:
func btnCropAndSaveClicked(sender: UIButton!) {
print("save btn clicked")
let scale = 1 / scrollView.zoomScale
let visibleRect = CGRect(
x: (scrollView.contentOffset.x + scrollView.contentInset.left) * scale,
y: (scrollView.contentOffset.y + scrollView.contentInset.top) * scale,
width: CROP_WINDOW_WIDTH * scale,
height: CROP_WINDOW_HEIGHT * scale)
let imageRef: CGImageRef? = CGImageCreateWithImageInRect(processedImage.CGImage, visibleRect)!
let croppedImage:UIImage = UIImage(CGImage: imageRef!)
UIImageWriteToSavedPhotosAlbum(croppedImage, nil, nil, nil)
showResultMessage()
}
That code allows you to zoom in and out the selected picture, move it around and crop the desired area of that picture. It's simple to implement, everything is done on the ViewController. Hope this solves your problem.