Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
266 views
in Technique[技术] by (71.8m points)

ipad - 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
            currentPage++;
            [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 ++;
            CFRelease(framesetter);
            CFRelease(currentText);
        }

        // Close the PDF context and write the contents out.
        UIGraphicsEndPDFContext();


}


// Use Core Text to draw the text in a frame on the page.
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
   andFramesetter:(CTFramesetterRef)framesetter
  {
 // 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);
CGPathRelease(framePath);

// 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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...