开发语言:Objective-C
原生框架:CoreFoundation.framework
、CoreGraphics.framework
、QuickLook.framework
三方框架:TZImagePickerController
前言
图片转PDF
demo源码在这里Gitee
一、从相册选择图片
demo中使用TZImagePickerController
进行图片选择,支持多选。
使用TZImagePickerController
导航栏颜色问题可查看# TZImagePickerController设置导航栏颜色无效?导航栏颜色总是白色?
二、多图进行排序
使用UICollectionView
进行宫格布局,添加长按手势,实现拖动排序。
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(lonePressMoving:)];
[self.collectionView addGestureRecognizer:longPress];
//长按手势触发方法
- (void)lonePressMoving:(UILongPressGestureRecognizer *)longPress {
switch (longPress.state) {
case UIGestureRecognizerStateBegan: {
{
NSIndexPath *selectIndexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]];
//判断手势落点位置是否在路径上
if (selectIndexPath == nil) { break; }
[self.collectionView beginInteractiveMovementForItemAtIndexPath:selectIndexPath];
}
break;
}
case UIGestureRecognizerStateChanged: {
[self.collectionView updateInteractiveMovementTargetPosition:[longPress locationInView:self.collectionView]];
break;
}
case UIGestureRecognizerStateEnded: {
[self.collectionView endInteractiveMovement];
break;
}
default:
[self.collectionView cancelInteractiveMovement];
break;
}
}
// 数据源替换
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
// 获取移动位置数据
id objc = [self.dataSource objectAtIndex:sourceIndexPath.item];
// 从资源数组中移除该数据
[self.dataSource removeObject:objc];
// 将数据插入到资源数组中的目标位置上
[self.dataSource insertObject:objc atIndex:destinationIndexPath.item];
[self.collectionView reloadData];
}
三、图片转PDF,并设置密码
注意:CoreFoundation.framework
、CoreGraphics.framework
都是底层C语言框架,不适用ARC自动释放机制,需手动释放内存。
/// 将多张图片合成为PDF文件
/// - Parameters:
/// - dataSource: 图片数据源
/// - pdfSize: pdf大小
/// - pwd: 密码
/// - filePath: 生成pdf的路径
+ (void)creatPDFWithImagesDataSource:(NSArray <UIImage *>*)dataSource pdfSize:(CGSize)pdfSize pdfPWD:(NSString *)pwd filePath:(NSString *)filePath {
// 将OC字符串转成C字符串
CFStringRef pwdStrRef = NULL;
if (pwd && pwd.length > 0) {
pwdStrRef = (__bridge_retained CFStringRef)pwd;
}
CFStringRef filePathStrRef = NULL;
if (filePath && filePath.length > 0) {
filePathStrRef = (__bridge_retained CFStringRef)filePath;
}
// 获取PDF单页尺寸
if (CGSizeEqualToSize(pdfSize, CGSizeZero)) {
pdfSize = CGSizeMake(595, 842);
}
CGRect pdfRect = (CGRect){CGPointZero, pdfSize};
// 创建本地存储PDF路径url
CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, filePathStrRef, kCFURLPOSIXPathStyle, NO);
// 创建pdf信息字典
CFMutableDictionaryRef pdfInfo = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// 设置pdf标题
CFDictionarySetValue(pdfInfo, kCGPDFContextTitle, CFSTR("图片转PDF"));
// 设置作者
CFDictionarySetValue(pdfInfo, kCGPDFContextAuthor, CFSTR("Emo,"));
// 设置是否允许绘制
CFDictionarySetValue(pdfInfo, kCGPDFContextAllowsPrinting, kCFBooleanTrue);
// 设置密码
if (pwdStrRef) {
CFDictionarySetValue(pdfInfo, kCGPDFContextOwnerPassword, pwdStrRef);
CFDictionarySetValue(pdfInfo, kCGPDFContextUserPassword, pwdStrRef);
}
// 转换rect为data
CFDataRef rectDataRef = CFDataCreate(NULL, (const UInt8 *)&pdfRect, sizeof(pdfRect));
// 创建单页信息
CFMutableDictionaryRef pageInfo = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(pageInfo, kCGPDFContextMediaBox, rectDataRef);
// 创建PDF上下文
CGContextRef context = CGPDFContextCreateWithURL(urlRef, &pdfRect, pdfInfo);
if (context == NULL) {
NSLog(@"create pdf context fail.");
if (pwdStrRef) {
CFRelease(pwdStrRef);
}
CFRelease(filePathStrRef);
CFRelease(urlRef);
CFRelease(pdfInfo);
CFRelease(pageInfo);
CFRelease(rectDataRef);
CGContextRelease(context);
return;
}
// 循环创建PDF页面
for (int i = 0; i < dataSource.count; i++) {
UIImage *image = dataSource[i];
// 等比计算图片尺寸
CGFloat imgW = image.size.width;
CGFloat imgH = image.size.height;
CGFloat pdfW = pdfRect.size.width;
CGFloat pdfH = pdfRect.size.height;
CGRect pageRect = [self calculatePDFPageRectWithImgW:imgW imgH:imgH pdfW:pdfW pdfH:pdfH];
// 将UIImage转成NSData
NSData *imageData = UIImageJPEGRepresentation(image, 0.1);
// 将NSData转成CFData
CFDataRef imgDataRef = (__bridge_retained CFDataRef)imageData;
// 开始绘制PDF单页
CGPDFContextBeginPage(context, pageInfo);
// 绘制PDF单页
CGDataProviderRef providerRef = CGDataProviderCreateWithCFData(imgDataRef);
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(providerRef, NULL, NO, kCGRenderingIntentDefault);
CGContextDrawImage(context, pageRect, imageRef);
// 绘制完成释放资源
CGDataProviderRelease(providerRef);
CGImageRelease(imageRef);
CFRelease(imgDataRef);
// 结束绘制PDF单页
CGPDFContextEndPage(context);
}
// 释放资源、
if (pwdStrRef) {
CFRelease(pwdStrRef);
}
CFRelease(filePathStrRef);
CFRelease(urlRef);
CFRelease(pdfInfo);
CFRelease(pageInfo);
CFRelease(rectDataRef);
CGContextRelease(context);
}
四、预览PDF文件
使用QuickLook.framework
的预览文件功能。
- (void)viewDidLoad {
[super viewDidLoad];
QLPreviewController *qlVC = [[QLPreviewController alloc] init];
qlVC.view.frame = self.view.bounds;
qlVC.delegate = self;
qlVC.dataSource = self;
[self addChildViewController:qlVC];
[self.view addSubview:qlVC.view];
[qlVC reloadData];
}
// 预览的文件数
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller {
return 1;
}
// 返回预览数据
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
return [NSURL fileURLWithPath: self.filePath?:@""];
}