【iOS】图片转PDF文件(支持多张图片生成多页PDF文件)

开发语言:Objective-C
原生框架:CoreFoundation.frameworkCoreGraphics.frameworkQuickLook.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.frameworkCoreGraphics.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?:@""];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值