如何通过生成 pdf 的缩略图来预加载 CollectionView 中的图像?
How to preload the images in CollectionView by generating a Thumbnail of the pdf?
我想创建一个带有集合视图的 pdfReader。我想要的是有一个带有 pdf 缩略图的集合视图来显示。所以我在 viewDidLoad 中使用它(以避免每次我们向下或向上时它都会在 collectionview 中生成缩略图)。一次性生成,无延迟:
正在 viewDidLoad 中加载 pdf 的缩略图:
- (void)viewDidLoad
...
coverPdf = [NSMutableArray new];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
// Load image on a non-ui-blocking thread
NSString *pdfPath = nil;
NSURL *pdfUrl = nil;
CGPDFDocumentRef pdfRef = nil;
NSMutableArray *arr = [NSMutableArray new];
for (id cover in filePathsArray)
{
pdfPath = [categoryPath stringByAppendingPathComponent:cover];
pdfUrl = [NSURL fileURLWithPath:pdfPath];
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfUrl);
[arr addObject:[self imageFromPDFWithDocumentRef:pdfRef]];
NSLog(@"first process");
}
coverPdf = [NSMutableArray arrayWithArray:arr];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
[pdfCollectionView reloadData];
});
});
...
}
正在生成缩略图:
- (UIImage *)imageFromPDFWithDocumentRef:(CGPDFDocumentRef)documentRef
{
CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, 1);
CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, CGRectGetMinX(pageRect),CGRectGetMaxY(pageRect));
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, -(pageRect.origin.x), -(pageRect.origin.y));
CGContextDrawPDFPage(context, pageRef);
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
使用缩略图:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ListPdfCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionViewCell" forIndexPath:indexPath];
cell.productLabel.text = [filePathsArray objectAtIndex:indexPath.row];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
// Load image on a non-ui-blocking thread
dispatch_sync(dispatch_get_main_queue(), ^(void) {
// Assign image back on the main thread
if ([coverPdf count] > indexPath.row)
{
cell.pdfImage.image = [coverPdf objectAtIndex:indexPath.row];
}
});
});
return cell;
}
这个方法有两个问题:
- 第一个是缩略图显示时间过长。当它加载时,它运行良好。
- 第二个问题,内存在不断增加,即使我关闭viewcontroller,我进来了,似乎内存没有释放。如果我关闭 viewcontroller 并进入 9 或 10 次,如果应用程序崩溃。
总之,如何通过预先加载pdf的缩略图来创建集合视图以及如何避免随着内存增加而崩溃?
提前致谢。
解决方案:
由于出现时间太长,我只是把DISPATCH_QUEUE_PRIORITY_BACKGROUND换成了DISPATCH_QUEUE_PRIORITY_HIGH。好多了。
对于内存泄漏,我在循环的末尾使用了 CGPDFDocumentRelease() 函数,就像这样,一切都很顺利:
for (id cover in filePathsArray)
{
pdfPath = [categoryPath stringByAppendingPathComponent:cover];
pdfUrl = [NSURL fileURLWithPath:pdfPath];
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfUrl);
[arr addObject:[self imageFromPDFWithDocumentRef:pdfRef]];
CGPDFDocumentRelease(pdfRef);//Line added
NSLog(@"first process");
}
我有个坏消息要告诉你。内存泄漏不是你的问题而是 iOS 10 内存管理错误
There is a memory management bug in iOS 10.0.1 and 10.0.2 in the CGContextDrawPDFPage() function.
您可以在此处找到详细信息http://www.openradar.me/28415289
您还可以找到有用的讨论 https://github.com/vfr/Reader/issues/166
简而言之,可能的解决方法是不创建
CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, 1);
每次都对所有 pdf 文件使用一个 CGPDFPageRef。然后当你不再需要它时将它设置为 NULL。
创建缩略图延迟
以及创建缩略图的解决方案。我只能建议根本不要在此 VC 中执行此操作,而是在将此 .pdf 添加到应用程序时为应用程序中的每个 .pdf 创建缩略图(或者如果所有 pdf 都已存储,则在后台服务中启动应用程序时)在应用程序包中)。然后,您可以将此预览保存为 .jpg 或 .png 文件,其名称等于 pdf 名称,或者在任何数据库或其他存储中设置 pdf 和预览之间的关系(如果您的应用程序中有它)。
然后只需在您的 collectionView 中重复使用此预览。
我想创建一个带有集合视图的 pdfReader。我想要的是有一个带有 pdf 缩略图的集合视图来显示。所以我在 viewDidLoad 中使用它(以避免每次我们向下或向上时它都会在 collectionview 中生成缩略图)。一次性生成,无延迟:
正在 viewDidLoad 中加载 pdf 的缩略图:
- (void)viewDidLoad
...
coverPdf = [NSMutableArray new];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
// Load image on a non-ui-blocking thread
NSString *pdfPath = nil;
NSURL *pdfUrl = nil;
CGPDFDocumentRef pdfRef = nil;
NSMutableArray *arr = [NSMutableArray new];
for (id cover in filePathsArray)
{
pdfPath = [categoryPath stringByAppendingPathComponent:cover];
pdfUrl = [NSURL fileURLWithPath:pdfPath];
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfUrl);
[arr addObject:[self imageFromPDFWithDocumentRef:pdfRef]];
NSLog(@"first process");
}
coverPdf = [NSMutableArray arrayWithArray:arr];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
[pdfCollectionView reloadData];
});
});
...
}
正在生成缩略图:
- (UIImage *)imageFromPDFWithDocumentRef:(CGPDFDocumentRef)documentRef
{
CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, 1);
CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, CGRectGetMinX(pageRect),CGRectGetMaxY(pageRect));
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, -(pageRect.origin.x), -(pageRect.origin.y));
CGContextDrawPDFPage(context, pageRef);
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
使用缩略图:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ListPdfCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionViewCell" forIndexPath:indexPath];
cell.productLabel.text = [filePathsArray objectAtIndex:indexPath.row];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
// Load image on a non-ui-blocking thread
dispatch_sync(dispatch_get_main_queue(), ^(void) {
// Assign image back on the main thread
if ([coverPdf count] > indexPath.row)
{
cell.pdfImage.image = [coverPdf objectAtIndex:indexPath.row];
}
});
});
return cell;
}
这个方法有两个问题:
- 第一个是缩略图显示时间过长。当它加载时,它运行良好。
- 第二个问题,内存在不断增加,即使我关闭viewcontroller,我进来了,似乎内存没有释放。如果我关闭 viewcontroller 并进入 9 或 10 次,如果应用程序崩溃。
提前致谢。
解决方案:
由于出现时间太长,我只是把DISPATCH_QUEUE_PRIORITY_BACKGROUND换成了DISPATCH_QUEUE_PRIORITY_HIGH。好多了。
对于内存泄漏,我在循环的末尾使用了 CGPDFDocumentRelease() 函数,就像这样,一切都很顺利:
for (id cover in filePathsArray) { pdfPath = [categoryPath stringByAppendingPathComponent:cover]; pdfUrl = [NSURL fileURLWithPath:pdfPath]; pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfUrl); [arr addObject:[self imageFromPDFWithDocumentRef:pdfRef]]; CGPDFDocumentRelease(pdfRef);//Line added NSLog(@"first process"); }
我有个坏消息要告诉你。内存泄漏不是你的问题而是 iOS 10 内存管理错误
There is a memory management bug in iOS 10.0.1 and 10.0.2 in the CGContextDrawPDFPage() function.
您可以在此处找到详细信息http://www.openradar.me/28415289
您还可以找到有用的讨论 https://github.com/vfr/Reader/issues/166
简而言之,可能的解决方法是不创建
CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, 1);
每次都对所有 pdf 文件使用一个 CGPDFPageRef。然后当你不再需要它时将它设置为 NULL。
创建缩略图延迟
以及创建缩略图的解决方案。我只能建议根本不要在此 VC 中执行此操作,而是在将此 .pdf 添加到应用程序时为应用程序中的每个 .pdf 创建缩略图(或者如果所有 pdf 都已存储,则在后台服务中启动应用程序时)在应用程序包中)。然后,您可以将此预览保存为 .jpg 或 .png 文件,其名称等于 pdf 名称,或者在任何数据库或其他存储中设置 pdf 和预览之间的关系(如果您的应用程序中有它)。 然后只需在您的 collectionView 中重复使用此预览。