QLThumbnailGenerator doesn't generate the thumbnail - thumbnails

I tried using QLThumbnailGenerator in Simulator/Device for iOS and iPadOS, but it does not work.
I'am able to only obtain a standard empty thumbnail but not the rich icon from my files from documents directory.
Some progress with files in sandbox but nothing useful.
Do you make it work?
Maybe something with the permission is wrong...but what? From my app I am able to list files, and read (open) them.
#IBAction func generateDidSelect(_ sender: Any) {
let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last
print("DOC: \(docDir)")
let absPath = URL(fileURLWithPath: docDir ?? "").appendingPathComponent("flowers.png").absoluteString
//[[NSBundle mainBundle]URLForResource:#"flowers" withExtension:#"png"];
let fileURL = URL(fileURLWithPath: absPath)
fileURL.startAccessingSecurityScopedResource()
let size = CGSize(width: 200, height: 200)
let scale = UIScreen.main.scale
let isFile = fileURL.isFile()
let exists = FileManager.default.fileExists(atPath: fileURL.path)
print("isFILE? \(isFile ? "YES" : "NO") exists? \(exists ? "YES" : "NO") \nFILE: \(fileURL)")
let request = QLThumbnailGenerationRequest(fileAtURL: fileURL, size: size, scale: scale, representationTypes: QLThumbnailGenerationRequestRepresentationTypeAll)
//request.iconMode = YES;
QLThumbnailGenerator.shared().generateRepresentations(for: request, updateHandler: { thumbnail, type, error i
DispatchQueue.main.async(execute: {
print(String(format: "*** TYPE: %ld ****", Int(type)))
let uiimage = thumbnail?.uiImage
let cgImage = thumbnail?.cgImage
if let uiimage = uiimage {
print("uiimage: \(uiimage)")
}
if let cgImage = cgImage {
print("cgImage: \(cgImage)")
}
if uiimage != nil {
self.thumbnailImageView.image = uiimage
}
if error != nil {
if let error = error {
print("ERROR: \(error)")
}
//self.thumbnailImageView.image = [UIImage imageWithContentsOfFile:fileURL.path]; // test read, works
}
})
})
}
Then I tried with an image into the bundle.
Getting the file url with:
Bundle.main.url(forResource: "flowers", withExtension: "png")
and it magically works! ...but no with fileURLWithPath method.
But, accessing the same identical file uploaded via iTunes into the Documents directory of the app i get a read error.
2019-10-01 12:41:27.167091+0200 test_thumb_obj[618:57118] DOC: /var/mobile/Containers/Data/Application/BE4A5950-5D24-4620-A1FE-B837222E8B64/Documents
2019-10-01 12:41:27.196739+0200 test_thumb_obj[618:57118] isFILE? YES exists? YES
FILE: file:///var/mobile/Containers/Data/Application/BE4A5950-5D24-4620-A1FE-B837222E8B64/Documents/flowers.png
2019-10-01 12:41:27.233546+0200 test_thumb_obj[618:57118] *** TYPE: 0 ****
2019-10-01 12:41:27.233788+0200 test_thumb_obj[618:57118] uiimage:
2019-10-01 12:41:27.233858+0200 test_thumb_obj[618:57118] cgImage: (DP)
< (kCGColorSpaceDeviceRGB)>
width = 493, height = 640, bpc = 8, bpp = 32, row bytes = 1984
kCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Little | kCGImagePixelFormatPacked
is mask? No, has masking color? No, has soft mask? No, has matte? No, should interpolate? Yes
2019-10-01 12:41:27.234761+0200 test_thumb_obj[618:57118] *** TYPE: 1 ****
2019-10-01 12:41:27.234836+0200 test_thumb_obj[618:57118] uiimage: (null)
2019-10-01 12:41:27.234865+0200 test_thumb_obj[618:57118] cgImage: (null)
2019-10-01 12:41:27.234943+0200 test_thumb_obj[618:57118] ERROR: Error Domain=QLThumbnailErrorDomain Code=2 "No cached thumbnail"
2019-10-01 12:41:27.262228+0200 test_thumb_obj[618:57118] *** TYPE: 2 ****
2019-10-01 12:41:27.262317+0200 test_thumb_obj[618:57118] uiimage: (null)
2019-10-01 12:41:27.262349+0200 test_thumb_obj[618:57118] cgImage: (null)
2019-10-01 12:41:27.262452+0200 test_thumb_obj[618:57118] ERROR: Error Domain=QLThumbnailErrorDomain Code=0 "Could not generate a thum
bnail" UserInfo={NSUnderlyingError=0x281676940 {Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened."}}
The only image a get i TYPE = 0, the white empty one.
And, as before, on simulator nothing good....
Error Domain=NSPOSIXErrorDomain Code=22 "couldn't issue sandbox extension com.apple.app-sandbox.read for...
Some test i missed to make it working?

I had the same issue. I resolved it by changing representationTypes from .all to .thumbnail
let request = QLThumbnailGenerator
.Request(fileAt: fileURL, size: size, scale: scale,
representationTypes: .thumbnail)
Or if you like, you can try to create a recursion. After 20-30 calls of generateRepresentations the error "No cached thumbnail" stopped appearing and the image was available.
func thumbnail(for fileURL: URL, size: CGSize, scale: CGFloat) {
QLThumbnailGenerator.shared.generateRepresentations(for: request) { (thumbnail, type, error) in
let uiimage = thumbnail?.uiImage
if uiimage == nil {
thumbnail(fileURL, size, scale)
}
else {
//image is available
}
}
}

Solved on iOS13.2 beta.
On device ok, still read issues on simulator

This worked for me, I create this method:
import QuickLook
...
func generateThumbnailFromQuickLook(url: URL,
type: QLThumbnailGenerator.Request.RepresentationTypes,
completionHandler: #escaping (Bool, UIImage?) -> Void) {
let size = CGSize(width: 300, height: 250)
let scale = UIScreen.main.scale
let request = QLThumbnailGenerator.Request(fileAt: url,
size: size,
scale: scale,
representationTypes: type)
let generator = QLThumbnailGenerator.shared
generator.generateBestRepresentation(for: request) { thumbnail, error in
if let error = error {
print(error)
}
completionHandler(thumbnail != nil, thumbnail?.uiImage)
}
}
Then I check if the representation type thumbnail fail. If it fails, I try to get the representation type all:
let url: URL = <url file>
generateThumbnailFromQuickLook(url: url, type: .thumbnail) { success, image in
if success == false {
generateThumbnailFromQuickLook(url: url, type: .all) { success, image in
// use the thumbnail here
}
} else if let image = image {
// use the thumbnail here
}
}

Related

creating PDF with WKWebView throws unknown error in swift

Following this example ( Swift: create pdf with WKWebView's createPdf - copied almost one to one), I try to create a pdf from WKWebView (I am still very amazed that it is still so catastrophically complicated (up to impossible) to create a PDF under macOS. (It's easier with php.))
However - code is
private func CreatePDF(htmlString: String) {
let width = ((21/2.54)*72)
let height = ((29.7/2.54)*72)
if let downloadDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let savePath = downloadDir.appendingPathComponent("swiftPdf").appendingPathExtension("pdf")
let webViewConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: .init(x: 0, y: 0, width: width, height: height), configuration: webViewConfiguration)
let pdfConfiguration = WKPDFConfiguration()
pdfConfiguration.rect = CGRect(x: 0.0, y: 0.0, width: width, height: height)
webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
webView.createPDF(configuration: pdfConfiguration) { result in
switch result {
case .success(let data):
do {
try data.write(to: savePath)
print("Successfully created and saved pdf…")
} catch let error {
print("Could not _save_ pdf: \(error)")
}
case .failure(let error): // <<-- always comes out here with error
print("Could not create pdf: \(error)")
}
}
}
}
}
The console tells
failure(Error Domain=WKErrorDomain Code=1 "An unknown error occurred" UserInfo={NSLocalizedDescription=An unknown error occurred.})
Could not create pdf: Error Domain=WKErrorDomain Code=1 "An unknown error occurred." UserInfo={NSLocalizedDescription=An unknown error occurred.}
Wonderful errormessage. :-)
But what ist the problem now?

Swift Memory Crash From Selecting Image

I have users enter a profile picture in an Enter Photo Controller as apart of registration. 90% of the time it doesn't crash when the user selects a photo from the Image Picker Controller. The error says that it's a memory error.
I thought resizing was supposed to fix the problem, yet it persists.
I am using Firestore as a backend.
Any ideas on why this is happening? I'm going insane trying to figure this out!
extension EnterPhotoController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
weak var selectedImage = info[.originalImage] as? UIImage
let selectedImage2 = selectedImage?.resized(maxSize: CGSize(width: 500, height: 500))
let imageButton = (picker as? CustomImagePickerController)?.imageBttn
imageButton?.setImage(selectedImage2?.withRenderingMode(.alwaysOriginal), for: .normal)
self.imageFull = true
dismiss(animated: true)
self.errorLabel.text = "Registering, hang tight..."
self.errorLabel.isHidden = false
self.selectPhotoButton.isEnabled = false
let filename = UUID().uuidString
let ref = Storage.storage().reference(withPath: "/images/\(filename)")
guard let imageData = selectedImage2?.jpegData(compressionQuality: 0.9) else { return }
ref.putData(imageData, metadata: nil) { (nil, err) in
guard err == nil else { return }
ref.downloadURL { (url, err) in
guard err == nil else { return }
let imageUrl = url?.absoluteString ?? ""
if imageUrl == "" {
print("fuck me man")
}
self.saveInfoToFirestore(imageUrl: imageUrl)
}
}
}
}
extension UIImage {
public func resized(maxSize: CGSize) -> UIImage? {
let imageSize = self.size
guard imageSize.height > 0, imageSize.width > 0 else { return nil }
let ratio = min(maxSize.width/imageSize.width, maxSize.height/imageSize.height)
let newSize = CGSize(width: imageSize.width*ratio, height: imageSize.height*ratio)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image(actions: { (ctx) in
self.draw(in: CGRect(origin: .zero, size: newSize))
})
}
}
And from memory (my memory) I believe this is the error. I can't reproduce it.
malloc: Heap corruption detected, free list is damaged at 0x280165460 *** Incorrect guard value: 10751132320 "app-name"(945,0x16f5df000) malloc: *** set a breakpoint in malloc_error_break to debug
I'm not sure if my issue was similar, but I went crazy over figuring my issue out. I was trying to add custom metadata with spaces in them. So if you're adding any custom metadata, take out the spaces. Just a possibility this is your problem, I can't see your upload code.

Play a Video in Collection View failed

I am working on an app where I am getting videos from a firebase link.
To be able to display and play the video I am using this extension:
func generateThumbnailForVideoAtURL(filePathLocal: NSString) -> UIImage? {
let vidURL = NSURL(fileURLWithPath:filePathLocal as String)
let asset = AVURLAsset(url: vidURL as URL)
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
let timestamp = CMTime(seconds: 1, preferredTimescale: 60)
do {
let imageRef = try generator.copyCGImage(at: timestamp, actualTime: nil)
return UIImage(cgImage: imageRef)
} catch let error as NSError {
print("Image generation failed with error \(error)")
return nil
}
}
And then using it like this in cellAtIndexPath:
if posts[indexPath.row].videoUrl != nil {
cell.videoView.generateThumbnailForVideoAtURL(filePathLocal: self.posts[indexPath.row].videoUrl as! NSString)
print("VIDEO IS: \(posts[indexPath.row].videoUrl)")
}
I am getting this error:
Image generation failed with error Error Domain=NSURLErrorDomain Code=-1102 "You do not have permission to access the requested resource." UserInfo={NSLocalizedDescription=You do not have permission to access the requested resource., NSUnderlyingError=0x1c4046ff0 {Error Domain=NSOSStatusErrorDomain Code=-12660 "(null)"}}
It seems like a UserInfo description, but I can not find anything in my plist to add for permission. It may just sound stupid for somebody else because this is how I feel now as I can't find a way to make it work. Please help!
You should use this
let vidURL = URL(string:filePathLocal as String)
instead of
let vidURL = NSURL(fileURLWithPath:filePathLocal as String)

Firebase Storage Download Response Error

I have been able to successfully upload images to firebase storage but have been unable to successfully download the image.
I have attempted to download images in all three of the suggested ways on Firebase Storage Guides:
1) Download to NSData in memory
2) Download to an NSURL representing a file on device
3) Generate an NSURL representing the file online
An example is below of two different attempts:
func loadProfileImage() {
guard let currentUser = Auth.auth().currentUser else { return }
let profilePhotoFile = "ProfileImages/" + currentUser.uid
let reference = Storage.storage().reference(withPath: profilePhotoFile)
#1st Attempt downloading to memory:
reference.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
if let error = error {
print("an error occurred: \(error)")
print("see data response: \(data)")
} else {
self.profileView.image = UIImage(data: data!)
}
}
#2nd Attempt with download url:
reference.downloadURL { (url, error) in
if let error = error {
print(error)
} else {
self.profileView.sd_setImage(with: url, placeholderImage:
#imageLiteral(resourceName: "placeHolderProfileView")) {
(image, error, type, reference2) in
print("reference location of image in the google
bucket: \(reference2)")
print("error retrieving image: \(String(describing:
error))")
print("type: \(type)")
print("image details: \(String(describing: image))")
}
}
}
}
Also tried using alamofire instead of SDWebImage to see if error code was same and it is the same see below:
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response." UserInfo={object=ProfileImages/6I2RhzFI3edYNph9J4WsaXXXX, ResponseErrorCode=100, bucket=bXXXX-production.appspot.com, NSLocalizedDescription=An unknown error occurred, please check the server response., ResponseErrorDomain=NSPOSIXErrorDomain, _kCFStreamErrorDomainKey=1, NSErrorPeerAddressKey={length = 28, capacity = 28, bytes = 0x1c1e01bb000000002607f8b040090813 ... 0000200a00000000}, _kCFStreamErrorCodeKey=100}
I have checked and rechecked the google storage bucket location and believe I have the reference location correct (using the same as the upload file path which works correctly).
Any help would be much appreciated
There you go :
func downloadImage(url : String,
completionHandler: #escaping (Bool?, UIImage?, String?) -> Void) -> Void
{
var success : Bool = false
var img : UIImage? = nil
var errorLog : String? = nil
let u = URL(string: url)
let task = URLSession.shared.dataTask(with: u!, completionHandler: { (data, response, error) in
if error != nil
{
errorLog = error?.localizedDescription
completionHandler(success, img, errorLog)
}
else
{
success = true
img = UIImage(data: data!)
completionHandler(usuccess, img, errorLog)
}
})
task.resume()
}
Get URL using :
imgReference.downloadURL { (url, error) in
guard let url = url else { return }
urlString = url.absoluteString
//do something with the urlString (such as download image)
}
Realized the error was in headers that were included when uploading the image:
I had originally listed the following with the upload, by commenting them out I was able to successfully download with SDWebImage and the suggestion from vbuzze.
let uploadMetadata = StorageMetadata()
uploadMetadata.contentType = "image/jpeg"
uploadMetadata.customMetadata = ["Profile Name" : currentUser.displayName] as? [String : String]

PNG/JPEG representation from CIImage always returns nil

I'm currently making a photo editing app.
When a photo is selected by the user, it is automatically converted into black and white using this code:
func blackWhiteImage(image: UIImage) -> Data {
print("Starting black & white")
let orgImg = CIImage(image: image)
let bnwImg = orgImg?.applyingFilter("CIColorControls", withInputParameters: [kCIInputSaturationKey:0.0])
let outputImage = UIImage(ciImage: bnwImg!)
print("Black & white complete")
return UIImagePNGRepresentation(outputImage)!
}
The problem I am having with this code is that I keep getting this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I have had my code in a slightly different configuration, but it still breaks when it gets to the UIImagePNG/JPEGRepresentation(xx) section.
Are there any ways to get the PNG or JPEG data from a CIImage for use in an image view / just UIImage in general?
Any of the other methods don't go into enough detail for what code should be used.
Just begin a new graphics context and draw your grayscale image there. iOS 10 or later you can use UIGraphicsImageRenderer, for older iOS version syntax please check edit history:
Xcode 11 • Swift 5.1
func blackWhiteImage(image: UIImage, isOpaque: Bool = false) -> Data? {
guard let ciImage = CIImage(image: image)?.applyingFilter("CIColorControls", parameters: [kCIInputSaturationKey: 0]) else { return nil }
let format = image.imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: image.size, format: format).image { _ in
UIImage(ciImage: ciImage).draw(in: CGRect(origin: .zero, size: image.size))
}.pngData()
}
You can also extend UIImage to return a grayscale image :
extension UIImage {
var coreImage: CIImage? { CIImage(image: self) }
func grayscale(isOpaque: Bool = false) -> UIImage? {
guard let coreImage = coreImage?.applyingFilter("CIColorControls", parameters: [kCIInputSaturationKey: 0]) else { return nil }
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: size, format: format).image { _ in
UIImage(ciImage: coreImage).draw(in: CGRect(origin: .zero, size: size))
}
}
}
let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))!
if let grayscale = profilePicture.grayscale(), let data = grayscale.pngData() { // or Swift 4.1 or earlier -> let data = UIImagePNGRepresentation(grayscale)
print(data.count) // 689035
}