Generate thumbnails for PDFs sent via share extension

This commit is contained in:
Ilya Laktyushin 2019-07-15 18:13:44 +02:00
parent 0144957e82
commit 1293d565d0
5 changed files with 42 additions and 34 deletions

View File

@ -209,7 +209,7 @@ func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<MediaResour
if resource.thumbnail { if resource.thumbnail {
let tempFile = TempBox.shared.tempFile(fileName: "thumb.jpg") let tempFile = TempBox.shared.tempFile(fileName: "thumb.jpg")
var data = Data() var data = Data()
if let image = generatePdfPreviewImage(url: url, size: CGSize(width: 320.0, height: 320.0)), let jpegData = UIImageJPEGRepresentation(image, 0.5) { if let image = generatePdfPreviewImage(url: url, size: CGSize(width: 256, height: 256.0)), let jpegData = UIImageJPEGRepresentation(image, 0.5) {
data = jpegData data = jpegData
} }
if let _ = try? data.write(to: URL(fileURLWithPath: tempFile.path)) { if let _ = try? data.write(to: URL(fileURLWithPath: tempFile.path)) {

View File

@ -3,7 +3,13 @@ import UIKit
import Display import Display
func generatePdfPreviewImage(url: URL, size: CGSize) -> UIImage? { func generatePdfPreviewImage(url: URL, size: CGSize) -> UIImage? {
guard let document = CGPDFDocument(url as CFURL) else { return nil } guard let data = try? Data(contentsOf: url, options: .mappedIfSafe) else { return nil }
return generatePdfPreviewImage(data: data, size: size)
}
func generatePdfPreviewImage(data: Data, size: CGSize) -> UIImage? {
guard let provider = CGDataProvider(data: data as CFData) else { return nil }
guard let document = CGPDFDocument(provider) else { return nil }
guard let firstPage = document.page(at: 1) else { return nil } guard let firstPage = document.page(at: 1) else { return nil }
let context = DrawingContext(size: size) let context = DrawingContext(size: size)

View File

@ -222,27 +222,25 @@ public class ShareRootControllerImpl {
let requestUserInteraction: ([UnpreparedShareItemContent]) -> Signal<[PreparedShareItemContent], NoError> = { content in let requestUserInteraction: ([UnpreparedShareItemContent]) -> Signal<[PreparedShareItemContent], NoError> = { content in
return Signal { [weak self] subscriber in return Signal { [weak self] subscriber in
switch content[0] { switch content[0] {
case let .contact(data): case let .contact(data):
let controller = deviceContactInfoController(context: context, subject: .filter(peer: nil, contactId: nil, contactData: data, completion: { peer, contactData in let controller = deviceContactInfoController(context: context, subject: .filter(peer: nil, contactId: nil, contactData: data, completion: { peer, contactData in
let phone = contactData.basicData.phoneNumbers[0].value let phone = contactData.basicData.phoneNumbers[0].value
if let vCardData = contactData.serializedVCard() { if let vCardData = contactData.serializedVCard() {
subscriber.putNext([.media(.media(.standalone(media: TelegramMediaContact(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumber: phone, peerId: nil, vCardData: vCardData))))]) subscriber.putNext([.media(.media(.standalone(media: TelegramMediaContact(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumber: phone, peerId: nil, vCardData: vCardData))))])
}
subscriber.putCompletion()
}), cancelled: {
cancelImpl?()
})
if let strongSelf = self, let window = strongSelf.mainWindow {
controller.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet)
window.present(controller, on: .root)
} }
subscriber.putCompletion() break
}), cancelled: {
cancelImpl?()
})
if let strongSelf = self, let window = strongSelf.mainWindow {
controller.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet)
window.present(controller, on: .root)
}
break
} }
return EmptyDisposable
return ActionDisposable { } |> runOn(Queue.mainQueue())
}
} |> runOn(Queue.mainQueue())
} }
let sentItems: ([PeerId], [PreparedShareItemContent], Account) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, contents, account in let sentItems: ([PeerId], [PreparedShareItemContent], Account) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, contents, account in
@ -271,17 +269,17 @@ public class ShareRootControllerImpl {
return .single(.done) return .single(.done)
} }
switch state { switch state {
case .preparing: case .preparing:
return .single(.preparing) return .single(.preparing)
case let .progress(value): case let .progress(value):
return .single(.progress(value)) return .single(.progress(value))
case let .userInteractionRequired(value): case let .userInteractionRequired(value):
return requestUserInteraction(value) return requestUserInteraction(value)
|> mapToSignal { contents -> Signal<ShareControllerExternalStatus, NoError> in |> mapToSignal { contents -> Signal<ShareControllerExternalStatus, NoError> in
return sentItems(peerIds, contents, account) return sentItems(peerIds, contents, account)
} }
case let .done(contents): case let .done(contents):
return sentItems(peerIds, contents, account) return sentItems(peerIds, contents, account)
} }
} }
} else { } else {
@ -338,7 +336,7 @@ public class ShareRootControllerImpl {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
})]) })])
strongSelf.mainWindow?.present(controller, on: .root) strongSelf.mainWindow?.present(controller, on: .root)
}, completed: {})) }, completed: {}))
} }
} }
} }

View File

@ -178,7 +178,12 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
} }
} }
} else { } else {
return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(data), mimeType: mimeType, attributes: [.FileName(fileName: fileName ?? "file")], hintFileIsLarge: data.count > 5 * 1024 * 1024) var thumbnailData: Data?
if mimeType == "application/pdf", let image = generatePdfPreviewImage(data: data, size: CGSize(width: 256.0, height: 256.0)), let jpegData = UIImageJPEGRepresentation(image, 0.5) {
thumbnailData = jpegData
}
return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(data), thumbnailData: thumbnailData, mimeType: mimeType, attributes: [.FileName(fileName: fileName ?? "file")], hintFileIsLarge: data.count > 5 * 1024 * 1024)
|> mapError { _ -> Void in return Void() } |> mapError { _ -> Void in return Void() }
|> mapToSignal { event -> Signal<PreparedShareItem, Void> in |> mapToSignal { event -> Signal<PreparedShareItem, Void> in
switch event { switch event {

View File

@ -553,7 +553,7 @@ static void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t
// add output reader to reader // add output reader to reader
[iPodAssetReader addOutput: readerOutput]; [iPodAssetReader addOutput: readerOutput];
if (! [iPodAssetReader startReading]) { if (![iPodAssetReader startReading]) {
NSLog(@"Unable to start reading!"); NSLog(@"Unable to start reading!");
return nil; return nil;
} }
@ -563,7 +563,6 @@ static void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t
int _waveformPeakCount = 0; int _waveformPeakCount = 0;
while (iPodAssetReader.status == AVAssetReaderStatusReading) { while (iPodAssetReader.status == AVAssetReaderStatusReading) {
// Check if the available buffer space is enough to hold at least one cycle of the sample data
CMSampleBufferRef nextBuffer = [readerOutput copyNextSampleBuffer]; CMSampleBufferRef nextBuffer = [readerOutput copyNextSampleBuffer];
if (nextBuffer) { if (nextBuffer) {