Errors on creating a multipage PDF
Asked Answered
J

4

0

Has anyone already created a PDF document in an iPad app? I see that there are new functions in the UIKit to do this, but I can't find any code example for it.

BOOL UIGraphicsBeginPDFContextToFile (
   NSString *path,
   CGRect bounds,
   NSDictionary *documentInfo
);

void UIGraphicsBeginPDFPage (
   void
);

I found an example that is supposed to work on the iPhone, but this gives me errors:

Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: CGFont/Freetype: The function `create_subset' is currently unimplemented.
Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: invalid Type1 font: unable to stream font.
Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: FT_Load_Glyph failed: error 6.
Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: FT_Load_Glyph failed: error 6.
Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: FT_Load_Glyph failed: error 6.
Fri Apr 30 11:55:32 wks104.hs.local PDF[1963] <Error>: FT_Load_Glyph failed: error 6.
Johnsonjohnsonese answered 30/4, 2010 at 10:25 Comment(1)
UIKit has been extended in OS 3.2 to support PDF functions. So instead of pdfContext = CGPDFContextCreateWithURL (url, &pageRect, docInfo); it will use pdfContext = UIGraphicsBeginPDFContextToFile( path, &pageRect, docInfo); The example I was looking at is here: iphonedevsdk.com/forum/iphone-sdk-tutorials/…Johnsonjohnsonese
J
-1

This is a better solution as it uses the correct coordinate transform to get the text to print from the top down.

#define LEFT_MARGIN 25
#define RIGHT_MARGIN 25
#define TOP_MARGIN 35
#define BOTTOM_MARGIN 50
#define BOTTOM_FOOTER_MARGIN 32
#define DOC_WIDTH 595
#define DOC_HEIGHT 842

- (void) createPDF:(NSString *)fileName withContent:(NSString *)content forSize:(int)fontSize andFont:(NSString *)font andColor:(UIColor *)color
{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *newFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:fileName];

    CGRect a4Page = CGRectMake(0, 0, DOC_WIDTH, DOC_HEIGHT);

    NSDictionary *fileMetaData = [[NSDictionary alloc] init];

    if (!UIGraphicsBeginPDFContextToFile(newFilePath, a4Page, fileMetaData )) {
        NSLog(@"error creating PDF context");
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();
    UIGraphicsBeginPDFPage();

    CGContextSetTextDrawingMode (context, kCGTextFill);
    CGContextSelectFont (context, [font cStringUsingEncoding:NSUTF8StringEncoding], fontSize, kCGEncodingMacRoman);                                                 
    CGContextSetFillColorWithColor(context, [color CGColor]);

    CGMutablePathRef path = CGPathCreateMutable();

    CGRect bounds = CGRectMake(LEFT_MARGIN, 
                               TOP_MARGIN, 
                               DOC_WIDTH - RIGHT_MARGIN - LEFT_MARGIN, 
                               DOC_HEIGHT - TOP_MARGIN - BOTTOM_MARGIN
                               );

    CGPathAddRect(path, NULL, bounds);

    // Initialize an attributed string.
    CFMutableAttributedStringRef attrString =
    CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
    CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)content);

    // Create the framesetter with the attributed string.
    CTFramesetterRef framesetter =
    CTFramesetterCreateWithAttributedString(attrString);

    // Create the frame and draw it into the graphics context
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CFRange visibleRange = CTFrameGetVisibleStringRange(frame);

    if (visibleRange.length < [content length] ) {
        NSLog(@"WARNING: Not all displayed on a single page");
    }

    CFRelease(attrString);
    CFRelease(framesetter);

    if(frame) {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, 0, bounds.origin.y); 
        CGContextScaleCTM(context, 1, -1); 
        CGContextTranslateCTM(context, 0, -(bounds.origin.y + bounds.size.height)); 
        CTFrameDraw(frame, context);
        CGContextRestoreGState(context); 
        CFRelease(frame);       
    }

    UIGraphicsEndPDFContext();

    [fileMetaData release];
}
Johnsonjohnsonese answered 4/5, 2010 at 16:3 Comment(0)
O
6

I actually got multi page PDF creation working by modifying the code above, like:

- (void) createPDF:(NSString *)fileName withContent:(NSString *)content forSize:(int)fontSize andFont:(NSString *)font andColor:(UIColor *)color {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *newFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:fileName];

CGRect a4Page = CGRectMake(0, 0, DOC_WIDTH, DOC_HEIGHT);

NSDictionary *fileMetaData = [[NSDictionary alloc] init];

if (!UIGraphicsBeginPDFContextToFile(newFilePath, a4Page, fileMetaData )) {
    NSLog(@"error creating PDF context");
    return;
}

BOOL done = NO;

CGContextRef context = UIGraphicsGetCurrentContext();

CFRange currentRange = CFRangeMake(0, 0);

CGContextSetTextDrawingMode (context, kCGTextFill);
CGContextSelectFont (context, [font cStringUsingEncoding:NSUTF8StringEncoding], fontSize, kCGEncodingMacRoman);                                                 
CGContextSetFillColorWithColor(context, [color CGColor]);
// Initialize an attributed string.
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString, currentRange, (CFStringRef)content);

// Create the framesetter with the attributed string.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);

do {
    UIGraphicsBeginPDFPage();



    CGMutablePathRef path = CGPathCreateMutable();

    CGRect bounds = CGRectMake(LEFT_MARGIN, 
                               TOP_MARGIN, 
                               DOC_WIDTH - RIGHT_MARGIN - LEFT_MARGIN, 
                               DOC_HEIGHT - TOP_MARGIN - BOTTOM_MARGIN);

    CGPathAddRect(path, NULL, bounds);



    // Create the frame and draw it into the graphics context
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, currentRange, path, NULL);

    if(frame) {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, 0, bounds.origin.y); 
        CGContextScaleCTM(context, 1, -1); 
        CGContextTranslateCTM(context, 0, -(bounds.origin.y + bounds.size.height)); 
        CTFrameDraw(frame, context);
        CGContextRestoreGState(context); 

        // Update the current range based on what was drawn.
        currentRange = CTFrameGetVisibleStringRange(frame);
        currentRange.location += currentRange.length;
        currentRange.length = 0;

        CFRelease(frame);       
    }

    // If we're at the end of the text, exit the loop.
    if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)attrString))
        done = YES;
}
while(!done);

UIGraphicsEndPDFContext();

[fileMetaData release];
CFRelease(attrString);
CFRelease(framesetter);
}

However, as mentioned above, it ignores the font I try to set. I always get something, looking like "Helvetica".

So, there is currently no way to create a PDF file on an iPad/iPhone, that embeds the font used on the device? I can hardly believe that. I would have at least hoped for those "usual suspects" fonts , like: Courier, Times New Roman, etc... to be supported.

If anyone out there has more information or useful tips on workarounds, please feel welcome to share.

Thanks in advance.

Overnice answered 16/8, 2010 at 5:8 Comment(1)
I am getting bad access for CFAttributedStringReplaceString (attrString, currentRange, (CFStringRef)content).Anyone any help plz ?Vines
J
2

Here is a method that will create a new PDF document. It does not do text formatting though.

    - (void) createNewPDF: (NSString *) saveFileName withContent: (NSString *) content forSize: (int) fontSize andFont:(NSString *) font andColor: (UIColor *) color
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *newFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:saveFileName];

    CGRect a4Page = CGRectMake(0, 0, 595, 842);

    NSDictionary *fileMetaData = [[NSDictionary alloc] init];

    if (!UIGraphicsBeginPDFContextToFile(newFilePath, a4Page, fileMetaData )) {
        NSLog(@"error creating PDF context");
        return;
    }

    CGContextRef mpdfContext = UIGraphicsGetCurrentContext();
    UIGraphicsBeginPDFPage();
    CGContextSetTextMatrix(mpdfContext, CGAffineTransformMake(1, 0, 0, -1, 0, 0));
    CGContextSetTextDrawingMode (mpdfContext, kCGTextFill);
    CGContextSelectFont (mpdfContext, [font cStringUsingEncoding:NSUTF8StringEncoding], fontSize, kCGEncodingMacRoman);                                                 
    CGContextSetFillColorWithColor(mpdfContext, [color CGColor]);
    CGContextShowTextAtPoint (mpdfContext, 20, 20, [content cStringUsingEncoding:NSUTF8StringEncoding], [content length]);
    UIGraphicsEndPDFContext();

}
Johnsonjohnsonese answered 3/5, 2010 at 14:3 Comment(1)
Those error messages still appear, but can be ignored. Also note that the PDF doc has a bug in it that it doesn't embed the font, and the text is not visible on Windows or on online apps like Google Docs. This is a bug in the SDK and there is a radar existing on it. Search the Apple developer forums for more info.Johnsonjohnsonese
C
2

just to let you know that the error message:

invalid Type1 font: unable to stream font

and: FT_Load_Glyph failed: error 6.

disappeared in iOS 4.2

Coat answered 20/4, 2011 at 0:51 Comment(0)
J
-1

This is a better solution as it uses the correct coordinate transform to get the text to print from the top down.

#define LEFT_MARGIN 25
#define RIGHT_MARGIN 25
#define TOP_MARGIN 35
#define BOTTOM_MARGIN 50
#define BOTTOM_FOOTER_MARGIN 32
#define DOC_WIDTH 595
#define DOC_HEIGHT 842

- (void) createPDF:(NSString *)fileName withContent:(NSString *)content forSize:(int)fontSize andFont:(NSString *)font andColor:(UIColor *)color
{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *newFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:fileName];

    CGRect a4Page = CGRectMake(0, 0, DOC_WIDTH, DOC_HEIGHT);

    NSDictionary *fileMetaData = [[NSDictionary alloc] init];

    if (!UIGraphicsBeginPDFContextToFile(newFilePath, a4Page, fileMetaData )) {
        NSLog(@"error creating PDF context");
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();
    UIGraphicsBeginPDFPage();

    CGContextSetTextDrawingMode (context, kCGTextFill);
    CGContextSelectFont (context, [font cStringUsingEncoding:NSUTF8StringEncoding], fontSize, kCGEncodingMacRoman);                                                 
    CGContextSetFillColorWithColor(context, [color CGColor]);

    CGMutablePathRef path = CGPathCreateMutable();

    CGRect bounds = CGRectMake(LEFT_MARGIN, 
                               TOP_MARGIN, 
                               DOC_WIDTH - RIGHT_MARGIN - LEFT_MARGIN, 
                               DOC_HEIGHT - TOP_MARGIN - BOTTOM_MARGIN
                               );

    CGPathAddRect(path, NULL, bounds);

    // Initialize an attributed string.
    CFMutableAttributedStringRef attrString =
    CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
    CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)content);

    // Create the framesetter with the attributed string.
    CTFramesetterRef framesetter =
    CTFramesetterCreateWithAttributedString(attrString);

    // Create the frame and draw it into the graphics context
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CFRange visibleRange = CTFrameGetVisibleStringRange(frame);

    if (visibleRange.length < [content length] ) {
        NSLog(@"WARNING: Not all displayed on a single page");
    }

    CFRelease(attrString);
    CFRelease(framesetter);

    if(frame) {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, 0, bounds.origin.y); 
        CGContextScaleCTM(context, 1, -1); 
        CGContextTranslateCTM(context, 0, -(bounds.origin.y + bounds.size.height)); 
        CTFrameDraw(frame, context);
        CGContextRestoreGState(context); 
        CFRelease(frame);       
    }

    UIGraphicsEndPDFContext();

    [fileMetaData release];
}
Johnsonjohnsonese answered 4/5, 2010 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.