UIGraphicsBeginPDFContextToData creates PDFs unreadable by Acrobat - ios

Im creating PDF's from iOS using a ordinary code block.
NSMutableData *pdfdata = [NSMutableData dataWithLength:2048];
CGRect newf = CGRectMake(0, 0,1024,1024);
UIGraphicsBeginPDFContextToData(pdfdata,newf,nil);
UIGraphicsBeginPDFPage();
//rendering code
UIGraphicsEndPDFContext();
iOS and OS X read these PDF's just fine but Acrobat claims they are damaged and unreadable. The interesting thing is that doing a duplicate in Preview unmangles them and makes them readable by Acrobat again.
By diff-ing the two versions I can see that the OS X PDF encoder has added a bunch of stuff (its binary so no idea what)
Anyone know the secret sauce to making my PDF's Acrobat compatible again.
EDIT
Broken file - will not open in Acrobat

The document starts with a block of 2048 bytes filled with zero and this damages all offsets in the file.
Create an empty NSMutableData without initial length and the problem should be fixed.

Related

How to copy from Storage to FileSystemStorage in Codenameone and display in BrowserComponent

I've been reading a lot of StackOverflow posts that discuss copying data from FileSystemStorage to Storage in CodenameOne, such as described in this answer from Shai, as seen below:
InputStream stream =
FileSystemStorage.getInstance().openInputStream(i);
OutputStream out =
Storage.getInstance().createOutputStream("MyImage");
Util.copy(stream, out);
Util.cleanup(stream);
Util.cleanup(out);`
I've been trying to do the reverse: save from Storage to FileSystemStorage in order to show a PDF in the BrowserComponent (while using iOS), but have not been able to do so. I need to show the PDF within the app (so I don't want to use Display.getInstance().execute()).
Basically, I'm trying to dynamically populate a Container with whatever files the user selects-- I am using the FileChooser library for CN1 from Steve Hannah. (Disclaimer: I have made slight modifications to this library as it used in the app I'm working on-- HOWEVER, when I choose images with this library and pull them from Storage to an Image via InputStream, they display perfectly in an ImageViewer so I know that all files are being saved correctly in Storage.)
Here is my code (with help from Steve Hannah's comment on GitHub):
//fileLocation and fileName are slightly different but both end with file extension
File file = new File(fileToUpload.getFileName());
FileSystemStorage fss = FileSystemStorage.getInstance();
InputStream is = Storage.getInstance().createInputStream(fileToUpload.getLocation());
OutputStream os = fss.openOutputStream(file.getAbsolutePath());
Util.copy(is, os);
ToastBar.Status status = ToastBar.getInstance().createStatus();
String message = file.exists() + " " + file.isFile() + file.getAbsolutePath();
status.setMessage(message);
status.setExpires(3000);
status.show();
NativeLogs.getNativeLogs();
if (Display.getInstance().getPlatformName().equals("ios")) {
//Log.p("in ios !!!!");
BrowserComponent browserComponent = new BrowserComponent();
browserComponent.setURL(file.getPath());
horizontalContainer.add(browserComponent);
}
The ToastBar displays true and true for file.exists() and file.isFile().
I stipulate iOS because as far as I've seen while researching previewing PDFs within an app, I've seen that Android needs to have a different implementation, like adding a NativeInterface with an Android library. I also saw in different answers on the Google Group that this functionality (using browserComponent to view PDFs) is only available for iOS and not on the simulator. In the simulator, I see a blank space. My iPhone just freezes and/or crashes after displaying the ToastBar (and I work on a Windows machine, so not much ability to see native logs....)
What can I do to access the file and show it in the BrowserComponent?
Thank you!
Simple solution -- the file had a space in it (eg. "Test page.pdf") and didn't show! When I used files that didn't have spaces this worked and after removing spaces in the file names, thankfully everything worked. I'll have to add code to handle this scenario.
Thanks for your help!

Recover a PDF on iOS from a web service

I have a strange problem with my iOS application that calls a .NET web service to recover a PDF.
The web service does some stuff, and returns a PDF document as a reference of the web service (via an out parameter)
The iOS application call the web service, receives an answer and deals with the XML received.
To begin, the web service just returned a "simple" pdf (created in Word). I test my application and all was running well.
I was happy :). Then, I used Microsoft Report Viewer to really generate the PDF...
So I really implement my web service for create the PDF with ReportViewer (http://msdn.microsoft.com/en-us/library/ms251671(v=vs.80).aspx). The pdf generated was correct, I can open it on my server when it was generated. But when I receive the answer in the iOS application, I can't open it because it was corrupt.
Here is the difference of the XML I receive from the web service :
When I return the pdf generated with Word : http://pastie.org/7982815
When I return the pdf generated with ReportViewer : http://pastie.org/7982811
So the main difference is the image parameter that is one-part with the simple PDF and split with the ReportViewer PDF.
Actually I have no idea why the byte array is split as it, and I don't know what I could do to receive a valid PDF.
Once again, the PDF generated with ReportViewer is good, I can open it on the server, and when I send it by e-mail I can open it on my iPad. The problem comes when the web service returns me the PDF as a byte array...
The "split" image is actually an artifact of the web service trying to parse the image for line separators (ie 0d0a == carriage return / new line). If you're lucky, you can reassemble the image by taking each one of the records, including the 0d0a, and just concatenating them. This may be easier than fixing the real problem, which is that your web service is not sending you a single blob, but trying to parse an image into "lines".
It's ok, I solved my problem by concat all the data contains in the image array.
So, considering the XML I receive from the web service (http://pastie.org/7982811), here is my objective-c code to build the correct NSData (the pdf) :
NSMutableData *concatData = [NSMutableData data];
NSArray *partsData = [result objectForKey:#"image"];
for(NSDictionary *dicPdfDataLine in partsData) { // Foreach parts of data
NSArray *arrayPdfDataLine = [dicPdfDataLine allValues];
NSData *dataLine = [arrayPdfDataLine objectAtIndex:0]; // Get the NSData of the current part part
[concatData appendData:dataLine]; // Concat the data
}

Issue on attaching csv & pdf file- Objective c [duplicate]

I'm working with PDF generation,it generated the PDF, viewed using QLPreviewController, all worked fine except mail forwarding, I have two attachments of type .pdf and .csv. I have the following issues while emailing.
sometimes no attachments while emailing
pdf size will be very huge when pdf contains image(10 mb for one page pdf, if it contains image)
Problem is when testing in device,in simulator it all works fine...,
I come to know some exporting or importing UTI associated issues here
since I am a starter I feel difficult to understand it, I think some UTI's I have to add somewhere.. Can anyone please help me to identify the issue and solve, please. Thanks in advance.
1. Attachment issue
set mime type as text/csv instead of application/csv or image/csv. code is as shown below
[mailComposer addAttachmentData:[NSData dataWithContentsOfFile:self.csvFilePath]
mimeType:#"text/csv" fileName:[NSString stringWithFormat:#"csvPage.csv" ]];
1. Size issue
I struggled a lot.. at last when wrote image in jpeg format to pdf page using below code, size got reduced ten times!!
UIImage *lowResImage = [UIImage imageWithData:UIImageJPEGRepresentation(plotImage, 0.02)];

How to use AirPrint to print a locked pdf file

I know use CGPDFDocumentUnlockWithPassword to unlock a pdf, but it returned a CGPDFDocumentRef, and if I want use AirPrint to print it, it should be a NSData or a url, But I don't know how to convert a CGPDFDocumentRef to a NSData object or a save it as a file . Did anyone have a idea to solve this case?
Simply printing each page of your source pdf into a newly created CGPDFContext and saving the resulting pdf to separate file should do it. Principially, it should look like this:
// create PDFContext
NSURL* dstPath = [NSURL fileURLWithPath:pathInCachesFolder]
CGRect pageRect = CGRectMake(0,0,1024,1024); // example, use real page size of src document here
CGContextRef pdfContext = CGPDFContextCreateWithURL(dstPath, &pageRect, nil);
// use for loop here to repeat following stuff for each pdf page from the src pdf
CGPDFContextBeginPage(pdfContext, NULL);
CGContextDrawPDFPage(pdfContext, sourcePDFpageRef);
CGPDFContextEndPage(pdfContext);
// close pdfContext, saves dst file
CGPDFContextClose(pdfContext);
CGContextRelease (pdfContext);
This piece of code just prints a page from the source pdf to the newly created pdf and saves the pdf to the dst path. Of course, you'll have repeat the drawing part for each page from the source document. Afterwards you should be able to print the pdf via AirPrint without any problems.
I already solved this question. you can have information here:
How to pass a password to UIPrintInteractionController when using AirPrint to print a locked pdf?

Cannot create PDF document with 400+ pages on iOS

I am using the following pseudocode to generate a PDF document:
CGContextRef context = CGPDFContextCreateWithURL(url, &rect, NULL);
for (int i = 1; i <= N; i++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGContextBeginPage(context, &mediaBox);
// drawing code
CGContextEndPage(context);
[pool release];
}
CGContextRelease(context);
It works very well with small documents (N < 100 pages), but it uses too much
memory and crashes if the document has more than about 400 pages (it received
two memory warnings before crashing.) I have made sure there were no leaks using
Instruments. What's your advice on creating large PDF documents on iOS? Thanks a lot.
edit: The pdf creation is done in a background thread.
Since you're creating a single document via CGPDFContextCreateWithURL the entire thing has to be held in memory and appended to, something that commonly (though I can't say for certain with iOS and CGPDFContextCreateWithURL) requires a full before and after copy of the document to be kept. No need for a leak to create a problem, even without the before-and-after issue.
If you aren't trying to capture a bunch of existing UIKit-drawn stuff -- and in your sample it seems that you're not -- use the OS's printing methods instead, which offer built-in support for printing to a PDF. UIGraphicsBeginPDFContextToFile writes the pages out to disk as they're added so the whole thing doesn't have to be held in memory at once. You should be able to generate a huge PDF that way.
Probably not the answer you want to hear, but looking at it from another perspective.
Could you consider it as a limitation of the device?... First check the number of pages in the PDF and if it is too large, give a warning to the user. Therefore handling it gracefully.
You could then expand on this....
You could construct small PDF's on the iDevice and if the PDF is too large, construct it server-side the next time the iDevice has a net connection.
If you allocate too much memory, your app will crash. Why is generating an unusually large PDF a goal? What are you actually trying to accomplish?
What about using a memory mapped file to back your CG data consumer? Then it doesn't necessarily have to fit in RAM all at once.
I created an example here: https://gist.github.com/3748250
Use it like this:
NSURL * url = [ NSURL fileURLWithPath:#"pdf.pdf"] ;
MemoryMappedDataConsumer * consumer = [ [ MemoryMappedDataConsumer alloc ] initWithURL:url ] ;
CGDataConsumerRef cgDataConsumer = [ consumer CGDataConsumer ] ;
CGContextRef c = CGPDFContextCreate( cgDataConsumer, NULL, NULL ) ;
CGDataConsumerRelease( cgDataConsumer ) ;
// write your PDF to context `c`
CGPDFContextClose( c ) ;
CGContextRelease( c ) ;
return 0;

Resources