将 UIImage/CGImage 渲染到 CGPDFContext 会导致...空白!

发布于 2024-08-28 07:15:43 字数 1334 浏览 8 评论 0原文

我正在尝试将图像对象中的图像渲染到 Core Graphics PDF 上下文中——恰好在 iPhone 上,但这个问题肯定同样适用于桌面 Quartz。此 UIImage 是一个简单的白底彩色图像,分辨率约为 600x800。如果我(比如说)将其转换为 PNG 文件,该文件看起来与预期完全一致——所以数据没问题。

以下是我生成 PDF 的方法:

NSMutableData * outputData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData);

CFMutableDictionaryRef attrDictionary = NULL;    
attrDictionary = CFDictionaryCreateMutable(NULL, 0,
                                         &kCFTypeDictionaryKeyCallBacks,
                                         &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, @"My Awesome Document");
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary); 
CFRelease(dataConsumer);
CFRelease(attrDictionary);
CGImageRef pageImage = [myUIImage CGImage];
CGPDFContextBeginPage(pdfContext, NULL);
CGContextDrawImage(pdfContext, CGRectMake(0, 0, [myUIImage size].width, [myUIImage size].height), pageImage);
CGPDFContextEndPage(pdfContext);
CGPDFContextClose(pdfContext);
CGContextRelease(pdfContext);

生成的 PDF(最终出现在 outputData 中)看起来像是一个有效的 PDF 文件(可以正确打开,文档标题存在于元数据中),但它包含以下内容:正好一页空白。

我做错了什么?

谢谢。

更新:哈!这是我的错。我用于生成 PNG 文件的测试代码通过不同的路径来获取数据。 PDF 路径确实收到了一个空图像。

I'm trying to take an image that I have in a image object and render into a Core Graphics PDF context-- happens to be on an iPhone but this question surely applies equally to desktop Quartz. This UIImage is a simple color-on-white image at about 600x800 resolution. If I (say) turn it into a PNG file, that file looks exactly as expected-- so the data is OK.

Here's what I'm doing to generate the PDF:

NSMutableData * outputData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData);

CFMutableDictionaryRef attrDictionary = NULL;    
attrDictionary = CFDictionaryCreateMutable(NULL, 0,
                                         &kCFTypeDictionaryKeyCallBacks,
                                         &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, @"My Awesome Document");
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary); 
CFRelease(dataConsumer);
CFRelease(attrDictionary);
CGImageRef pageImage = [myUIImage CGImage];
CGPDFContextBeginPage(pdfContext, NULL);
CGContextDrawImage(pdfContext, CGRectMake(0, 0, [myUIImage size].width, [myUIImage size].height), pageImage);
CGPDFContextEndPage(pdfContext);
CGPDFContextClose(pdfContext);
CGContextRelease(pdfContext);

The resulting PDF, which ends up in outputData, seems like a valid PDF file (opens correctly, document title is present in metadata), but it consists of precisely one blank page.

What am I doing wrong?

Thanks.

UPDATE: Ha! This was my fault. My test code for just generating the PNG file went through a different path to get the data. The PDF path indeed was receiving an empty image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无人问我粥可暖 2024-09-04 07:15:43

我测试了你的代码,它似乎可以工作。
您确定您的 UIImage 在将其绘制到上下文中时是有效的而不是 nil 吗?
我的测试方法从主包加载 .png 并将最终的 pdf 写入应用程序文档文件夹中的文件:

- (IBAction)outputPDF:(id)sender
{
    NSMutableData* outputData = [[NSMutableData alloc] init];
    CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData);
    CFMutableDictionaryRef attrDictionary = NULL;    
    attrDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, @"My Awesome Document");
    CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary); 
    CFRelease(dataConsumer);
    CFRelease(attrDictionary);
    UIImage* myUIImage = [UIImage imageNamed:@"tmp.png"];
    CGImageRef pageImage = [myUIImage CGImage];
    CGPDFContextBeginPage(pdfContext, NULL);
    CGContextDrawImage(pdfContext, CGRectMake(0, 0, [myUIImage size].width, [myUIImage size].height), pageImage);
    CGPDFContextEndPage(pdfContext);
    CGPDFContextClose(pdfContext);
    CGContextRelease(pdfContext);   
    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsDirectory = [paths objectAtIndex:0];
    NSString* appFile = [documentsDirectory stringByAppendingPathComponent:@"tmp.pdf"];
    [outputData writeToFile:appFile atomically:YES];
}

I tested your code and it seems to work.
Are you sure your UIImage is valid and not nil when drawing it into the context?
My test method loads a .png from the main bundle and writes the final pdf to a file in the applications document folder:

- (IBAction)outputPDF:(id)sender
{
    NSMutableData* outputData = [[NSMutableData alloc] init];
    CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData);
    CFMutableDictionaryRef attrDictionary = NULL;    
    attrDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, @"My Awesome Document");
    CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary); 
    CFRelease(dataConsumer);
    CFRelease(attrDictionary);
    UIImage* myUIImage = [UIImage imageNamed:@"tmp.png"];
    CGImageRef pageImage = [myUIImage CGImage];
    CGPDFContextBeginPage(pdfContext, NULL);
    CGContextDrawImage(pdfContext, CGRectMake(0, 0, [myUIImage size].width, [myUIImage size].height), pageImage);
    CGPDFContextEndPage(pdfContext);
    CGPDFContextClose(pdfContext);
    CGContextRelease(pdfContext);   
    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsDirectory = [paths objectAtIndex:0];
    NSString* appFile = [documentsDirectory stringByAppendingPathComponent:@"tmp.pdf"];
    [outputData writeToFile:appFile atomically:YES];
}
很快妥协 2024-09-04 07:15:43

这个问题似乎已经在 iphone dev sdk 论坛上得到解决:
PDF 创建教程

所有功劳to danielb21:这里是他们的 CreatePDFFile 方法的重印:

// Our method to create a PDF file natively on the iPhone
// This method takes two parameters, a CGRect for size and
// a const char, which will be the name of our pdf file
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);
}

This issue seems to have been addressed on the iphone dev sdk forums:
PDF creation tutorial

All credit goes to danielb21: here is a reprint of their CreatePDFFile method:

// Our method to create a PDF file natively on the iPhone
// This method takes two parameters, a CGRect for size and
// a const char, which will be the name of our pdf file
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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文