iOS2013. 1. 15. 19:58


http://cafe.daum.net/iLogic/915W/20?docid=1KHkj915W2020110321201150

PDF 문서 생성, 출력, 변환

PDF 문서는 소형 프로그래밍 언어로 작성된 명령들로 해상도 독립 벡터 그래픽, 텍스트, 이미지를 저장한다. PDF 문서는 이미지와 텍스트를 여러 페이지 포함할 수 있다. PDF 는 크로스 플랫폼, 읽기 전용 문서, 해상도 독립 그래픽 드로잉에 유용하다.

모든 어플에 대해 Quartz 는 그림 13-1 처럼 어플의 드로잉 연산을 보존하는 충실도가 높은 PDF 문서를 생성한다. 결과 PDF 는 시스템의 다른 일부나 외우 업체 제품으로 특정 프린터나 웹을 위해 특정한 목적으로 최적화될 수도 있다. Quartz 에서 생성된 PDF 문서는 미리보기나 Acrobat 에서 볼 수 있다.

그림 13-1  Quartz 는 고해상도 PDF 문서를 생성한다.

Quartz 는 "디지털 종이" 로 PDF 를 사용할 뿐만 아니라 PDF 를 표시하고 생성하고, PDF 관련 작업들을 사용할 수 있는 수많은 API 함수중 일부를 포함하고 있다. 다음 내용을 다룬다.

PDF 언어와 문법을 포함한 PDF 에 대한 자세한 정보는 PDF 레퍼런스 네 번째 판인 버전 1.5 를 참고해라.

PDF 열기와 화면 출력

Quartz 는 PDF 문서를 표현하기 위해 CGPDFDocumentRef 데이터 타입을 제공한다.CGPDFDocumentCreateWithProvider 함수나 CGPDFDocumentCreateWithURL 함수를 사용하여 CGPDFDocument 객체를 생성해야 한다. CGPDFDocument 객체를 생성한 후, 그래픽 콘텍스트에 드로잉할 수 있다. 그림 13-2 는 PDFViewer 샘플 어플에서 표시된 PDF 문서를 보여준다. Xcode 도구 CD 를 인스톨할 후, 이 어플의 Xcode 프로젝트를 다음 위치에서 찾을 수 있다.

/Developer/Examples/Quartz/PDF/PDFViewer

그림 13-2  PDFViewer 샘플 어플에 의해 표시된 PDF 문서

코드 13-1 은 CGPDFDocument 객체를 생성하고 문서내의 페이지수를 얻는 방법을 보여준다.

코드 13-1  PDF 파일로부터 CGPDFDocument 객체를 생성하는 함수

CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename)
{
    CFStringRef path;
    CFURLRef url;
    CGPDFDocumentRef document;
 
    path = CFStringCreateWithCString (NULL, filename,
                         kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 1
                        kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    document = CGPDFDocumentCreateWithURL (url);// 2
    CFRelease(url);
    count = CGPDFDocumentGetNumberOfPages (document);// 3
    if (count == 0) {
        printf("`%s' needs at least one page!", filename);
        return NULL;
    }
    return document;
}

코드 설명:

  1. 디스플레이할 PDF 파일의 파일명을 나타내는 CFString 객체로 부터 CFURL 객체를 생성하기 위해 코어 파운데이션 함수를 호출해야 한다.

  2. CFURL 객체로 부터 CGPDFDocument 객체를 생성한다.

  3. 다음 코드에서 문서가 최소 한 페이지를 갖고 있는지 확인하기 위해서 PDF 의 페이지 수를 얻는다.

코드 13-2는 PDF 페이지를 그래픽 콘텍스트에 드로잉하는 방법을 보여준다.

코드 13-2  PDF 페이지를 드로잉하는 함수

void MyDisplayPDFPage (CGContextRef myContext,
                    size_t pageNumber,
                    const char *filename)
{
    CGPDFDocumentRef document;
    CGPDFPageRef page;
    CGRect box;
 
    document = MyGetPDFDocumentRef (filename);// 1
    page = CGPDFDocumentGetPage (document, pageNumber);// 2
    CGContextDrawPDFPage (myContext, page);// 3
    CGPDFDocumentRelease (document);// 4
}

코드 설명:

  1. 대입한 파일이름으로 부터 CGPDFDocument 객체를 생성하기 위해 함수를 호출한다.

  2. PDF 문서로 부터 명시한 페이지 번호의 페이지를 얻는다.  

  3. CGContextDrawPDFPage 함수를 호출하여 PDF 파일로 부터 명시한 페이지를 드로잉한다. 그래픽 콘텍스트와 드로잉할 페이지를 대입해야만 한다. iPhone OS 나 Mac OS X v10.3 이후 버전에서 어플을 수행하려면, 이전의CGContextDrawPDFDocument 함수대신에 이 함수를 사용하는 것이 좋다.

  4. CGPDFDocument 객체를 해제한다.

PDF 페이지용 변환을 생성

Quartz 는 PDF 페이지의 한 상자를 대입한 사각형으로 매핑하는 affine 변환을 생성하는 CGPDFPageGetDrawingTransform함수를 제공한다. 이 함수의 형식은 다음과 같다.

CGAffineTransform CGPDFPageGetDrawingTransform (
        CGPPageRef page,
        CGPDFBox box,
        CGRect rect,
        int rotate,
        bool preserveAspectRatio
);

함수는 다음 알고리즘을 사용하여 affine 변환을 리턴한다.

  • 파라미터에 대입하는 media, crop, bleed, trim, art 와 같은 PDF 박스의 타입과 명시된 PDF 페이지의 /MediaBox 엔트리와 관련된 사각형을 교차시킨다. 교차하여 교집합 부분이 유효한 결과 사각형이 된다.

  • PDF 페이지의 /Rotate 엔트리에 의해 명시된 값에 의해서 유효 사각형을 회전시킨다.

  • 결과 사각형을 파라미터로 제공한 사각형의 중심으로 옮긴다.

  • 대입한 rotate 파라미터의 값이 0 이 아니고 90 의 배수면, 함수는 대입한 각도로 유효 사각형을 회전시킨다. 양수 값은 오른쪽으로 사각형을 회전시키며, 음수 값은 사각형을 왼쪽으로 회전시킨다. 전달하는 각도는 라디안 값이 아니다. PDF 페이지의 /Rotate 엔트리도 회전을 포함한다. 대입하는 rotate 파라미터는 /Rotate 엔트리와 조합된다.

  • 필요하면 유효 사각형을 확대/축소한다. 그래서, 대입한 사각형의 가장자리와 일치시킨다. 

  • preserveAspectRatio 파라미터에 true 를 전달하여 가로 세로의 비를 보존한다면, 마지막 사각형은 rect 파라미터에서 명시된 사각형의 제한된 가장자리와 일치시킨다.

예를 들어 그림 13-3 에서 보이는 PDF 파일을 보여주는 어플을 작성할 때 이 함수를 사용할 수 있다. 왼쪽과 오른쪽으로 회전하는 기능을 제공하고자 한다면, 현재 윈도우 크기와 회전하는 설정에 대한 적절한 변환을 계산하기 위해CGPDFPageGetDrawingTransform 를 호출할 수 있다.

그림 13-3  오른쪽으로 90 도 회전된 PDF 페이지

코드 13-3 은 함수에 전달된 파라미터를 사용하여 PDF 페이지용 affine 변환을 생성하는 함수가 변환을 적용하고 PDF 페이지를 드로잉하는 방법을 보여준다.

코드 13-3  PDF 페이지용 affine 변환 생성

void MyDrawPDFPageInRect (CGContextRef context,
                    CGPDFPageRef page,
                    CGPDFBox box,
                    CGRect rect,
                    int rotation,
                    bool preserveAspectRatio)
{
    CGAffineTransform m;
 
    m = CGPDFPageGetDrawingTransform (page, box, rect, rotation,// 1
                                    preserveAspectRato);
    CGContextSaveGState (context);// 2
    CGContextConcatCTM (context, m);// 3
    CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));// 4
    CGContextDrawPDFPage (context, page);// 5
    CGContextRestoreGState (context);// 6
}

코드 설명:

  1. 함수에 제공된 파라미터로 부터 affine 변환을 생성한다.

  2. 그래픽 상태를 저장한다.

  3. CTM 을 affine 변환과 연관시킨다.

  4. 그래픽 콘텍스트를 box 파라미터에 대입된 사각형으로 자른다. CGPDFPageGetBoxRect 함수는 대입한 상수kCGPDFMediaBoxkCGPDFCropBoxkCGPDFBleedBox,kCGPDFTrimBoxkCGPDFArtBox 과 관련된 (media, crop, bleed, trim, art box) 형 사각형을 경계로하는 페이지를 얻는다.

  5. PDF 페이지를 변환되고 잘린 콘텍스트에 드로잉한다.

  6. 그래픽 상태를 복원한다.

PDF 파일 생성

 PDF 파일을 그래픽 콘텍스트에 드로잉하는 것과 같이 Quartz 2D 를 사용하여 PDF 파일을 생성하는 것은 쉽다. PDF 파일의 위치를 명시하고, PDF 그래픽 콘텍스트를 설정하고, 다른 그래픽 콘텍스트에서 사용했던 동일한 드로잉 루틴을 사용하게 된다. 코드 13-4 의 MyCreatePDFFile 함수는 PDF 를 생성하기 위해 사용하는 모든 작업을 보여줄 것이다.

코드는 CGContextBeginPage 함수와 CGContextEndPage 함수를 호출하여 PDF 페이지를 묘사한다. iPhone OS 와 Mac OS X v10.4 이후 버전에서는, CGPDFContextBeginPage 함수와 CGPDFContextEndPage 함수를 대신 사용할 수 있다. 새로 추가된 함수들의 장점은 media, crop bleed, trim, art box 의 페이지 속성을 대입하기 위해 CFDictionary 를 전달할 수 있다는 점이다.

사전용 키 상수의 목록과 이들에 대한 정보는 CGPDFContext 레퍼런스 를 참고해라.

코드 13-4  PDF 를 생성하는 함수

void MyCreatePDFFile (CGRect pageRect, const char *filename)// 1
{
    CGContextRef pdfContext;
    CFStringRef path;
    CFURLRef url;
    CFMutableDictionaryRef myDictionary = NULL;
 
    path = CFStringCreateWithCString (NULL, filename, // 2
                                kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 3
                     kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    myDictionary = CFDictionaryCreateMutable(NULL, 0,
                        &kCFTypeDictionaryKeyCallBacks,
                        &kCFTypeDictionaryValueCallBacks); // 4
    CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
    CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
    pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary); // 5intent 
    CFRelease(myDictionary);
    CFRelease(url);
    CGContextBeginPage (pdfContext, &pageRect); // 6
    myDrawContent (pdfContext);// 7
    CGContextEndPage (pdfContext);// 8
    CGContextRelease (pdfContext);// 9
}

코드 설명:

  1. PDF 페이지의 크기를 나타내는 사각형과 파일명을 나타내는 문자열을 파라미터로 받는다.

  2. MyCreatePDFFile 함수에 전달된 파일명으로 부터 CFString 객체를 생성한다.

  3. CFString 객체로 부터 CFURL 객체를 생성한다.

  4. 메타데이터를 얻기 위해서 빈 CFDictionary 객체를 생성한다. 다음 두 줄은 타이틀과 작가 이름을 추가하는 것이다.CFDictionarySetValue 함수를 사용하여 여러 키-값 쌍을 추가할 수 있다. 사전을 생성하는데 대한 자세한 정보는CFDictionary 레퍼런스 을 참고해라.

  5. 다음의 3 개의 파라미터를 전달하여 PDF 그래픽 콘텍스트를 생성한다.

    • PDF 데이터의 위치를 나타내는 CFURL 객체.

    • PDF 페이지의 기본 크기와 위치를 정의하는 사각형에 대한 포인터. 사각형의 원점은 일반적으로 (0, 0) 이다. Quartz 는 이 사각형을 페이지의 미디어 박스의 기본 영역으로 사용한다. NULL 을 전달하면, Quartz 는 8.5 x 11 인치(612 x 792 픽셀)의 기본 페이지 크기를 사용한다.

    • PDF 메타데이터를 포함하는 CFDictionary 객체. 추가할 메타데이터가 없다면 NULL 을 전달한다. 

      iPhone OS 와 Mac OS X v10.4 에서는 부분 형식, 조건, 조건 식별자, 레지스트리 이름, 목적 파일 프로필, 목적 장치나 제조 조건에 관한 추가 정보나 설명을 포함하는 사람이 읽ㅅ을 수 있는 문자열 등의 출력 옵션을 표시하기 위해 CFDictionary 객체를 사용할 수 있다. 출력 옵션에 대한 자세한 정보는 CGPDFContext 레퍼런스를 참고해라.

  6. 페이지의 시작을 나타낸다. PDF 와 같은 다중 페이지를 제공하는 그래픽 콘텍스트를 사용할 때, 출력에서 페이지의 경계를 나타내기 위해 CGContextEndPage 와 CGContextBeginPage 함수를 호출해야 한다. Quartz 는 페이지 기반 콘텍스트에서 페이지의 경계를 넘어가는 외부에서 실행된 모든 드로잉 연산은 무시한다. 

    iPhone OS 와 Mac OS X v10.4 이후 버전에서, 페이지의 속성을 정의하기 위해 키-값 쌍을 포함하는 그래픽 콘텍스트와 CFDictionary 를 제공하는 CGPDFContextBeginPage 함수를 대신 사용할 수 있다.

  7. PDF 콘텍스트에 콘텢츠를 드롱이하기 위해 어플에서 정의한 함수를 호출한다. 여기에 드로잉 루틴들을 작성하면 된다.

  8. 페이지 기반 그래픽 콘텍스트에 페이지가 끝났다고 알린다.

    iPhone OS 와 Mac OS X v10.4 이후 버전에서 이전에 CGPDFContextBeginPage 함수를 호출했다면, 페이지의 끝을 알리기 위해 CGPDFContextEndPage 함수를 사용해야만 했다.

  9. PDF 콘텍스트를 해제한다.

링크 추가

생성한 PDF 콘텍스트에 링크와 지점을 추가할 수 있다. iPhone OS 와 Mac OS X v10.4 부터, Quartz 는 링크에 관한 정보와 파라미터로 PDF 그래픽 콘텍스트를 갖는 다음의 3 가지 함수를 제공한다.

  • CGPDFContextSetURLForRect 는 현재 PDF 페이지에서 사각형을 클릭할 때 오픈할 URL 을 명시하도록 한다.

  • CGPDFContextSetDestinationForRect 는 현재 PDF 페이지에서 사용자가 사각형을 클릭할 때 목적지로 이동하도록 설정한다. 목적지 이름을 명시해야 한다.

  • CGPDFContextAddDestinationAtPoint 는 현재 PDF 페이지에서 점을 클릭할 때 이동할 목적지를 설정하도록 한다. 목적지 이름을 명시해야 한다.

PDF 콘텐츠 보호

iPhone OS 와 Mac OS X v10.4 부터 가능한 PDF 콘텐츠를 보호하려면, CGPDFContextCreate 함수에 전달할 보조 사전에서 명시할 수 있는 여러 보안 옵션들이 존재한다. 소유자 패스워드, 사용자 패스워드, PDF 가 보조 사전에 다음 키를 포함하여 복사될 수 있는지 프린트될 수 있는지를 설정할 수 있다. 

  • kCGPDFContextOwnerPassword 는 PDF 문서의 소유자 패스워드를 정의할 때 사용한다. 이 키가 대입되면, 문서는 소유자 패스워드를 값으로 사용하여 암호화된다. 그렇지 않으면, 문서는 암호화되지 않는다. 이 키 값은 ASCII 로 표현될 수 있는 CFString 객체가 되어야 한다. 처음 32 바이트만 패스워드로 사용된다. 이 키의 디폴트 값은 없다. 이 키의 값이 ASCII 로 표현될 수 없다면, 문서는 생성되지 않으며 생성 함수는 NULL 을 리턴한다. iPhone OS 와 Mac OS X v10.4 에서 Quartz 는 40 비트 암호화를 사용한다.

  • kCGPDFContextUserPassword 는 PDF 문서의 사용자 패스워드를 정의한다. 문서가 암호화되면, 이 키 값은 문서의 사용자 패스워드가 된다. 이 값이 명시되지 않으면 사용자 패스워드는 빈 문자열이 된다. 이 키 값은 ASCII 암호화로 표현될 수 있는 CFString 객체가 되어야 한다. 첫 번째 32 바이트만 패스워드로 사용된다. 이 키 값이 ASCII 로 표현될 수 없으면, 문서는 생성되지 않고, 생성함수는 NULL 을 리턴한다.

  • kCGPDFContextAllowsPrinting 는 문서가 사용자 패스워드로 비공개가 아닐 때 프린트할 수 있는지를 나타낸다. 이 키 값은 CFBoolean 객체가 되어야 한다. 이 키의 디폴드 값은 kCFBooleanTrue 이다.

  • kCGPDFContextAllowsCopying 는 문서가 사용자 패스워드로 비공개가 아닌 경우 복사될 수 있는지를 나타낸다. 이 키 값은 CFBoolean 객체이어야 한다. 이 키의 디폴트 값은 kCFBooleanTrue 이다.

다음 강좌의 코드 14-4 는 PDF 문서가 공개인지 비공개인지를 검사하고, 패스워드를 사용하여 문서를 오픈하는 코드를 보여줄 것이다.

 

Posted by 삼스