iOS CTFramesetterCreateWithAttributedString not sizing correctly

I am building an app that takes a few different text files and strings them together, then builds a pdf out of them. I needed to add the file's text add separate times so I can add in hyperlinks to the text from each file. I have made some progress and got it to display almost accurately, but it appears CTFramesetterCreateWithAttributedString is not sizing correctly.

For example, the first of the three files displays too much, in other words, after the text ends there is a blank page that comes after it. The second text file displays just fine, but the third has a large chunk from the beginning missing. I do not believe it has anything to do with the files themselves, because I get the same problem if I reverse the order in which the files are rendered. The first file (whichever file it is) has a blank page at the end, and the third file has the first page or so missing. Does anyone know what could be causing this phenomenon?

- (void)savePDFFile:(NSString *)file_Name
 NSString *homeDir = NSHomeDirectory();
 NSString *saveDirectory = [NSString stringWithFormat: @"%@/%@", homeDir, @"Documents/"]; 

 NSArray *fileAr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:saveDirectory error:nil];
 NSMutableArray *textArray = [[NSMutableArray alloc] init];
 NSInteger currentPage = 0;
 NSInteger currentFile = 0;

 for (NSString *string in fileAr) {
    if([string hasSuffix:@"txt"]){
        NSString *file = [NSString stringWithFormat: @"%@/%@", saveDirectory, string];
        NSString *text =[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
        completeString = [NSString stringWithFormat:@"%@%@", completeString, text];

        NSString* pdfFileName = file_Name;

        // Create the PDF context using the default page size of 612 x 792.
        UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);

        CFRange currentRange = CFRangeMake(0, 0);
        for (NSString *string in textArray){
        BOOL done = NO;
            NSString *thisText = [textArray objectAtIndex:currentFile];
            CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (CFStringRef)thisText, NULL);                                
            CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)currentText);
            currentPage = currentPage;
        do {
            // Mark the beginning of a new page.
            UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);

            // Draw a page number at the bottom of each page
            [self drawPageNumber:currentPage];

            // Render the current page and update the current range to
            // point to the beginning of the next page.
            currentRange = [self renderPage:currentPage withTextRange:currentRange andFramesetter:framesetter];
            // If we're at the end of the text, exit the loop.
            if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)currentText))
                done = YES;

        } while (!done);
            currentFile ++;

        // Close the PDF context and write the contents out.


// Use Core Text to draw the text in a frame on the page.
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
 // Get the graphics context.
CGContextRef    currentContext = UIGraphicsGetCurrentContext();

// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);

// Create a path object to enclose the text. Use 72 point
// margins all around the text.
CGRect    frameRect = CGRectMake(72, 72, 500, 648);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);

// Get the frame that will do the rendering.
// The currentRange variable specifies only the starting point. The framesetter
// lays out as much text as will fit into the frame.
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);

// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, 792);
CGContextScaleCTM(currentContext, 1.0, -1.0);

// Draw the frame.
CTFrameDraw(frameRef, currentContext);

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

return currentRange;


I have figured it out.

I placed "currentPage = currentPage;" in my code just to have a spot to put a breakpoint after the framesetter had been set so I could watch it. Haven't quite mastered the debugger just yet. It wasn't causing a problem, obviously, but if I replaced that line of code with "currentRange.location = 0;", resetting the range after each loop. Problem solved. Strange, as originally it was the resetting of currentRange that was causing the problem.

Anyway, with the change I list above, along with the second answer to this question (minus the last four lines), the problem is solved!

Need Your Help

Is there a transformation matrix that can scale the x and/or y axis logarithmically?

wpf math matrix transform

I'm using .net WPF geometry classes to graph waveforms. I've been using the matrix transformations to convert from the screen coordinate space to my coordinate space for the waveform. Everything w...

Eloquent: Scope for getting related models?

scope eloquent

I have 3 models: User, Project, Task