Используя Какао, NSPrintOperation, Как правильно создать PDF-файл из текста в NSView?
Используя NSPrintOperation, Как правильно создать PDF-файл из текста в NSView?
* * ОБРАТИТЕ ВНИМАНИЕ, Я НАШЕЛ ВРЕМЕННОЕ РЕШЕНИЕ, КОТОРОЕ ПОКАЗАНО НА НИЖЕ
Что я сделал: 1. Поместил текст в NSTextView.
- (NSTextView *)printableViewWithRecipe:(Recipe *)recipe
{
[_printView setString:@""];
[_printView setTextColor:[NSColor textColor]];
[_printView setFont:[NSFont userFontOfSize:0]];
NSDictionary *titleAttr;
_printView = [[NSTextView alloc] initWithFrame:[[self printInfo] imageablePageBounds]];
[_printView setVerticallyResizable:YES];
[_printView setHorizontallyResizable:NO];
// Begin to ADD THE TEXT
[[_printView textStorage] beginEditing];
// Set the attributes for the title
[[_printView textStorage] beginEditing];
titleAttr =
[NSDictionary dictionaryWithObject:[(AppDelegate*)[[NSApplication sharedApplication] delegate] tableFont] forKey:NSFontAttributeName];
// Add the title
[
[_printView textStorage] appendAttributedString:
[[NSAttributedString alloc] initWithString:[recipe name] attributes:titleAttr ]
];
// Create a couple returns between the title and the body
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
// Add the body text
if([[recipe ingredients] length] )
[[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
initWithString:[recipe ingredients] attributes:titleAttr]];
// Create a couple returns between the ingredients and the directions
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
if([[recipe directions] length] )
[[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
initWithString:[recipe directions] attributes:titleAttr]];
// Create a couple returns between the directions and the comments
[[_printView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
if([[recipe comments] length] )
[[_printView textStorage] appendAttributedString: [ [NSAttributedString alloc]
initWithString:[recipe comments] attributes:titleAttr]];
// Center the title
[_printView setAlignment:NSCenterTextAlignment range:NSMakeRange(0, [[recipe name] length])];
[[_printView textStorage] endEditing];
return _printView;
} // end printableViewForRecipe
2. Попробуйте создать файл PDF из текста TextView, используя метод ниже:
- (PDFDocument *)exportPDFfromView:(NSTextView*)textView fileNumber:(NSUInteger)fileNumber
{
NSPrintInfo *printInfo;
NSPrintInfo *sharedInfo;
NSPrintOperation *printOp;
NSMutableDictionary *printInfoDict;
NSMutableDictionary *sharedDict;
sharedInfo = [NSPrintInfo sharedPrintInfo];
sharedDict = [sharedInfo dictionary];
printInfoDict = [NSMutableDictionary dictionaryWithDictionary: sharedDict];
[printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
[printInfoDict setObject:poTempfileURL forKey:NSPrintJobSavingURL];
printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];//1
[printInfo setHorizontalPagination: NSAutoPagination];//2
[printInfo setVerticalPagination: NSAutoPagination];//3
[printInfo setVerticallyCentered:NO];//4
printOp = [NSPrintOperation printOperationWithView:textView printInfo:printInfo];//5
[printOp setShowsPrintPanel:NO];
[printOp setShowsProgressPanel:NO];//6
DLog(@"poTempfileURL=%@",poTempfileURL);
BOOL didRunOK = [printOp runOperation];//7
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[poTempfileURL path]];
DLog(@"poTempfileURL=%@",poTempfileURL);
DLog(@"didRunOK=%lu\nfileExists=%lu",didRunOK,exists);
PDFDocument *doc = [[PDFDocument alloc] initWithURL:poTempfileURL];
return doc;
}
Запустите следующий код:
[self tempDirectoryURL];// invoke getter NSLog(@"_tempDirectoryURL=%@",_tempDirectoryURL); _tempDirectoryURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/
Геттер следует:
- (NSURL *)tempDirectoryURL { //getter
NSURL *tempURL;
if(!_tempDirectoryURL){
tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]] isDirectory:YES];
_tempDirectoryURL = tempURL;
}
return _tempDirectoryURL;
}
После запуска этого кода:
BOOL didRunOK = [printOp runOperation]; // 7
BOOL существует = [[NSFileManager defaultManager] fileExistsAtPath:[путь poTempfileURL]]; DLOG (@"didRunOK=% лу \nfileExists=% лу",didRunOK, существует); DLoG (@"poTempfileURL=%@",poTempfileURL);
Я ожидаю, что файл PDF будет создан по адресу: poTempfileURL, где его значение будет следующим: poTempfileURL=file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/884B9B4C-907B-489E21F9A1B9A10009 000016435C134E56/7A196040-0D81-496D-B9F3-BF0B855F6BBC-1821-0000164A9446040F_file_0.pdf
консоль показывает:
didRunOK=1
fileExists=1
Когда выполняется следующая строка кода:
BOOL didRunOK = [printOp runOperation]; // 7
Содержимое printInfo для printOp:
{
NSBottomMargin = 90;
NSCopies = 1;
NSDestinationFormat = "application/pdf";
NSDetailedErrorReporting = 0;
NSFaxNumber = "";
NSFirstPage = 1;
NSHorizonalPagination = 0;
NSHorizontallyCentered = 0;
NSJobDisposition = NSPrintSaveJob;
NSJobSavingFileNameExtensionHidden = 0;
NSJobSavingURL = "file:///var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/2687B4CD-6ABF-4826-B8F8-3D536FFACA66-1362-00001DEFA0B13D70/1F0483BF-00B4-4F65-A3C7-C4824F53C03E-1362-00001DF033AAD968_file_0.pdf";
NSLastPage = 2147483647;
NSLeftMargin = 72;
NSMustCollate = 1;
NSOrientation = 0;
NSPagesAcross = 1;
NSPagesDown = 1;
NSPaperName = "na-letter";
NSPaperSize = "NSSize: {612, 792}";
NSPrintAllPages = 1;
NSPrintProtected = 0;
NSPrintSelectionOnly = 0;
NSPrintTime = "0000-12-30 00:00:00 +0000";
NSPrinter = "{\n \"Device Description\" = {\n NSDeviceIsPrinter = YES;\n };\n \"Language Level\" = 3;\n Name = \"HP DESKJET 840C @ Mark\\U2019s Mac Pro\";\n Type = \"Generic PCL Laser Printer\";\n}";
NSPrinterName = "HP DESKJET 840C @ Mark\U2019s Mac Pro";
NSRightMargin = 72;
NSSavePath = "/var/folders/8p/c2x7m74j1wzdf92jy770zx500000gn/T/com.DrummingGrouse.HungryMe/2687B4CD-6ABF-4826-B8F8-3D536FFACA66-1362-00001DEFA0B13D70/1F0483BF-00B4-4F65-A3C7-C4824F53C03E-1362-00001DF033AAD968_file_0.pdf";
NSScalingFactor = 1;
NSTopMargin = 90;
NSVerticalPagination = 0;
NSVerticallyCentered = 0;
}
В Xcode: po [[textView textStorage] string] производит текст ниже с пометкой:
/// BEGIN NSTextView TEXT ///
В Finder, когда я открываю файл, расположенный в poTempFileURL, в окне предварительного просмотра этот файл состоит из четырех страниц (он должен иметь только одну страницу) и представляется в виде предварительного просмотра пустым файлом PDF.
Когда я открываю тот же самый файл "PDF" в TextEdit, этот файл содержит содержимое ниже, которое помечено: /// BEGIN TEXT PDF Tempfile ///
Что мне нужно сделать, чтобы создать "правильный" PDF-файл? Я не могу получить PDF, который я могу открыть и прочитать в Preview.
po [doc pageCount] показывает "4"
/// НАЧАТЬ NSTextView TEXT /// - po [[textView textStorage] string]
French Toast
[French Toast]
preptime 0:03 cooktime 0:08 serves:1-2
egg 1
milk 3/4 cup
ground cinnamon 1/8 tsp (optional)
best bread 2 slices
butter 4 tsp (two per side)
maple syrup (to taste)
[French Toast]
1. Add egg to a bowl and beat with a fork.
2. Add milk and cinnamon to egg and beat briefly.
3. Heat heavy skillet to medium high. Add 2 tsp butter.
4. Dip bread slice halves in batter and brown in skillet. Flip and add additional butter. Brown and serve with syrup.
Serve with pork sausage, chorizo or bacon.
/// КОНЕЦ NSTextView TEXT ///
/// НАЧАТЬ ТЕКСТ PDF Tempfile ///
%PDF-1.3
%ƒÂÚÂÎßÛ†–ƒ∆
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
5 0 obj
11
endobj
2 0 obj
<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792]
>>
endobj
6 0 obj
<< /ProcSet [ /PDF ] >>
endobj
8 0 obj
<< /Length 9 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
9 0 obj
11
endobj
7 0 obj
<< /Type /Page /Parent 3 0 R /Resources 10 0 R /Contents 8 0 R /MediaBox [0 0 612 792]
>>
endobj
10 0 obj
<< /ProcSet [ /PDF ] >>
endobj
12 0 obj
<< /Length 13 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
13 0 obj
11
endobj
11 0 obj
<< /Type /Page /Parent 3 0 R /Resources 14 0 R /Contents 12 0 R /MediaBox
[0 0 612 792] >>
endobj
14 0 obj
<< /ProcSet [ /PDF ] >>
endobj
16 0 obj
<< /Length 17 0 R /Filter /FlateDecode >>
stream
x+T�Á�„
endstream
endobj
17 0 obj
11
endobj
15 0 obj
<< /Type /Page /Parent 3 0 R /Resources 18 0 R /Contents 16 0 R /MediaBox
[0 0 612 792] >>
endobj
18 0 obj
<< /ProcSet [ /PDF ] >>
endobj
3 0 obj
<< /Type /Pages /MediaBox [0 0 612 792] /Count 4 /Kids [ 2 0 R 7 0 R 11 0 R
15 0 R ] >>
endobj
19 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
20 0 obj
(Untitled)
endobj
21 0 obj
(Mac OS X 10.10.3 Quartz PDFContext)
endobj
22 0 obj
(HungryMe)
endobj
23 0 obj
(D:20150513191029Z00'00')
endobj
24 0 obj
()
endobj
25 0 obj
[ ]
endobj
1 0 obj
<< /Title 20 0 R /Producer 21 0 R /Creator 22 0 R /CreationDate 23 0 R /ModDate
23 0 R /Keywords 24 0 R /AAPL:Keywords 25 0 R >>
endobj
xref
0 26
0000000000 65535 f
0000001363 00000 n
0000000125 00000 n
0000001022 00000 n
0000000022 00000 n
0000000107 00000 n
0000000229 00000 n
0000000371 00000 n
0000000268 00000 n
0000000353 00000 n
0000000476 00000 n
0000000622 00000 n
0000000516 00000 n
0000000603 00000 n
0000000729 00000 n
0000000875 00000 n
0000000769 00000 n
0000000856 00000 n
0000000982 00000 n
0000001125 00000 n
0000001175 00000 n
0000001202 00000 n
0000001255 00000 n
0000001282 00000 n
0000001324 00000 n
0000001343 00000 n
trailer
<< /Size 26 /Root 19 0 R /Info 1 0 R /ID [ <1abd1092f1d909274c086bf0f90d6200>
<1abd1092f1d909274c086bf0f90d6200> ] >>
startxref
1507
%%EOF
/// КОНЕЦ ТЕКСТА PDF Tempfile
Если я переделываю метод exportPDFfromView: fileNumber: таким образом,
- (PDFDocument *)exportPDFfromView:(NSTextView*)textView fileNumber:(NSUInteger)fileNumber
{
NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
DLog(@"poTempfileURL=%@",poTempfileURL);
NSRect r = [textView bounds];
NSData *data = [textView dataWithPDFInsideRect:r];
[data writeToFile:poTempfileURL.path atomically:YES];
PDFDocument *doc2 = [[PDFDocument alloc] initWithURL:poTempfileURL];
DLog(@"doc2.pageCount=%lu",doc2.pageCount);
...
return doc2;
}
когда я просматриваю результирующий PDF-файл по URL poTempfileURL, он имеет одну страницу, и это правильно. Но опять же, PDF не показывает текст в Preview. Если я просматриваю этот "PDF" с TextEdit, содержание ниже.
%PDF-1.3
%ƒÂÚÂÎßÛ†–ƒ∆
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
x+TÁ„
endstream
endobj
5 0 obj
11
endobj
2 0 obj
<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 576 734]
>>
endobj
6 0 obj
<< /ProcSet [ /PDF ] >>
endobj
3 0 obj
<< /Type /Pages /MediaBox [0 0 576 734] /Count 1 /Kids [ 2 0 R ] >>
endobj
7 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
8 0 obj
(Mac OS X 10.10.3 Quartz PDFContext)
endobj
9 0 obj
(D:20150517134359Z00'00')
endobj
1 0 obj
<< /Producer 8 0 R /CreationDate 9 0 R /ModDate 9 0 R >>
endobj
xref
0 10
0000000000 65535 f
0000000493 00000 n
0000000125 00000 n
0000000268 00000 n
0000000022 00000 n
0000000107 00000 n
0000000229 00000 n
0000000351 00000 n
0000000400 00000 n
0000000452 00000 n
trailer
<< /Size 10 /Root 7 0 R /Info 1 0 R /ID [ <d86abf98c49359ba2092ad602722f659>
<d86abf98c49359ba2092ad602722f659> ] >>
startxref
565
%%EOF
!!!!
Я нашел обходной путь, который приведет меня туда, куда я хочу пойти. Это все еще не объясняет мне, почему все мои, казалось бы, бесконечные попытки использовать
+ (NSPrintOperation *)printOperationWithView:(NSView *)aView
printInfo:(NSPrintInfo *)aPrintInfo
потерпеть поражение.
Обходной путь создает многостраничные файлы PDF, которые можно просматривать в режиме предварительного просмотра.
Я надеюсь, что это полезно для других.
- (void)testQuartz:(NSData *)pdfDocumentData savePath:(NSString*)savePath
{
//Create the pdf document reference
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)pdfDocumentData);
CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(dataProvider);
//Create the pdf context
CGPDFPageRef page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CFMutableDataRef mutableData = CFDataCreateMutable(NULL, 0);
//NSLog(@"w:%2.2f, h:%2.2f",pageRect.size.width, pageRect.size.height);
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData(mutableData);
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, NULL);
if (CGPDFDocumentGetNumberOfPages(document) > 0)
{
//Draw the page onto the new context
//page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1
CGPDFContextBeginPage(pdfContext, NULL);
CGContextDrawPDFPage(pdfContext, page);
CGPDFContextEndPage(pdfContext);
}
else
{
NSLog(@"Failed to create the document");
}
CGContextRelease(pdfContext); //Release before writing data to disk.
//Write to disk
[(__bridge NSData *)mutableData writeToFile:savePath atomically:YES];
//Clean up
CGDataProviderRelease(dataProvider); //Release the data provider
CGDataConsumerRelease(dataConsumer);
CGPDFDocumentRelease(document);
CFRelease(mutableData);
}
- (PDFDocument *)exportPDFfromView:(NSTextView*)textView fileNumber:(NSUInteger)fileNumber
{
NSString *tempFileName = [NSString stringWithFormat:@"%@_file_%lu.pdf", [[NSProcessInfo processInfo] globallyUniqueString], fileNumber];
NSURL *poTempfileURL = [_tempDirectoryURL URLByAppendingPathComponent:tempFileName];
DLog(@"poTempfileURL=%@",poTempfileURL);
NSRect r = [textView bounds];
NSData *data = [textView dataWithPDFInsideRect:r];
[ self testQuartz:(NSData *)data savePath:poTempfileURL.path ];
...
return aDoc;
}
Если вы похожи на меня и хотите опубликовать один PDF-файл, скажем, эссе, начинающийся с верхней части страницы в одном PDF-файле, вам, вероятно, понадобится что-то вроде следующего, чтобы вынуть страницы из временных входных документов и переместить их все в единый выходной PDF.
NSUInteger pageCountDocZero = [[inputDocuments objectAtIndex:0] pageCount];
NSUInteger pageIndex = pageCountDocZero;
for (PDFDocument *document in inputDocuments) {
for (NSUInteger j = 0; j < [document pageCount]; j++) {
PDFPage *page = [document pageAtIndex:j];
DLog(@"Inserting pageIndex:%lu i.e inputPage:%lu of %lu",pageIndex,j+1,[document pageCount]);
[outputDocument insertPage:page atIndex:pageIndex++];
}
}