iOS SDK - प्रोग्राम पीडीएफ फाइल जनरेट करता है


79

CoreGraphics ढांचे का उपयोग थकाऊ काम है, मेरी ईमानदार राय में, जब यह प्रोग्रामेटिक रूप से एक पीडीएफ फाइल ड्राइंग करने की बात आती है।

मैं अपने ऐप में विचारों से विभिन्न वस्तुओं का उपयोग करके, प्रोग्राम को पीडीएफ बनाना चाहूंगा ।

मुझे यह जानने में दिलचस्पी है कि क्या आईओएस एसडीके के लिए कोई अच्छा पीडीएफ ट्यूटोरियल है, शायद लाइब्रेरी में गिरावट है।

मैंने इस ट्यूटोरियल, पीडीएफ क्रिएशन ट्यूटोरियल को देखा है , लेकिन यह ज्यादातर सी में लिखा गया था। यह भी एक पीडीएफ फाइल को लिखने के लिए एक हास्यास्पद तरीके की तरह लगता है, जहां लाइनों और अन्य वस्तुओं को रखा जाएगा गणना करने के लिए।

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 परियोजना में libHaru का उपयोग कर GitHub पर एक उदाहरण है ।


1
हाहा, मुझे पता है कि यह पुराना है, लेकिन एक iPhone पर 100 पेज पीडीएफ कुछ भी नहीं है। यह आईओएस डिवाइस की तुलना में सर्वर पर अधिक जोर देगा, क्योंकि सर्वर को कई गुना समवर्ती उपयोगकर्ताओं को इसे करने की कोशिश करनी होगी।
आर्मंड

जवाबों:


56

एक दो बातें ...

सबसे पहले, iOS में कोरग्राफिक्स पीडीएफ पीढ़ी के साथ एक बग है जो दूषित पीडीएफ में परिणाम करता है। मुझे पता है कि यह समस्या आईओएस 4.1 और (आईओएस 4.2 का परीक्षण नहीं किया है) तक मौजूद है। समस्या फोंट से संबंधित है और केवल तभी पता चलता है जब आप अपने पीडीएफ में पाठ शामिल करते हैं। लक्षण यह है कि पीडीएफ बनाते समय, आपको डिबग कंसोल में त्रुटियां दिखाई देंगी जो इस तरह दिखती हैं:

<Error>: can't get CIDs for glyphs for 'TimesNewRomanPSMT'

मुश्किल पहलू यह है कि परिणामस्वरूप पीडीएफ कुछ पीडीएफ पाठकों में ठीक प्रस्तुत करेगा, लेकिन अन्य स्थानों में प्रस्तुत करने में विफल। इसलिए, यदि आपके पास अपने पीडीएफ को खोलने के लिए उपयोग किए जाने वाले सॉफ़्टवेयर पर नियंत्रण है, तो आप इस समस्या को अनदेखा करने में सक्षम हो सकते हैं (उदाहरण के लिए, यदि आप केवल iPhone या Mac डेस्कटॉप पर PDF प्रदर्शित करने का इरादा रखते हैं, तो आपको इसका उपयोग करके ठीक होना चाहिए कोरग्राफिक्स)। हालांकि, अगर आपको एक पीडीएफ बनाने की ज़रूरत है जो कहीं भी काम करती है, तो आपको इस मुद्दे पर बारीकी से विचार करना चाहिए। यहाँ कुछ अतिरिक्त जानकारी है:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/15505-pdf-font-problem-cant-get-cids-glyphs.html#post97854

वर्कअराउंड के रूप में, मैंने iPhone पर CoreGraphics PDF पीढ़ी के प्रतिस्थापन के रूप में libHaru का सफलतापूर्वक उपयोग किया है। यह शुरू में मेरी परियोजना के साथ निर्माण करने के लिए काम कर रहा था थोड़ा मुश्किल था, लेकिन एक बार मुझे अपना प्रोजेक्ट सेटअप ठीक से मिल गया, तो इसने मेरी जरूरतों के लिए ठीक काम किया।

दूसरा, आपके पीडीएफ के प्रारूप / लेआउट के आधार पर, आप अपने पीडीएफ आउटपुट के लिए "टेम्पलेट" के रूप में कार्य करने वाले दृश्य बनाने के लिए इंटरफ़ेस बिल्डर का उपयोग करने पर विचार कर सकते हैं। फिर आप दृश्य को लोड करने के लिए, किसी भी डेटा को भरने के लिए (उदाहरण के लिए, UILabels, आदि के लिए पाठ सेट करें) कोड लिखेंगे, फिर पीडीएफ में दृश्य के व्यक्तिगत तत्वों को प्रस्तुत करेंगे। दूसरे शब्दों में, उपयोग आईबी निर्देशांक, फ़ॉन्ट, छवियों, आदि और लिखने कोड विभिन्न तत्वों रेंडर करने के लिए (जैसे, निर्दिष्ट करने के लिए UILabel, UIImageViewआदि) एक सामान्य तरीके ताकि आप कड़ी मेहनत से कोड सब कुछ करने के लिए नहीं है। मैंने इस दृष्टिकोण का इस्तेमाल किया और इसने मेरी जरूरतों के लिए बहुत अच्छा काम किया। फिर, यह आपकी पीडीएफ के प्रारूपण / लेआउट आवश्यकताओं के आधार पर आपकी स्थिति के लिए या नहीं हो सकता है।

संपादित करें: (पहली टिप्पणी पर प्रतिक्रिया)

मेरा कार्यान्वयन एक वाणिज्यिक उत्पाद का हिस्सा है जिसका अर्थ है कि मैं पूर्ण कोड साझा नहीं कर सकता, लेकिन मैं एक सामान्य रूपरेखा दे सकता हूं:

मैंने एक .xib फ़ाइल को एक दृश्य के साथ बनाया और दृश्य को 850 x 1100 पर आकार दिया (मेरा पीडीएफ 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";

तब मैं पीडीएफ फाइल को देखने के लिए एक फ़ंक्शन को कॉल करता हूं। यह फ़ंक्शन पुनरावर्ती रूप से दृश्य पदानुक्रम चलता है और प्रत्येक सबव्यू को प्रस्तुत करता है। मेरी परियोजना के लिए, मुझे केवल लेबल, ImageView और दृश्य (नेस्टेड विचारों के लिए) का समर्थन करने की आवश्यकता है:

- (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);
        }
    }
}

उम्मीद है कि यह आपको विचार देता है।


क्या आपके पास टेम्पलेट के रूप में XIB का उपयोग करने का कोई उदाहरण है?
राइट्ससीएस

12

यह एक देर से जवाब है, लेकिन जैसा कि मैंने पीडीएफ पीढ़ी के साथ बहुत संघर्ष किया, मैंने अपने विचार साझा करना उचित समझा। कोर ग्राफिक्स के बजाय, एक संदर्भ बनाने के लिए, आप एक पीडीएफ उत्पन्न करने के लिए UIKit विधियों का उपयोग कर सकते हैं।

Apple ने इसे ड्राइंग और प्रिंटिंग गाइड में अच्छी तरह से प्रलेखित किया है


4
FWIW- ट्यूटोरियल के लिए साइट गोडैडी में मृत-समाप्त हो गई है।
जिज्ञासु खरगोश

8

IOS पर PDF फ़ंक्शंस सभी CoreGraphics आधारित हैं, जो समझ में आता है, क्योंकि iOS में ड्रा प्राइमरी भी CoreGraphics आधारित हैं। यदि आप सीधे एक पीडीएफ में 2D प्राइमेटिव्स प्रदान करना चाहते हैं, तो आपको CoreGraphics का उपयोग करना होगा।

वस्तुओं के लिए कुछ शॉर्टकट हैं जो छवियों की तरह, UIKit में भी रहते हैं। पीएनजी को एक पीडीएफ संदर्भ में आकर्षित करने के लिए अभी भी कॉल की आवश्यकता होती है CGContextDrawImage, लेकिन आप इसे CGImage के साथ कर सकते हैं जिसे आप UIImage से प्राप्त कर सकते हैं, जैसे:

UIImage * myPNG = [UIImage imageNamed:@"mypng.png"];
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385), [myPNG CGImage]);

यदि आप समग्र डिजाइन पर अधिक मार्गदर्शन चाहते हैं, तो कृपया "अपने ऐप में विभिन्न ऑब्जेक्ट्स" से क्या मतलब है और क्या आप पूरा करने की कोशिश कर रहे हैं।


उत्तर के लिए धन्यवाद। ऑब्जेक्ट द्वारा, मेरा सीधा मतलब है कि मैं उपयोगकर्ता-इनपुट पाठ ले रहा हूं और उन्हें पीडीएफ में विभिन्न स्थानों पर रखना चाहता हूं। और जैसा कि आपने बताया है, कुछ ग्राफिक्स। एक प्रपत्र की तरह SOmething जो ईमेल किया जा सकता है।
राइट्ससीएस

हाय यार, मेरा एक सवाल है: इस तरह से (CGContextDrawImage), पीडीएफ़ वेक्टर नहीं है। अगर मैं एक पीडीएफ के एक ही पृष्ठ में कई वेक्टर ग्राफिक्स प्रस्तुत करना चाहता हूं तो मुझे क्या करना चाहिए, इस बीच, सुनिश्चित करें कि पीडीएफ भी वेक्टर है
पैराडाइज

2

देर से, लेकिन संभवतः दूसरों के लिए उपयोगी है। ऐसा लगता है कि एक पीडीएफ टेम्पलेट शैली ऑपरेशन की तरह कोड में पीडीएफ के निर्माण के बजाय आप चाहते हैं कि दृष्टिकोण हो सकता है। चूँकि आप इसे किसी भी तरह से ईमेल करना चाहते हैं, आप नेट से जुड़े हुए हैं इसलिए आप डोकमोसिस जैसी किसी चीज़ का उपयोग कर सकते हैं क्लाउड सेवा जो प्रभावी रूप से मेल-मर्ज सेवा है। इसे अपने टेम्पलेट में मर्ज करने के लिए डेटा / चित्र भेजें। इस प्रकार के दृष्टिकोण से बहुत कम कोड का लाभ होता है और आपके आईपैड ऐप से अधिकांश प्रोसेसिंग को ऑफलोड किया जाता है। मैंने देखा है कि यह एक iPad ऐप में इस्तेमाल किया गया था और यह अच्छा था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.