iOS SDK - 프로그래밍 방식으로 PDF 파일 생성
프로그래밍 방식으로 PDF 파일을 작성할 때 CoreGraphics 프레임워크를 사용하는 것은 지루한 작업이라고 생각합니다.
제 앱 전체의 뷰에서 다양한 객체를 사용하여 프로그래밍 방식으로 PDF를 만들고 싶습니다.
iOS SDK를 위한 좋은 PDF 튜토리얼이 있는지 알고 싶습니다. 아마도 도서관에서 떨어질 것입니다.
PDF 생성 튜토리얼이라는 이 튜토리얼을 본 적이 있지만, 대부분은 C로 작성되었습니다.좀 더 오브젝티브-C 스타일을 찾고 있습니다.이것은 또한 줄과 다른 물체가 배치될 위치를 계산해야 하는 PDF 파일에 쓰는 우스꽝스러운 방법처럼 보입니다.
void CreatePDFFile (CGRect pageRect, const char *filename)
{
// This code block sets up our PDF Context so that we can draw to it
CGContextRef pdfContext;
CFStringRef path;
CFURLRef url;
CFMutableDictionaryRef myDictionary = NULL;
// Create a CFString from the filename we provide to this method when we call it
path = CFStringCreateWithCString (NULL, filename,
kCFStringEncodingUTF8);
// Create a CFURL using the CFString we just defined
url = CFURLCreateWithFileSystemPath (NULL, path,
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
// This dictionary contains extra options mostly for 'signing' the PDF
myDictionary = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
// Create our PDF Context with the CFURL, the CGRect we provide, and the above defined dictionary
pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary);
// Cleanup our mess
CFRelease(myDictionary);
CFRelease(url);
// Done creating our PDF Context, now it's time to draw to it
// Starts our first page
CGContextBeginPage (pdfContext, &pageRect);
// Draws a black rectangle around the page inset by 50 on all sides
CGContextStrokeRect(pdfContext, CGRectMake(50, 50, pageRect.size.width - 100, pageRect.size.height - 100));
// This code block will create an image that we then draw to the page
const char *picture = "Picture";
CGImageRef image;
CGDataProviderRef provider;
CFStringRef picturePath;
CFURLRef pictureURL;
picturePath = CFStringCreateWithCString (NULL, picture,
kCFStringEncodingUTF8);
pictureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), picturePath, CFSTR("png"), NULL);
CFRelease(picturePath);
provider = CGDataProviderCreateWithURL (pictureURL);
CFRelease (pictureURL);
image = CGImageCreateWithPNGDataProvider (provider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385),image);
CGImageRelease (image);
// End image code
// Adding some text on top of the image we just added
CGContextSelectFont (pdfContext, "Helvetica", 16, kCGEncodingMacRoman);
CGContextSetTextDrawingMode (pdfContext, kCGTextFill);
CGContextSetRGBFillColor (pdfContext, 0, 0, 0, 1);
const char *text = "Hello World!";
CGContextShowTextAtPoint (pdfContext, 260, 390, text, strlen(text));
// End text
// We are done drawing to this page, let's end it
// We could add as many pages as we wanted using CGContextBeginPage/CGContextEndPage
CGContextEndPage (pdfContext);
// We are done with our context now, so we release it
CGContextRelease (pdfContext);
}
편집: iPhone 프로젝트에서 libHuru를 사용한 GitHub의 예입니다.
몇 가지...
첫째, iOS에서 CoreGraphics PDF 생성에 문제가 있어 PDF가 손상됩니다.iOS 4.1까지 이 문제가 존재한다는 것을 알고 있습니다(iOS 4.2는 테스트하지 않았습니다).이 문제는 글꼴과 관련이 있으며 PDF에 텍스트를 포함하는 경우에만 표시됩니다.증상은 PDF를 생성할 때 디버그 콘솔에 다음과 같은 오류가 표시된다는 것입니다.
<Error>: can't get CIDs for glyphs for 'TimesNewRomanPSMT'
까다로운 점은 결과 PDF가 일부 PDF 판독기에서는 잘 렌더링되지만 다른 위치에서는 렌더링되지 않는다는 것입니다.따라서 PDF를 여는 데 사용할 소프트웨어를 제어할 수 있는 경우 이 문제를 무시할 수 있습니다(예: iPhone 또는 Mac 데스크톱에만 PDF를 표시하려는 경우 CoreGraphics를 사용하면 됩니다).그러나 어디서나 작동하는 PDF를 만들어야 하는 경우에는 이 문제를 자세히 살펴봐야 합니다.다음은 몇 가지 추가 정보입니다.
해결 방법으로 iPhone에서 코어 그래픽 PDF 생성을 대체하는 libHaru를 성공적으로 사용했습니다.처음에는 libHaru가 제 프로젝트로 빌드하는 것이 조금 어려웠지만, 일단 제 프로젝트를 제대로 설정하면 제 요구에 맞게 잘 작동했습니다.
둘째, PDF 형식/레이아웃에 따라 Interface Builder를 사용하여 PDF 출력의 "템플릿" 역할을 하는 보기를 만드는 것을 고려할 수 있습니다.그런 다음 코드를 작성하여 보기를 로드하고 모든 데이터(예: UI 레이블의 텍스트 설정 등)를 입력한 다음 보기의 개별 요소를 PDF로 렌더링합니다.즉, IB를 사용하여 좌표, 글꼴, 이미지 등을 지정하고 코드를 작성하여 다양한 요소(예:UILabel
,UIImageView
모든 것을 하드 코딩할 필요가 없도록 일반적인 방법을 사용합니다.저는 이 접근 방식을 사용했고 그것은 제 요구에 아주 잘 맞았습니다.PDF의 포맷/레이아웃 요구에 따라 상황에 적합하지 않을 수도 있습니다.
편집: (첫 번째 댓글에 대한 답변)
이 구현은 상용 제품의 일부이므로 전체 코드를 공유할 수 없지만 일반적인 개요는 제공할 수 있습니다.
보기가 있는 .xib 파일을 만들고 보기 크기를 850 x 1100으로 조정했습니다(PDF는 8.5 x 11인치를 대상으로 했기 때문에 디자인 타임 좌표로/에서 쉽게 변환할 수 있습니다).
코드에서는 보기를 로드합니다.
- (UIView *)loadTemplate
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ReportTemplate" owner:self options:nil];
for (id view in nib) {
if ([view isKindOfClass: [UIView class]]) {
return view;
}
}
return nil;
}
그런 다음 다양한 요소를 채웁니다.태그를 사용하여 적절한 요소를 찾았지만 다른 방법으로 찾을 수 있습니다.예:
UILabel *label = (UILabel *)[templateView viewWithTag:TAG_FIRST_NAME];
if (label != nil) {
label.text = (firstName != nil) ? firstName : @"None";
그런 다음 PDF 파일에 뷰를 렌더링하는 함수를 호출합니다.이 함수는 뷰 계층 구조를 재귀적으로 이동하고 각 하위 뷰를 렌더링합니다.프로젝트의 경우 레이블, 이미지 보기 및 보기(내포된 보기)만 지원하면 됩니다.
- (void)addObject:(UIView *)view
{
if (view != nil && !view.hidden) {
if ([view isKindOfClass:[UILabel class]]) {
[self addLabel:(UILabel *)view];
} else if ([view isKindOfClass:[UIImageView class]]) {
[self addImageView:(UIImageView *)view];
} else if ([view isKindOfClass:[UIView class]]) {
[self addContainer:view];
}
}
}
예를 들어, addImageView(HPDF_ 함수는 libHaru에서 가져온 것)를 구현했습니다.
- (void)addImageView:(UIImageView *)imageView
{
NSData *pngData = UIImagePNGRepresentation(imageView.image);
if (pngData != nil) {
HPDF_Image image = HPDF_LoadPngImageFromMem(_pdf, [pngData bytes], [pngData length]);
if (image != NULL) {
CGRect destRect = [self rectToPDF:imageView.frame];
float x = destRect.origin.x;
float y = destRect.origin.y - destRect.size.height;
float width = destRect.size.width;
float height = destRect.size.height;
HPDF_Page page = HPDF_GetCurrentPage(_pdf);
HPDF_Page_DrawImage(page, image, x, y, width, height);
}
}
}
그것이 당신에게 아이디어를 줄 수 있기를 바랍니다.
답장이 늦었지만 pdf 생성으로 많은 어려움을 겪으면서 제 의견을 공유할 가치가 있다고 생각했습니다.Core 그래픽 대신 UIKit 메서드를 사용하여 pdf를 생성할 수도 있습니다.
Apple은 도면 및 인쇄 가이드에 이를 잘 문서화했습니다.
iOS의 PDF 기능은 모두 CoreGraphics 기반이며, iOS의 그리기 기본 요소도 CoreGraphics 기반이기 때문에 의미가 있습니다.PDF로 직접 2D 프리미티브를 렌더링하려면 CoreGraphics를 사용해야 합니다.
이미지와 같이 UIKit에 있는 개체에 대한 몇 가지 바로 가기도 있습니다. PDF로 .CGContextDrawImage
그러나 UI 이미지에서 얻을 수 있는 CGI 이미지를 사용하여 다음과 같은 작업을 수행할 수 있습니다.
UIImage * myPNG = [UIImage imageNamed:@"mypng.png"];
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385), [myPNG CGImage]);
전반적인 디자인에 대한 더 많은 지침을 원하시면 "앱 전체의 다양한 객체"가 무엇을 의미하는지, 그리고 달성하고자 하는 것이 무엇인지 좀 더 명확하게 말씀해 주십시오.
늦었지만 다른 사람들에게 도움이 될 수도 있습니다.PDF를 코드로 작성하는 것보다 PDF 템플릿 작업 스타일이 원하는 접근 방식인 것 같습니다.어차피 이메일로 보내고 싶으니 인터넷에 연결되어 있기 때문에 효과적으로 메일 병합 서비스인 Docmosis 클라우드 서비스와 같은 것을 사용할 수 있습니다.템플릿과 병합할 데이터/이미지를 보냅니다.이러한 접근 방식은 코드를 훨씬 줄이고 iPad 앱에서 대부분의 처리를 오프로드하는 이점이 있습니다.아이패드 앱에서 사용하는 것을 본 적이 있는데 좋았습니다.
언급URL : https://stackoverflow.com/questions/4362734/ios-sdk-programmatically-generate-a-pdf-file
'programing' 카테고리의 다른 글
웹 브라우저(클라이언트 측)에서 TCP 소켓 연결을 설정하는 방법은 무엇입니까? (0) | 2023.07.30 |
---|---|
도커가 컨텍스트 외부의 심볼릭 링크를 따릅니다. (0) | 2023.07.30 |
Android 앱에서 배경색을 변경하는 방법 (0) | 2023.07.30 |
Oracle SQL - 테이블에 기본 키 추가 (0) | 2023.07.30 |
문자열 클래스에서 처음 N자만 반환하는 메서드는 무엇입니까? (0) | 2023.07.25 |