Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Q&As > QuickTime > Import & Export >

Viewing multi-page PDF files


Q: I'm trying to view a multi-page PDF file using the QuickTime 6 graphics importers. I'm able to view the first page, however the GraphicsImporterGetImageCount API call always returns 1 for the number of pages (images) even for documents that have more than one page. How can I view all the pages?

A: The PDF graphics importer only displays the first page of a multi-page PDF file. However, the PDF movie importer can display any page. The code listing below shows how to draw each page of a multi-page PDF using the PDF movie importer. Simply open the file as a movie, then step through each frame (page) in the movie.

This same technique can be used for other file formats such as animated GIF files. For more information see TN2018 .



Listing 1. Drawing each page of a multi-page PDF file.



#include <QuickTime/QuickTime.h>

//////////
//
// drawMultiPagePDF
//
// Open the multi-page PDF document file as a movie, then 
// step through each page and draw the page to the 
// specified port
//
//////////

void drawMultiPagePDFtoPort(FSSpec *pdfFileSpec, CGrafPtr thePort)
{
    OSErr   err = noErr;
    Movie   theMovie = nil;
    short   movieFileRefNum = 0;
    Track   firstVideoTrack = nil;

    // open the PDF file 
    err = OpenMovieFile(pdfFileSpec, &movieFileRefNum, fsRdPerm);
    if (err) goto bail;
    
    // create a movie from that file
    err = NewMovieFromFile(&theMovie,
                           movieFileRefNum,
                           NULL,
                           NULL,
                           newMovieActive,
                           NULL);
    if (err) goto bail;

    // set the drawing port for the movie
    SetMovieGWorld(theMovie,thePort,nil);
    if (GetMoviesError()) goto bail;
    
    // get the first video track in the movie
    firstVideoTrack = GetMovieIndTrackType(theMovie,
                                           1,
                                           VideoMediaType,
                                           movieTrackMediaType);
    if (firstVideoTrack)
    {
        long frameCount  = 0;

        // get the video track frame count
        frameCount = getFrameCount (firstVideoTrack);
        for ( ; frameCount > 0; frameCount--)
        {
            // draw a frame (PDF page) into the port
            drawMovieFrameNextOrPrev (theMovie, fixed1);
        }
    }

bail:
    if (movieFileRefNum)
    {
        CloseMovieFile(movieFileRefNum);
    }
    
    if (theMovie)
    {
        DisposeMovie(theMovie);
    }

}

//////////
//
// getFrameCount
// Get the number of frames in the specified movie track.
// We return the value -1 if an error occurs and we cannot
// determine the number of frames in the track.
//
// Based (loosely) on frame-counting code in ConvertToMovie
// Jr.c.
// 
// We count the frames in the track by stepping through all 
// of its interesting times (the places where the track 
// displays a new sample).
//
//////////

long getFrameCount (Track theTrack)
{   
    long        myCount = -1;
    short       myFlags;
    TimeValue   myTime = 0;
    
    if (theTrack == NULL)
        goto bail;
        
    // we want to begin with the first frame (sample) in the track
    myFlags = nextTimeMediaSample + nextTimeEdgeOK;

    while (myTime >= 0) {
        myCount++;
        
    // look for the next frame in the track; when there are no more 
    // frames, myTime is set to -1, so we'll exit the while loop
        GetTrackNextInterestingTime(theTrack,
                                    myFlags,
                                    myTime,
                                    fixed1,
                                    &myTime,
                                    NULL);
        
    // after the first interesting time, don't include the time we're 
    // currently at
        myFlags = nextTimeStep;
    }

bail:
    return(myCount);
}

//////////
//
// drawMovieFrameNextOrPrev
// Draw the next or previous video sample of a QuickTime movie.
// If theRate is 1, the next video sample is drawn; if theRate is -1,
// the previous sample is drawn.
//
//////////

OSErr drawMovieFrameNextOrPrev (Movie theMovie, Fixed theRate)
{
    TimeValue       myCurrTime;
    TimeValue       myNextTime;
    short           myFlags;
    OSType          myTypes[1];
    OSErr           myErr = noErr;
    
    if (theMovie == NULL)
        return(invalidMovie);
    
    // want the next frame in the movie's media
    myFlags = nextTimeStep;
    // we want video samples
    myTypes[0] = VisualMediaCharacteristic;     
    myCurrTime = GetMovieTime(theMovie, NULL);

    GetMovieNextInterestingTime(theMovie,
                                myFlags,
                                1,
                                myTypes,
                                myCurrTime,
                                theRate,
                                &myNextTime,
                                NULL);
    myErr = GetMoviesError();
    if (myErr != noErr)
        return(myErr);
        
    myErr = drawMovieFrameAtTime(theMovie, myNextTime);
    
    return(myErr);
}

//////////
//
// drawMovieFrameAtTime
// Draw the video sample of a QuickTime movie at the specified time.
//
//////////

OSErr drawMovieFrameAtTime (Movie theMovie, TimeValue theTime)
{
    OSErr myErr = noErr;
    
    if (theMovie == NULL)
        return(invalidMovie);
    
    // make sure that the specified time lies within the movie's 
    // temporal bounds
    if ((theTime < 0) || (theTime > GetMovieDuration(theMovie)))
        return(paramErr);
    
    SetMovieTimeValue(theMovie, theTime);
    myErr = GetMoviesError();
    if (myErr != noErr)
        goto bail;
        
    // the following call to MoviesTask is not necessary if you 
    // are handling movie controller events in your main event 
    // loop (by passing the event to MCIsPlayerEvent); 
    // they don't hurt, however.
    
    // redraw the movie immediately by calling MoviesTask        
    MoviesTask(theMovie, 0L);
    myErr = GetMoviesError();

bail:
    return(myErr);
}



[Mar 05, 2003]