sincronizar recuperar pasar para los libros guardar guardan fotos entre donde descargar convertir como archivos archivo app iphone objective-c ipad ios pdf-generation

recuperar - guardar archivos pdf en iphone



iOS SDK-Genera programáticamente un archivo PDF (4)

Es una respuesta tardía, pero como luché mucho con la generación de PDF, consideré que valía la pena compartir mis puntos de vista. En lugar de gráficos Core, para crear un contexto, también puede usar los métodos UIKit para generar un pdf.

Apple lo ha documentado bien en la guía de dibujo e impresión.

Usar el marco CoreGraphics es un trabajo tedioso, en mi opinión honesta, cuando se trata de dibujar un archivo PDF mediante programación.

Me gustaría crear un PDF mediante programación, utilizando varios objetos desde vistas en toda mi aplicación.

Me interesa saber si hay algún buen tutorial en PDF para el SDK de iOS, quizás una caída en la biblioteca.

He visto este tutorial, Tutorial de creación de PDF , pero fue escrito principalmente en C. Buscando más estilo Objective-C. Esto también parece una forma ridícula de escribir en un archivo PDF, teniendo que calcular dónde se colocarán las líneas y otros objetos.

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

EDITAR: Aquí hay un ejemplo en GitHub usando libHaru en un proyecto de iPhone.


Las funciones de PDF en iOS están basadas en CoreGraphics, lo que tiene sentido, porque las primitivas de dibujo en iOS también están basadas en CoreGraphics. Si quiere renderizar primitivas 2D directamente en un PDF, deberá usar CoreGraphics.

También hay algunos atajos para objetos que viven en UIKit, como imágenes. Dibujar un PNG en un contexto PDF aún requiere la llamada a CGContextDrawImage , pero puede hacerlo con el CGImage que puede obtener de un UIImage, por ejemplo:

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

Si desea obtener más orientación sobre el diseño general, sea más explícito sobre lo que quiere decir con "varios objetos en su aplicación" y lo que intenta lograr.


Tarde, pero posiblemente útil para otros. Parece que el estilo de operación de una plantilla de PDF podría ser el enfoque que desea en lugar de construir el PDF en el código. Como quiera enviarlo por correo electrónico de todos modos, está conectado a la red, por lo que podría usar algo como el servicio en la nube Docmosis , que es efectivamente un servicio de combinación de correspondencia. Envíele los datos / imágenes para combinarlos con su plantilla. Ese tipo de enfoque tiene el beneficio de un código mucho menor y la descarga de la mayoría de los procesos de su aplicación para iPad. Lo he visto usado en una aplicación para iPad y fue agradable.


Un par de cosas ...

En primer lugar, hay un error con la generación de PDF CoreGraphics en iOS que da como resultado archivos PDF corruptos. Sé que este problema existe e incluye iOS 4.1 (no he probado iOS 4.2). El problema está relacionado con las fuentes y solo aparece si incluye texto en su PDF. El síntoma es que, al generar el PDF, verá errores en la consola de depuración que se ven así:

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

El aspecto complicado es que el PDF resultante se verá bien en algunos lectores de PDF, pero no se procesará en otros lugares. Por lo tanto, si tiene control sobre el software que se utilizará para abrir su PDF, puede ignorar este problema (por ejemplo, si solo desea mostrar el PDF en los escritorios de iPhone o Mac, entonces debería estar bien usando CoreGraphics). Sin embargo, si necesita crear un PDF que funcione en cualquier lugar, debe analizar este problema con más detalle. Aquí hay información adicional:

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

Como solución alternativa, utilicé libHaru con éxito en iPhone como reemplazo de la generación de PDF de CoreGraphics. Fue un poco complicado conseguir que libHaru construyera con mi proyecto inicialmente, pero una vez que obtuve la configuración de mi proyecto correctamente, funcionó bien para mis necesidades.

En segundo lugar, dependiendo del formato / diseño de su PDF, puede considerar utilizar Interface Builder para crear una vista que sirva como una "plantilla" para su salida de PDF. Luego, debe escribir el código para cargar la vista, completar cualquier dato (por ejemplo, establecer texto para UILabels, etc.) y luego representar los elementos individuales de la vista en el PDF. En otras palabras, use IB para especificar coordenadas, fuentes, imágenes, etc. y escriba código para representar varios elementos (por ejemplo, UILabel , UIImageView , etc.) de forma genérica para que no tenga que codificarlo todo. Usé este enfoque y funcionó muy bien para mis necesidades. Nuevamente, esto puede o no tener sentido para su situación dependiendo de las necesidades de formato / diseño de su PDF.

EDIT: (respuesta al primer comentario)

Mi implementación es parte de un producto comercial, lo que significa que no puedo compartir el código completo, pero puedo ofrecer un resumen general:

Creé un archivo .xib con una vista y dimensioné la vista a 850 x 1100 (mi PDF apuntaba a 8.5 x 11 pulgadas, por lo que facilita la traducción a / desde las coordenadas de tiempo de diseño).

En código, cargo la vista:

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

Luego llené varios elementos. Usé etiquetas para encontrar los elementos apropiados, pero podrías hacerlo de otras maneras. Ejemplo:

UILabel *label = (UILabel *)[templateView viewWithTag:TAG_FIRST_NAME]; if (label != nil) { label.text = (firstName != nil) ? firstName : @"None";

Luego invoco una función para mostrar la vista al archivo PDF. Esta función recorre de forma recursiva la jerarquía de vistas y representa cada subvista. Para mi proyecto, necesito admitir solamente Label, ImageView y View (para vistas anidadas):

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

Como ejemplo, aquí está mi implementación de addImageView (las funciones HPDF_ son de 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); } } }

Espero que eso te dé la idea.