iPhone PDF creation library or functions - iphone

Does anybody know of an open source PDF creation project for the iPhone to generate documents from a template (using Quartz)? Or are there any functions people have written for alignment etc? I've seen libHaru but I understand it is lacking some crucial functionality.
Thanks

You can create a Quartz context with a PDF file as a rendering destination and simply draw into that. For example, the following code will create a PDF file within an NSData object, which you could then attach to an email or save to disk:
NSMutableData *pdfData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfData);
const CGRect mediaBox = CGRectMake(0.0f, 0.0f, drawingWidth, drawingHeight);
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &mediaBox, NULL);
UIGraphicsPushContext(pdfContext);
CGContextBeginPage(pdfContext, &mediaBox);
// Draw your content here
CGContextEndPage(pdfContext);
CGPDFContextClose(pdfContext);
UIGraphicsPopContext();
CGContextRelease(pdfContext);
CGDataConsumerRelease(dataConsumer);
There are a few things going on here. First, we create an NSMutableData instance and set it to be a data consumer (a destination for the PDF context to write to). Because Core Graphics uses Core Foundation types, and not Cocoa classes, CGDataConsumerCreateWithCFData() requires a CFMutableDataRef argument. We are able to simply cast the NSMutableData class we created as this type, because NSData is a toll-free bridged class. What that means is that it can be used in either Cocoa methods or Core Foundation functions without conversion between types.
After that, we set the page size of the PDF context (in points) and create a PDF context, using the data consumer we set up before. We then make this the active context for drawing by using UIGraphicsPushContext().
In this case, we are only creating a single page in the PDF we're drawing, so we begin the page, draw, then end the page. If you wanted to do multiple pages, you could repeat this for each page.
Note that all of this drawing will be done in the Quartz coordinate space, so if you've set up your drawing routines to display correctly in an iPhone view, it will be flipped here. To counteract this flipping, you can place the following within your drawing code (after UIGraphicsPushContext()):
CGContextTranslateCTM(context, 0.0f, self.frame.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);

There 2 ways to generate a pdf in iPhone SDK. The first one is using Core Graphics methods:
CGContextRef CGPDFContextCreateWithURL(CFURLRef url, const CGRect *mediaBox, CFDictionaryRef auxiliaryInfo)
void CGContextBeginPage(CGContextRef c, const CGRect *mediaBox)
void CGContextEndPage(CGContextRef c)
The second way is to use the UIKit methods of creating a pdf context. You can find it here.
There is a good tutorial on generating a pdf programmatically with the iPhone SDK, and you can find it here.

Related

iOS support for Canon RAW format?

I know the iPad can read Canon RAW (.CR2) files when used with the Camera Kit but is any of that file format reading accessible to an iOS developer? Or are we just limited to things supported in the UIImage Class Reference document?
(https://developer.apple.com/documentation/uikit/uiimage)
For something like this, Apple's image APIs are not going to be sufficient for what you need. However, there are a few third party APIs that should work with the iPhone. Libraw is a good one that I found that has a C interface. Since Objective-C is a strict superset of C, you will probably be able to use it in your iOS application.
From what I see in their docs, you might be able to write a CR2 image as a TIFF, then decode it as a UIImage like this:
NSString * cr2Path = #"path/to/cr2/file";
NSString * tiffPath = [NSTemporaryDirectory stringByAppendingPathComponent:#"x.tiff"];
libraw_data_t * cr2Data = libraw_init(0);
libraw_open_file(cr2Data, [cr2Path UTF8String]);
libraw_unpack(cr2Data);
// setup encoding params
cr2Data->params.output_tiff = 1;
cr2Data->params.use_camera_wb = 1;
// encode and write as tiff
libraw_dcraw_process(cr2Data);
libraw_dcraw_ppm_tiff_writer(cr2Data, [tiffPath UTF8String]);
libraw_recycle(cr2Data); // free the memory
// load the UIImage
UIImage * myImage = [[UIImage alloc] initWithContentsOfFile:tiffPath];
// use myImage here ...
[myImage release];
From what I have seen, it looks like you will be able to download it here and then add the src files from the src/, libraw/, dcraw/, and internal/ directories to your Xcode project. Hopefully you will not run into any weird linking/compiling issues.

Deallocate memory used by CGContextDrawPDFPage

When I analyze my app with Instruments, I found out that data allocated by CGContextDrawPDFPage is not released immediately. Since my program receives a lot of 'memory warnings' I would like to release as much memory as possible but I don't know how to release this memory.
As you can see on http://twitpic.com/473e89/full it seems to be related to this code
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx{
NSAutoreleasePool * tiledViewPool = [[NSAutoreleasePool alloc] init];
CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform([self.superview.superview getPage],kCGPDFMediaBox,tiledLayer.bounds, 0, true);
CGContextSaveGState (ctx);
CGContextTranslateCTM(ctx, 0.0, tiledLayer.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM (ctx, pdfTransform);
CGContextClipToRect (ctx, CGPDFPageGetBoxRect([self.superview.superview getPage],kCGPDFMediaBox));
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
CGContextDrawPDFPage(ctx,[self.superview.superview getPage]);
CGContextRestoreGState (ctx);
UIGraphicsEndPDFContext();
[tiledViewPool drain];
}
I have already tried to wrap an AutoReleasePool around it but this does not seem to have any influence. The screenshot is taken after TiledView (the view where the method belongs to) is deallocated.
I hope someone can help me to reduce memory usage.
Everyone I know who had to deal with PDFs on iOS at some point has had this same problem.
The only solution seems to be to release the document and re-create it.
Note that the other common problem is that while you're releasing your document, a CATiledLayer may be rendering a page from that document at the same time. So, you should make good use of #synchronize (probably using your pdfDocRef) and release the document only when the tiled layer has finished its work.
Also, check this out: Fast and Lean PDF Viewer for iPhone / iPad / iOs - tips and hints?
I had a similar problem,
this line which gets a pdf page
[self.superview.superview getPage]
make sure you re-open the pdf every time you pull out a page, turns out CGPDFDocument does handle memory very well.
eg. something like
//release the current pdf doc
if(self.pdfDocumentRef!=nil){
CGPDFDocumentRelease(self.pdfDocumentRef);
}
//open it again
self.pdfDocumentRef=CGPDFDocumentCreateWithURL(..your url..);
//pull out a page
CGPDFPageRef pg = CGPDFDocumentGetPage(self.pdfDocumentRef, pageIndex+1);

Quartz PDF API Causing Out of Memory Crashes

I'm having crashing issues using the Quartz PDF API for iOS. At the moment I am compiling with the SDK 4.0 GM Seed and running on my 3.2 iPad (I have tried using the 3.2 SDK with identical results).
All the code I am using is based on the standard Apple Quartz documentation and from various sources around the internets. So I can't image I'm doing something drastically different or wrong.
The code runs perfectly in the Simulator (all versions, it's a Universal app) and even while using the "Simulate Memory Warning" function. I've used the Leaks tool and there are no leaks that it finds. Build and Analyze also finds nothing. No crash or low memory log is left in my Library.
All this leads me to believe the device is running out of memory. This happens after running through say 50 pdf pages, with about 35% having an image of some sort (some full page some icon). It does not crash on any particular page. The pdf I am loading is about 75 pages and 3.5MB.
I've perused similar issues on this site and around the internets, and have applied some of the advice in the code below. I now release the pdf document reference on every page turn and I no longer retain/release a page reference. I've also simplified the image swapping from using CGImages to just using the UIGraphicsGetImageFromCurrentImageContext function. I've tried various implementations for switching the images, including replacing the pdfImgView completely with a newly allocated temp instance (using [[UIImageView alloc] iniWithImage:UIGraphicsGetImageFromCurrentImageContext()]), using the setter for pdfImgView and releasing the temp. All of the variations pass the Leaks and Analyzer tests, but still exhibit the same crashing behavior.
So, before I move away from PDFs altogether, is there something I should try or something I am missing?
View controller code that is called in interface handlers to swap pages and on first load:
[self drawPage];
// ...animation code...simple CATransition animation...crashes with or without
// scrollView is a UIScrollView that is a subview of self.view
[scrollView.layer addAnimation:transition forKey:nil];
// pdfImgView is a UIImageView that is a subview of scrollView
pdfImgView.image = UIGraphicsGetImageFromCurrentImageContext();
drawPage method used to configure and draw PDF page to the context:
[CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("BME_interior.pdf"), NULL, NULL);
pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL); // instance variable, not a property
CFRelease(pdfURL);
CGPDFPageRef page = CGPDFDocumentGetPage(pdfRef, currentPage);
CGRect box = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
// ...setting scale and imageHeight, both floats...
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.frame.size.width, imageHeight), NO, 0.0);
} else {
UIGraphicsBeginImageContext(CGSizeMake(self.view.frame.size.width, imageHeight));
}
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(#"page is %d, context is %d, pdf doc is %d, pdf page is %d", currentPage, context, pdfRef, page); // all prints properly
// ...setting up scrollView for new page, using same instance...
CGContextTranslateCTM(context, (self.view.frame.size.width-(box.size.width*scale))/2.0f, imageHeight);
CGContextScaleCTM(context, scale, -1.0*scale);
CGContextSaveGState(context);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
CGPDFDocumentRelease(pdfRef);
pdfRef = NULL;
Aha! I've fixed the crashes by adding a UIGraphicsEndImageContext(); before beginning a new image context. I don't even get memory warnings now...
Calling
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
before CGContextDrawPDFPage solved a similar problem of mine.
Credits goes to this answer of Johann:
CGContextDrawPDFPage taking up large amounts of memory

Using NSString's drawAtPoint method in place of CGContextShowGlyphsAtPoint problems

In my app I'm trying to render text along a path; this is fine for most characters but not for Japanese (or anything non mac-Roman). I've been advised to use [NSString drawAtPoint] which displays the correct characters in my CATiledLayer; however, they dissapear after approximately 5 seconds. In this time I can zoom the layer and they scale properly, but they don't seem to get committed to the CATiledLayer like the rest of the text usually is.
Before I render, I check the string and decide whether any of them will not be renderable. If I'm going to have issues, I use drawAtpoint instead:
if (!isFullyDisplayable)
{
CGContextShowGlyphsAtPoint(context, pt.x, pt.y, realGlyph, 1);
}
else {
// fall back on less flexible font rendering for difficult characters
NSString *b = [gv text];
NSString *c = [b substringWithRange:NSMakeRange(j,1)];
[c drawAtPoint:pt withFont:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]];
}
Does anyone have any pointers as to why the text disappears?
As soon as the drawAtPoint is used my debug output gets flooded with:
<Error>: CGContextGetShouldSmoothFonts: invalid context
<Error>: CGContextSetFont: invalid context
<Error>: CGContextSetTextMatrix: invalid context
<Error>: CGContextSetFontSize: invalid context
<Error>: CGContextSetTextPosition: invalid context
<Error>: CGContextShowGlyphsWithAdvances: invalid context
So I'm guessing it is something to do with my context management, but I assumed that if this is in the same place as I use CGContextShowGlyphsAtPoint it should have the correct context already?
Answering my own question:
NSString drawAtPoint:withFont: makes use of the context stack, and from where I was calling this method the stack was empty. Wrapping the call with
UIGraphicsPushContext(context); and UIGraphicsPopContext();
did the trick.
For completeness, here is the code needed for Cocoa. Also works with .drawInRect...
CGContextSaveGState(context)
let old_nsctx = NSGraphicsContext.currentContext() // in case there was one
// force "my" context...
NSGraphicsContext.setCurrentContext(NSGraphicsContext(CGContext: context, flipped: true))
// Do any rotations, translations, etc. here
str.drawAtPoint(cgPt, withAttributes: attributes)
NSGraphicsContext.setCurrentContext(old_nsctx)// clean up for others
CGContextRestoreGState(context)
This is mostly not needed, as #davbryn says, as normally there is already a "working" context on the stack that is the same (you hope!) as your context, however, as he points out, sometimes there isn't. I discovered this problem particularly with MapKit MKOverlayRenderer's drawMapRect:, which simply wouldn't show text without setting the context explicitly.

Using .png files instead of using .ico files in windows programs

hi I have a collection of nice .png files....
meanwhile, I'm developing a win-based software and need some .ico files as icons for toolbar buttons and ....
Is there any way to use .png file as an icon ? or what?
Thank you
As a workaround you can use IrfanView to convert your *.png file to *.ico file (or any other image to ico) & use it.
http://www.irfanview.com/main_download_engl.htm
You can simply convert the images to ico files online Ico Convert.
If you are using .NET this is not a real problem for you, because afaik PNG support is already build in. You are probably talking about native C/C++ development with GDI/win32?
To my knowledge you will not accomplish this by simply using GDI. There are a couple of options where you can set ONE color as transparent then load a simple BMP/JPEG and do some BITMAP tricks however using ICO/GIF will be far easier for this.
What you are probably looking for is a working GDI+ example which will use a PNG with alpha channel? This is just an excerpt and I left out the whole mess loading external functions from a DLL part, but maybe this will help you:
static GpImage *background = NULL;
GDIPLOADIMAGEFROMSTREAM GdipLoadImageFromStream;
GDIPLUSSTARTUP GdiplusStartup;
GDIPPLUSSHUTDOWN GdiplusShutdown;
GDIPCREATEFROMHDC GdipCreateFromHDC;
GDIPDELETEGRAPHICS GdipDeleteGraphics;
GDIPDRAWIMAGEI GdipDrawImageI;
GDIPDRAWIMAGERECTI GdipDrawImageRectI;
GDIPLUS_STARTUP_INPUT GdiplusStartupInput;
void LoadPNG(GpImage **image, int resource, HMODULE hInstance)
{
HRSRC resrc;
LPSTREAM lpstr;
HGLOBAL hPng;
LPVOID fByte;
GpImage *img = NULL;
resrc = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(resource), TEXT("PNG"));
hPng = LoadResource(GetModuleHandle(NULL), resrc);
fByte = LockResource(hPng);
lpstr = SHCreateMemStream(fByte, 200000);
GdipLoadImageFromStream(lpstr, &img);
*image = img;
}
void CreateBack(HWND hWnd)
{
HDC memDC = NULL;
HDC hdc = NULL;
RECT rect;
DeleteObject(curBack);
GetClientRect(hWnd, &rect);
hdc = GetDC(hWnd);
memDC = CreateCompatibleDC(hdc);
curBack = CreateCompatibleBitmap(hdc, rect.right, 44);
SelectObject(memDC, curBack);
/* gdiplus - background*/ {
int e = 0;
GpGraphics *g;
GdipCreateFromHDC(memDC, &g);
GdipDrawImageRectI(g, background, e, 0, 971, 44);
GdipDeleteGraphics(g);
}
DeleteObject(memDC);
ReleaseDC(hWnd, hdc);
}
Just a quick note: This GDI+ stuff is really CPU/memory intensive for a couple of reasons. Although fun I did abandoned this approach in favor of gdi and simple BMPs.
If you're loading the images from a resource file, then no, you can't use PNGs, you have to use ICOs. Fortunately, there are a number of tools that can convert PNGs into ICOs, including ImageMagick (great for automation), and MSPaint as a lowest common denominator.
If you're loading image files at runtime, then you can load any type of image format you want (e.g. use libpng for loading PNGs), but you still have to convert them to icons internally before you can do interesting things with them, such as setting them as a window's icon. Once you've decoded the image data, it's not terribly difficult to convert it to the proper format, but it's not trivial, it just involves a lot of data mangling and strange structs and function calls from the Win32 API.