szymczykThanks for taking the time to reply.I followed up on your pointers to Apple Quartz 2D and the link you provided.The code below is based on both of those source and this code functions as expected.BUT it yields exactly the same output - the resulting .pdf file does not show an attributed string - it simply shows the .string value.Surely I'm missing something!Can someone provide any guidance?My suspicions center on 'pageDictionary' and 'CTFrameDraw(). [but what do I know]- (PDFDocument *) pdfForAttributedString:(NSAttributedString *)thisAtrributedString {
NSString *tDir = self.tempDirectoryURL.path;
NSString *globUniq = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *newFileName = [tDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.pdf", globUniq]];
const char *filename = [newFileName UTF8String];
CFStringRef path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0);
CFRelease (path);
CFMutableDictionaryRef myDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR(“XYZ - a macOS app"));
CGContextRef pdfContext = CGPDFContextCreateWithURL (url, nil, myDictionary); // Quartz assumes 8.5 x 11
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(thiscfAttr);
CFRange textRange = CFRangeMake(0, CFAttributedStringGetLength(thiscfAttr));
CFRange pageRange;
CGSize pageSize = CGSizeMake(612.0, 792.0);
CFAttributedStringRef thiscfAttr = (__bridge CFAttributedStringRef)(thisAtrributedString);
CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, nil, pageSize, &pageRange);
CGRect pageRect = CGRectMake(72.0, 72.0, 468.0, 648.0);// 1” margins
CGPathRef framePath = CGPathCreateWithRect(pageRect, nil);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, pageRange, framePath, nil);
CFMutableDictionaryRef pageDictionary = NULL;
CGPDFContextBeginPage (pdfContext, pageDictionary);
CTFrameDraw(frame, pdfContext);
CGPDFContextEndPage (pdfContext);
CGPDFContextClose(pdfContext);
NSURL *printURL = (__bridge NSURL *)(url);
PDFDocument *doc = [[PDFDocument alloc] initWithURL:printURL];
return doc;
}
Post
Replies
Boosts
Views
Activity
I am interested in looking at the solution you propose! Please post!
I don't understand how your 2 lines of code produce a .pdf document.You ask 'what precisely is your problem'?I have posted 2 different sets of code which DO produce .pdf files. My problem is is that these file do not produce the source attributedString -- they appear to produce the .string value of the NSAttributedString.My precise problem is that I am trying to produce a .pdf file which is an attributed string.
any code you might show about how to 'create pages as long as there is text remaining' would be appreciated!
symczyk;Thanks for the traction. Your contributions here are appreciated!!You say above: '...For creating a PDF from a text view's contents, you're better off going with NSPrintOperation...'Yeah, that's where I started this thread. Below is that code.I'm back to the original question: This code produces a .pdf file BUT that .pdf does not contain the NSAttributedString shown in the NSTextView. The .pdf file only contains the .string value of the source NSAttributedString.- (PDFDocument *) pdfForAttributedString:(NSView *)thisView {
NSString *globUniq = [[NSProcessInfo processInfo] globallyUniqueString];
NSURL *printURL = [NSURL URLWithString:[[self.tempDirectoryURL path] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.pdf", globUniq]]];
NSMutableDictionary *dict = [[NSPrintInfo sharedPrintInfo] dictionary];
[dict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
[dict setObject:printURL forKey:NSPrintJobSavingURL];
//set 1 in margins
[dict setObject:[NSNumber numberWithFloat:72.0] forKey:NSTopMarginDocumentAttribute];
[dict setObject:[NSNumber numberWithFloat:72.0] forKey:NSBottomMarginDocumentAttribute];
[dict setObject:[NSNumber numberWithFloat:72.0] forKey:NSLeftMarginDocumentAttribute];
[dict setObject:[NSNumber numberWithFloat:72.0] forKey:NSRightMarginDocumentAttribute];
//centering
[dict setObject:[NSNumber numberWithBool:0] forKey:NSPrintHorizontallyCentered];
[dict setObject:[NSNumber numberWithBool:0] forKey:NSPrintVerticallyCentered];
NSPrintInfo *pix = [[NSPrintInfo alloc] initWithDictionary:dict];
[pix setHorizontalPagination:NSPrintingPaginationModeFit];//NSPrintingPaginationModeFit NSAutoPagination
[pix setVerticalPagination:NSPrintingPaginationModeFit];//NSAutoPagination
//setup dataObject
NSMutableData *output = [[NSMutableData alloc] init];
NSPrintOperation *op = [NSPrintOperation PDFOperationWithView:thisView insideRect:thisView.frame toData:output printInfo:pix];
//hide UI
[op setShowsPrintPanel:NO];
[op setShowsProgressPanel:NO];
//do the thing
if ([op runOperation]) {
PDFDocument * doc = [[PDFDocument alloc] initWithData:output];
return doc;
} else {
return nil;
}
}
To Anyone Tagging Along;OMG It appears to me now that this is the expected behavior!Create a new Word document or TextEdit..Enter some text and assign a link to this text.Now use 'Print' and then 'Save as PDF' to save a document.Now open that newly created .pdf file.No hyperlinks!! You may see text that has link color but the underlying hyperlink is not embedded in the .pdf file!BTW this is tru for Catalina and High Sierra (10.13.6)Has it always been like this? It doesn't seem so to me but I can't point to anything.Steve
janabananaThank-You for tagging along in this voyage!However, your comment confuses me on several points:first you make no comment as to my Word or TextEdit suggested actions... can you confirm the behavior I have observed? (what OS?)you say 'tested in my app' -- so you wrote all the code involved?you say 'saved it as a pdf' - this is using your code or using the standard macOS 'Print' - 'Save As'?in your app are you using NSPrintOperation to render the attributed string within an NSTextView or are you doing something different?
janabananaSo the ONLY difference here is I am NOT using NSDocument.Why would that make any difference?
If anyone is still following along...Thanks go to janabanan for staying with this thread!!Here's simplified code which produces a .pdf file which retains the links embedded in the NSAttributedString which is displayed in 'sourceTextView'. This .pdf file is also appropriately paginated.[savePanel beginSheetModalForWindow:self.windowController.window completionHandler:^(NSInteger result){ if (result == NSFileHandlingPanelOKButton) { NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo]; [printInfo setHorizontalPagination:NSFitPagination]; [printInfo setVerticallyCentered:NO]; [printInfo setHorizontallyCentered:NO]; [printInfo setLeftMargin:67.0]; [printInfo setRightMargin:67.0]; [printInfo setTopMargin:72.0]; [printInfo setBottomMargin:72.0]; [printInfo dictionary] [NSPrintJobDisposition] = NSPrintSaveJob; [printInfo dictionary] [NSPrintJobSavingURL] = [savePanel URL]; NSPrintOperation *op = [NSPrintOperation printOperationWithView:self.windowController.sourceSourceTextView printInfo:printInfo]; [op setShowsPrintPanel:NO]; [op setShowsProgressPanel:NO]; [op runOperation]; } [savePanel orderOut:self];}];
Hey Just found the answer!!The hardened runtime requires an additional entitlement: com.apple.security.automation.apple-eventsSanity restored!
A dramatic improvement:tell application "Contacts"
set thisList to selection
return id of first item of thisList
end tell
hardened runtime!I had enabled and set the 'Contacts' option in Xcode but there is also an 'Apple Events' option.Turning on 'AppleEvents' restored the earlier functionality.
It has subsided....Occam's explanation: a glitch in the matrix
Helpful and to the point!
Thanks for taking the time to respond
Feedback from other sources has illuminated the following strategy:
-Split the database into two databases: ReadOnly and UserModifiable
Use the ReadOnly directly from within the mainBundle.
UserModifiable is copied to .applicationSupport and then used from there.
Duplication is then reduced to the initial database for userModifiable...(in my case this is relatively small!)
This strategy also addresses concern with backup (contents of .applicationSupport)