I have got a requirement like from REST API, I will get the PDF bytes data, So, In UI I have to convert the PDF bytes data to image(.jpg) format and download into photo Album. Is it Possible in Swift4? if Possible, can share me an example code snippet.
Thanks in advance
you can save your pdf to document directory and can create thumbnail of first page
import PDFKit
func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? {
guard let data = try? Data(contentsOf: url),
let page = PDFDocument(data: data)?.page(at: 0) else {
return nil
}
let pageSize = page.bounds(for: .mediaBox)
let pdfScale = width / pageSize.width
// Apply if you're displaying the thumbnail on screen
let scale = UIScreen.main.scale * pdfScale
let screenSize = CGSize(width: pageSize.width * scale,
height: pageSize.height * scale)
return page.thumbnail(of: screenSize, for: .mediaBox)
}
Check out PDFKit in the documentation.
You can initialise a PDF document with a Data representation of a PDF (or a PDF file) and then display it in a PDFView. Given PDFView inherits from UIView, all the standard UIView functionality should be there, including methods such as
func UIImageWriteToSavedPhotosAlbum(UIImage, Any?, Selector?, UnsafeMutableRawPointer?)
which should do what it says in it's signature!
This code is working fine for my question:
GHServiceManager.shared.getPDF(fileName: self.pdfName, success: { (ssdata) in
let pdfData = ssdata as CFData
let provider:CGDataProvider = CGDataProvider(data: pdfData)!
let pdfDoc:CGPDFDocument = CGPDFDocument(provider)!
let pdfPage:CGPDFPage = pdfDoc.page(at: 1)!
var pageRect:CGRect = pdfPage.getBoxRect(.mediaBox)
pageRect.size = CGSize(width:pageRect.size.width, height:pageRect.size.height)
print("\(pageRect.width) by \(pageRect.height)")
UIGraphicsBeginImageContext(pageRect.size)
let context:CGContext = UIGraphicsGetCurrentContext()!
context.saveGState()
context.translateBy(x: 0.0, y: pageRect.size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.concatenate(pdfPage.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true))
context.drawPDFPage(pdfPage)
context.restoreGState()
let pdfImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
dukePhotoLibrary?.saveImage(image: pdfImage)
})
Related
After captured photo from camera, I was doing image compression For (400kb and 1 Mb), it look almost 3 seconds in iPhone 6 and less than a second in iPhone 6s.
Is there any way to get thumbnail and original image without doing manual compression?
Code used for image compression
Extension for UIImage
extension UIImage {
// MARK: - UIImage+Resize
func compressTo(_ expectedSizeInMb:Int) -> Data? {
let sizeInBytes = expectedSizeInMb * 1024 * 1024
var needCompress:Bool = true
var imgData:Data?
var compressingValue:CGFloat = 1.0
while (needCompress && compressingValue > 0.0) {
if let data:Data = jpegData(compressionQuality: compressingValue) {
if data.count < sizeInBytes {
needCompress = false
imgData = data
} else {
compressingValue -= 0.1
}
}
}
if let data = imgData {
if (data.count < sizeInBytes) {
return data
}
}
return nil
}
}
usage:
if let imageData = image.compressTo(1) {
print(imageData)
}
For images saved in Photos Library :
Try :
let phAsset = info[UIImagePickerController.InfoKey.phAsset] as! PHAsset
let options = PHImageRequestOptions()
options.deliveryMode = .fastFormat
options.isSynchronous = false
// you can change your target size to CGSize(width: Int , height: Int) any number you want.
PHImageManager.default().requestImage(for: phAsset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: options, resultHandler: { image , _ in
let thumbnail = image
// use your thumbnail
})
For Captured images from Camera, you can get image pixels without recalculating data count :
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
// pixels are the same on each device’s camera
let widthPixels = image.size.width * image.scale
let heightPixels = image.size.height * image.scale
let sizeInBytes = 1024 * 1024
var thumbnail : UIImage! = nil
if Int(widthPixels * heightPixels) > sizeInBytes {
// assign custom width and height you need
let rect = CGRect(x: 0.0, y: 0.0, width: 100, height: 100)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 1)
let context = UIGraphicsGetCurrentContext()
context?.interpolationQuality = .low
image.draw(in: rect)
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
thumbnail = resizedImage
} else {
thumbnail = image
}
I am trying to create a collection view that shows all the pdfs the user has. The cell shows a preview image of the first page of the pdf. I am able to render an image but it is black.
I have tried different ways to show a pdf as a UIImageView but this is the only one that has been able to show something on screen.
func displayContent(document: DocumentModel) {
let pdf: CGPDFDocument = CGPDFDocument(Bundle.main.url(forResource: document.title, withExtension: ".pdf")! as CFURL)!
let pdfPage = pdf.page(at: 1)
let pageRect = pdfPage?.getBoxRect(.mediaBox)
let renderer = UIGraphicsImageRenderer(size: pageRect!.size)
let data = renderer.jpegData(withCompressionQuality: 0.5, actions: { cnv in
//UIColor.white.set()
cnv.fill(pageRect!)
cnv.cgContext.translateBy(x: 0.0, y: pageRect!.size.height)
cnv.cgContext.scaleBy(x: 1.0, y: -1.0)
cnv.cgContext.drawPDFPage(pdfPage!)
})
self.previewImage.contentMode = .scaleAspectFit
self.previewImage.clipsToBounds = true
self.previewImage.image = UIImage(data: data)
self.documentTitle.text = document.title
}
I should be seeing a lower quality image but I am just seeing a black box instead.
I was able to solve this problem by using this code from hacking with swift
This is the code from the website:
func drawPDFfromURL(url: URL) -> UIImage? {
guard let document = CGPDFDocument(url as CFURL) else { return nil }
guard let page = document.page(at: 1) else { return nil }
let pageRect = page.getBoxRect(.mediaBox)
let renderer = UIGraphicsImageRenderer(size: pageRect.size)
let img = renderer.image { ctx in
UIColor.white.set()
ctx.fill(pageRect)
ctx.cgContext.translateBy(x: 0.0, y: pageRect.size.height)
ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
ctx.cgContext.drawPDFPage(page)
}
return img
}
How to image write in pdf through html in Swift 4?
func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String
{
let fmt = UIMarkupTextPrintFormatter(markupText: sampleHTML)
// 2. Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
render.drawPrintFormatter(formmatter, forPageAt: 0)
// 3. Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
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
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
UIGraphicsBeginImageContext(CGSize.zero)
for i in 1...render.numberOfPages
{
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(documentsPath)
if pdfData.write(toFile: "\(documentsPath)/file.pdf", atomically: true)
{
pdfFilePath = "\(documentsPath)/file.pdf"
var URL = NSURL(fileURLWithPath: pdfFilePath!)
storedPdfFileData = try! Data(contentsOf:URL as URL)
fileName = URL.lastPathComponent
print("FileName\(fileName!)")
self.UserDefaultForfileName.setValue(self.fileName, forKey: "FILE")
}
else
{
print("choose how to handle error here")
}
return pdfFilePath!
}
If we have correctly understood, we can see two different requirements from your comments
1) you want to save the html pages to pdf.
or
2) you want to create pdf from images (list of UIImage).
for 1st approach:-
You should be using WKWebView to show html pages in your viewController. ( To know how to use WKWebView, you may search help from Stackoverflow. ) In the viewControler, you can have Button click event for 'printWebPagetoPDF" function. The function is as under.
func printWebPagetoPDF( theHeight:CGFloat = 0 ) {
var isHeightFound = true
let deviceW = UIScreen.main.bounds.size.width
let deviceH = UIScreen.main.bounds.size.height
let width = min(deviceW, deviceH)
var height = theHeight
if height <= 0 {
height = max(deviceW, deviceH)
isHeightFound = false
}
let fileParentPath = "<absolute path to save pdf file>" + "/"
let inDateTimeFormatter = DateFormatter()
inDateTimeFormatter.dateFormat = "yyyyMMddHHmm"
let dateTimeFileString = "test\(inDateTimeFormatter.string(from: Date()))"
let pdfFileName = dateTimeFileString + ".pdf"
let sharePdfFilePath = fileParentPath + pdfFileName
// - 1 - Grab the webView's print context
let fmt = myWKWebView.viewPrintFormatter()
fmt.perPageContentInsets = UIEdgeInsetsMake(10, 10, 10, 10) //Page margins
// - 2 - Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
// - 3 - Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: width, height: height) //width: 841.85, height: 595.22) //Page size
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, page, nil)
print( render.numberOfPages )
render.prepare(forDrawingPages: NSMakeRange(0, render.numberOfPages-1))
for i in 0..<render.numberOfPages {
UIGraphicsBeginPDFPage()
render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
// - 5 - Save the PDF file
let path = sharePdfFilePath
pdfData.write(toFile: path, atomically: true)
}
for 2nd approach:-
You may try following code to create pdf from images. I have not tested it properly, but you can try yourselves. mySelectedArray is the sequence of indexes of images to add in pdf. dataArray is array of UIImages. "import PDFKit" is required on start of swift file.
// The url to save the data to
let pdfFileName = "<some path>" + "/" + "test.pdf"
let url = URL(fileURLWithPath: pdfFileName)
if #available(iOS 11.0, *) {
// Create an empty PDF document
let pdfDocument = PDFDocument()
pdfDocument.delegate = self
for index in mySelectedArray {
// Load or create your UIImage
let image = dataArray[index].image
// Create a PDF page instance from your image
let pdfPage = PDFPage(image: image)
// Insert the PDF page into your document
pdfDocument.insert(pdfPage!, at: 0)
}
// Get the raw data of your PDF document
let data = pdfDocument.dataRepresentation()
// Save the data to the url
try! data!.write(to: url)
}
If possible, please comment clearly, for any further assistance.
I'm trying to resize a CVPixelBuffer to a size of 128x128. I'm working with one that is 750x750. I'm currently using the CVPixelBuffer to create a new CGImage, which I resize then convert back into a CVPixelBuffer. Here is my code:
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
let imageRect = CGRect(x: 0, y: 0, width: 128, height: 128)
if let image = context.createCGImage(ciImage, from: imageRect) {
let t = CIImage(cgImage: image)
let new = t.applying(transformation)
context.render(new, to: pixelBuffer)
return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .right)
}
}
return nil
}
I've also tried scaling the CIImage then converting it:
let t = CIImage(cgImage: image)
let transformation = CGAffineTransform(scaleX: 1, y: 2)
let new = t.applying(transformation)
context.render(new, to: pixelBuffer)
But that didn't work either.
Any help is appreciated. Thanks!
There's no need for pixel buffer rendering and alike. Just transform the original CIImage and crop to size. Cropping is necessary if you source and destination dimensions aren't proportional.
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let srcWidth = CGFloat(ciImage.extent.width)
let srcHeight = CGFloat(ciImage.extent.height)
let dstWidth: CGFloat = 128
let dstHeight: CGFloat = 128
let scaleX = dstWidth / srcWidth
let scaleY = dstHeight / srcHeight
let scale = min(scaleX, scaleY)
let transform = CGAffineTransform.init(scaleX: scale, y: scale)
let output = ciImage.transformed(by: transform).cropped(to: CGRect(x: 0, y: 0, width: dstWidth, height: dstHeight))
return UIImage(ciImage: output)
}
return nil
}
Try this
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let resizedCIImage = ciImage.applying(CGAffineTransform(scaleX: 128.0 / 750.0, y: 128.0 / 750.0))
let context = CIContext()
if let image = context.createCGImage(resizedCIImage, from: resizedCIImage.extent) {
return UIImage(cgImage: image)
}
}
return nil
}
Here I assume that pixel buffer is square and size is equal to 750x750, you can change it to work with all aspect ratios and sizes
I have an iOS app that I am now creating for Mac OSX. I have the code below that converts the image to a size of 1024 and works out the width based on the aspect ratio of the image. This works on iOS but obviously does not on OSX. I am not sure how to create a PNG representation of the NSImage or what I should be using instead of UIGraphicsBeginImageContext. Any suggestions?
Thanks.
var image = myImageView.image
let imageData = UIImagePNGRepresentation(image)
let imageWidth = image?.size.width
let calculationNumber:CGFloat = imageWidth! / 1024.0
let imageHeight = image?.size.height
let newImageHeight = imageHeight! / calculationNumber
UIGraphicsBeginImageContext(CGSizeMake(1024.0, newImageHeight))
image?.drawInRect(CGRectMake(0, 0, 1024.0, newImageHeight))
var resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let imageData = UIImagePNGRepresentation(resizedImage)
let theImageData:NSData = UIImagePNGRepresentation(resizedImage)
imageFile = PFFile(data: theImageData)
You can use:
let image = NSImage(size: newSize)
image.lockFocus()
//draw your stuff here
image.unlockFocus()
if let data = image?.TIFFRepresentation {
let imageRep = NSBitmapImageRep(data: data)
let imageData = imageRep?.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
//do something with your PNG data here
}
my two cents...
a quick extension to draw an image with a partially overlapped image:
extension NSImage {
func mergeWith(anotherImage: NSImage) -> NSImage {
self.lockFocus()
//draw your stuff here
self.draw(in: CGRect(origin: .zero, size: size))
let frame2 = CGRect(x: 4, y: 4, width: size.width/3, height: size.height/3)
anotherImage.draw(in: frame2)
self.unlockFocus()
return self
}
}
final effect: