// // BLBookletManager.m // Booklet // // Created by 蒋志鹏 on 2018/5/3. // Copyright © 2018年 NO1. All rights reserved. // #import "KMBookletManager.h" #import "KMBookletParameterModel.h" #import "NSMutableArray+KMOddEvenPartFetch.h" NSString *const BLBlankPageCountKey = @"blankPageNum";//空白页面数量key NSString *const BLBookletInfoKey = @"bookletInfo";//小册子编号和页数信息key @interface KMBookletManager() @end @implementation KMBookletManager - (void)dealloc { } //单例方法 static KMBookletManager *manager = nil; + (instancetype)sharedManager { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[KMBookletManager alloc] init]; }); return manager; } //根据参数,生成PDF并回调 - (void)generateNewPDFWithParameterModel:(KMBookletParameterModel *)parameterModel completionHandler:(Booklet_GenerateNewPDFBlock)handle { //获取数组,如果数组为空,回调错误,不处理 NSArray *printArr = [self fetchDrawPageArraysWithModel:parameterModel]; if (printArr.count == 0) { if (handle) { handle(NO,parameterModel.savePath); } return; } //添加,统一后缀名为pdf if (!parameterModel.savePath.pathExtension) { parameterModel.savePath = [parameterModel.savePath stringByAppendingString:@".pdf"]; }else{ NSString *lowString = [parameterModel.savePath.pathExtension lowercaseString]; if (![lowString isEqualToString:@"pdf"]) { parameterModel.savePath = [parameterModel.savePath stringByAppendingString:@".pdf"]; }else{ NSMutableString *mNewName = [parameterModel.savePath mutableCopy]; parameterModel.savePath = [mNewName stringByReplacingOccurrencesOfString:parameterModel.savePath.pathExtension withString:@"pdf"]; } } //创建画布 CGRect mediaBox; CGContextRef myPDFContext = NULL; mediaBox = CGRectMake(0, 0, parameterModel.pageSize.width, parameterModel.pageSize.height); CFStringRef ref = (__bridge CFStringRef)parameterModel.savePath; myPDFContext = MyPDFContextCreate (&mediaBox, ref); //如果画布为空,回调错误,返回 if (!myPDFContext) { if (handle) { handle(NO,parameterModel.savePath); } return; } CFStringRef myKeys[1]; CFTypeRef myValues[1]; myKeys[0] = kCGPDFContextMediaBox; myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof (CGRect)); CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 1, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); //遍历将要打印的数组,打印PDFpage for (NSInteger j = 0 ;j @[@"3",@"2",@"1"]; if (parameterModel.reversePages) { //只有数组个数大于1才有换序的必要 if (printArr.count > 1) { NSMutableArray *reverseArray = [NSMutableArray new]; for (NSInteger i = printArr.count; i > 0 ; i--) { [reverseArray addObject:printArr[i -1]]; } [printArr removeAllObjects]; [printArr addObjectsFromArray:reverseArray]; } } //计算最终的数组,页数 NSMutableArray *newArray = [NSMutableArray new]; //数组的起点和终点 NSInteger firstPageIndexPlusOne = 0; NSInteger lastPageIndexPlusOne = 0; //如果是双面打印,那么就要乘以2 if (parameterModel.printStyle == kBLPrintStyle_BothSide) { firstPageIndexPlusOne = 2 * parameterModel.sheetFromIndex; lastPageIndexPlusOne = 2 * parameterModel.sheetEndindex; }else{ firstPageIndexPlusOne = parameterModel.sheetFromIndex; lastPageIndexPlusOne = parameterModel.sheetEndindex; } //提取数组元素 for (NSInteger i = firstPageIndexPlusOne; i < lastPageIndexPlusOne ; i ++) { [newArray addObject:printArr[i]]; } [printArr removeAllObjects]; [printArr addObjectsFromArray:newArray]; return printArr; } - (void)drawPageWithContext:(CGContextRef) myPDFContext parameterModel:(KMBookletParameterModel *)parameterModel printArray:(NSArray *)subArr { for (NSInteger i = 0; i < subArr.count; i++) { { //定义X偏移,Y偏移,缩放比例 CGFloat xTransform = 0; CGFloat yTransform = 0; CGFloat scale = 0; //将用来绘制的PDFPage对象 PDFPage *page = subArr[i]; //是否需要移除注释 NSMutableArray *annotations = [NSMutableArray array]; for (PDFAnnotation *annotation in page.annotations) { [annotations addObject:annotation]; } if (parameterModel.commentForms == kBookletCommentForms_DocumentOnly) { for (PDFAnnotation *annotation in annotations) { [annotation.page removeAnnotation:annotation]; } } else if (parameterModel.commentForms == kBookletCommentForms_DocumentAndStamps) { for (PDFAnnotation *annotation in annotations) { if (![annotation isKindOfClass:[PDFAnnotationStamp class]]) { [annotation.page removeAnnotation:annotation]; } } } //page原尺寸 CGSize originalPageSize = [page boundsForBox:kPDFDisplayBoxCropBox].size; //自动旋转 if (parameterModel.autoRotatePage) { //旋转规则:如果当前的实际宽高(由宽高和旋转角度得到)的关系是宽大于高,那么要逆时针旋转90度; if (page.rotation == 0) { CGFloat actualWidth = originalPageSize.width; CGFloat actualHeight = originalPageSize.height; if (actualWidth > actualHeight) { page.rotation = page.rotation - 90; } }else if (page.rotation == 90){ CGFloat actualWidth = originalPageSize.height; CGFloat actualHeight = originalPageSize.width; if (actualWidth > actualHeight) { page.rotation = page.rotation -90; } }else if (page.rotation == 180){ CGFloat actualWidth = originalPageSize.width; CGFloat actualHeight = originalPageSize.height; if (actualWidth > actualHeight) { page.rotation = page.rotation - 90; } }else if (page.rotation == 270){ CGFloat actualWidth = originalPageSize.height; CGFloat actualHeight = originalPageSize.width; if (actualWidth > actualHeight) { page.rotation = page.rotation - 90; } } } //如果page的旋转角度对180求余还真,那么要将宽高大小交换 if (page.rotation%180) { originalPageSize = CGSizeMake(originalPageSize.height, originalPageSize.width); } //画布大小 CGSize availableSize = CGSizeMake((parameterModel.pageSize.width - parameterModel.gap)/2, parameterModel.pageSize.height); //画布和原来的page宽之比 CGFloat wRatio = availableSize.width/originalPageSize.width; //画布和原来的page高之比 CGFloat hRatio = availableSize.height/originalPageSize.height; //取最小值 CGFloat ratio = MIN(wRatio, hRatio); //如果scale大于1那么等于1(只允许缩小,不可以放大) scale = ratio > 1 ? 1 : ratio; //在画布上page的实际尺寸 CGSize realSize = CGSizeMake(originalPageSize.width * scale, originalPageSize.height *scale); //画第一张和画第二张x偏移区分 if (i == 0) { xTransform = (availableSize.width - realSize.width)/2; }else{ xTransform = (availableSize.width - realSize.width)/2 + parameterModel.pageSize.width/2 + parameterModel.gap/2; } //Y偏移 yTransform = (availableSize.height - realSize.height)/2; //画布状态入栈 CGContextSaveGState(myPDFContext); //偏移 CGContextTranslateCTM(myPDFContext, xTransform, yTransform); //缩放 CGContextScaleCTM(myPDFContext, scale, scale); //系统区分,绘制 if (@available(macOS 10.12, *)) { [page drawWithBox:kPDFDisplayBoxCropBox toContext:myPDFContext]; [page transformContext:myPDFContext forBox:kPDFDisplayBoxCropBox]; } else { [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:myPDFContext flipped:YES]]; [page drawWithBox:kPDFDisplayBoxCropBox]; [NSGraphicsContext restoreGraphicsState]; [page transformContextForBox:kPDFDisplayBoxCropBox]; } //画布状态出栈 CGContextRestoreGState(myPDFContext); } } } //创建一个图形上下文对象 CGContextRef MyPDFContextCreate (const CGRect *inMediaBox, CFStringRef path) { CGContextRef myOutContext = NULL; CFURLRef url; url = CFURLCreateWithFileSystemPath (NULL, // 1 path, kCFURLPOSIXPathStyle, false); if (url != NULL) { myOutContext = CGPDFContextCreateWithURL (url,// 2 inMediaBox, NULL); CFRelease(url);// 3 } return myOutContext;// 4 } #pragma mark - caculate - (NSMutableArray *)regroupBothSidesPrintArrayWithPrimaryArray:(NSArray *)primaryArray { NSMutableArray * backArray = [NSMutableArray array]; NSDictionary *infoDict = [self calculatePagesPerBookletWithBookletNumber:1 totalPage:primaryArray.count]; //小册子对应的页数信息 NSDictionary *detailInfoDict = infoDict[BLBookletInfoKey]; //空白页数量 NSInteger blankPageCount = [(NSNumber *)infoDict[BLBlankPageCountKey] integerValue]; NSMutableArray *tempArray = [NSMutableArray arrayWithArray:primaryArray]; for (NSInteger i = 0; i < blankPageCount; i ++) { PDFPage *page = [[PDFPage alloc] init]; [tempArray addObject:page]; } NSInteger sheetCount = [detailInfoDict.allValues.lastObject integerValue]; for (NSInteger i = 0; i < sheetCount; i ++) { NSMutableArray *tArr1 = [NSMutableArray new]; PDFPage *addingPage1 = tempArray[tempArray.count - 2 * i - 1]; PDFPage *addingPage2 = tempArray[2 * i]; [tArr1 addObject:addingPage2]; [tArr1 addObject:addingPage1]; [backArray addObject:tArr1]; NSMutableArray *tArr2 = [NSMutableArray new]; PDFPage *addingPage3 = tempArray[2 * i + 1]; PDFPage *addingPage4 = tempArray[tempArray.count - 2 * i -2]; [tArr2 addObject:addingPage4]; [tArr2 addObject:addingPage3]; [backArray addObject:tArr2]; } return backArray; } - (NSDictionary *)calculatePagesPerBookletWithBookletNumber:(NSInteger)bookletNum totalPage:(NSInteger)totalPageNum { NSMutableDictionary *backDict = [NSMutableDictionary dictionary]; NSMutableDictionary *bookletPageNumInfoDict = [NSMutableDictionary dictionary]; //对4取余,得到最后一个sheet会有多少张page NSInteger surplusPages = totalPageNum % 4; //总页数(每一页四页)= 总页数/4+是否有余数的bool值 NSInteger tTotalPageNum = totalPageNum/4 + (surplusPages > 0 ? 1:0); //平均每一个册子有的页数 NSInteger averagePageNum = tTotalPageNum / bookletNum; //平均分完还剩余多少页 NSInteger surplusPageNum = tTotalPageNum % bookletNum; //遍历,给小册子赋值(数量) for (NSInteger i = 0; i < bookletNum; i++) { [bookletPageNumInfoDict setObject:[NSNumber numberWithInteger:averagePageNum] forKey:[NSString stringWithFormat:@"%ld",i]]; } //遍历,给靠前的小册子添加页数 for (NSInteger j = 0; j < surplusPageNum; j++) { [bookletPageNumInfoDict setObject:[NSNumber numberWithInteger:averagePageNum + 1] forKey:[NSString stringWithFormat:@"%ld",j]]; } //空白页数量(分完了之后,最后一个小册子的空白页数量) NSInteger blankPageNum = tTotalPageNum * 4 - totalPageNum; [backDict setObject:[NSNumber numberWithInteger:blankPageNum] forKey:BLBlankPageCountKey]; [backDict setObject:bookletPageNumInfoDict forKey:BLBookletInfoKey]; return backDict; } @end