Drawn image over PDF is upside-down - ios

I am trying to draw an image over an existing PDF (displayed on the screen). The final goal would be to sign the pdf anywhere.
My sample code is here on Github
The code (basic) works like this :
The user clicks where he wants to draw the image
The PDF editing occurs and the final PDF appears on screen
However the problem is that my image appears upside down. While working with PDF, I learned that you have to flip context to render, it may be related.
- (void)editPDFWithName:(NSString*)pdfName
{
// grab reference to bundled PDF
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)[[NSBundle mainBundle] URLForResource:pdfName withExtension:#"pdf"]);
const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);
// Begin PDF context
NSMutableData* data = [NSMutableData data];
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);
// loop over PDF pages to render it
for(size_t page = 1; page <= numberOfPages; page++)
{
// Get the current page and page frame
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
// Draw the page (flipped)
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
// Y axis is negative in order to render PDF (mandatory)
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
CGContextDrawPDFPage(ctx, pdfPage);
CGContextRestoreGState(ctx);
if(page == [self getCurrentPage])
{
// 0.75f factor to convert pixel/points
CGContextDrawImage(ctx, CGRectMake(self.xTouchCoord*0.75f, self.yTouchCoord*0.75f, self.logo.size.width, self.logo.size.height), self.logo.CGImage);
}
}
UIGraphicsEndPDFContext();
CGPDFDocumentRelease(pdf);
pdf = nil;
// Save PDF
[self savePDF:data];
}
I tried multiple ways to flip image as suggested on this post
But the image is still flipped.
One thing I noticed is if I use the method drawAtPoint method on the image, it appears not flipped but does not appear at the specified position, like there is an offset (see other post here)
Can someone please suggest any idea ? I'm betting on the Save and Restore context methods but cannot get it working.

Well I finally found the solution :
use drawInRectinstead of CGContextDrawImage
for better precision, don't forget to subtract half of the width and height to the coordinates to adjust the center :
// 0.75f factor to convert pixel/points
[self.logo drawInRect:CGRectMake(self.xTouchCoord*0.75f - self.logo.size.width/2, self.yTouchCoord*0.75f - self.logo.size.width/2, self.logo.size.width, self.logo.size.height)];

Related

Core plot graph is rendered as black box when converting into pdf

I my application used Core Plot to render graphs, and finally there is a need to create a pdf file, there should be this graph, but when it is saved to pdf file, instead of graph I see black box.
The method I use to create a pdf:
UIGraphicsBeginPDFContextToFile(outputPath, CGRectZero, nil);
for(UIView *view in views) {
UIGraphicsBeginPDFPageWithInfo(view.bounds, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();UIGraphicsBeginPDFContextToFile
[view.layer renderInContext:pdfContext];
}
UIGraphicsEndPDFContext();
Could someone help how to make it render properly?
As a temporary solution before creating a pdf I convert graph to image and put it on the top of it as a result pdf is rendered properly, Is there any more elegant solution?
Edited:
I applied the above advice the code looks like this:
if([child isKindOfClass:[CPTGraphHostingView class]]) {
CGContextTranslateCTM(pdfContext, child.center.x, child.center.y);
CGAffineTransform transform = CGAffineTransformMakeRotation(0);
transform.d = -1;
CGContextConcatCTM(pdfContext, transform);
CGContextTranslateCTM(pdfContext,
child.bounds.size.width * 0.05,
-child.bounds.size.height * 0.75);
CPTLayer *layer = (CPTLayer *)((CPTGraphHostingView *)child).hostedGraph;
[layer layoutAndRenderInContext:pdfContext];
}
Result on UI:
and as a result is pdf:
Are you using any fills with partially transparent colors? The alpha channel doesn't render into PDF. This is a long-standing issue with the Apple PDF frameworks.

iOS - display PDF in a different Orientation

I'm using the following code to display a PDF inside a UIView
Its a simple application, displaying a single PDF (which is all I need) and I"m handling zooming separately: The problem I'm having with this is when the iPad changes to Landscape everything is distorted - any help as to where I should look ? / what i should do to handle the orientation issue ?
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
//PDF might be transparent, assume white paper - set White Background
[[UIColor whiteColor] set];
CGContextFillRect(ctx, rect);
//Flip coordinates
CGContextGetCTM(ctx);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -rect.size.height);
//PDF File Path
NSURL *pdfURL = [[NSBundle mainBundle] URLForResource:#"TEST" withExtension:#"pdf"];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfURL);
CGPDFPageRef page1 = CGPDFDocumentGetPage(pdf, 1);
//Get the rectangle of the cropped inside
CGRect mediaRect = CGPDFPageGetBoxRect(page1, kCGPDFCropBox);
CGContextScaleCTM(ctx, rect.size.width / mediaRect.size.width,
rect.size.height / mediaRect.size.height);
//Draw PDF
CGContextDrawPDFPage(ctx, page1);
CGPDFDocumentRelease(pdf);
}
Hi For Anybody Who may be interested in this. . .
This may be the best way to do it :
Supporting two orientations with separate view controllers in iOS
The following question discusses how to register to device orientation change, When a change in orientation is detected, a modal View is pushed -displaying the PDF with dimensions
The Other options may be as follows : when you initialize the UIView decide how you want it to react when the orientation changes
UIView.contentMode = UIViewContentModeScaleAspectFill;
Play around with the various UIViewContentMode... : to achieve the best effect for you
The current one allows the PDF to be redrawn maintaining its Aspect ration and filling the entire size of the screen:so it cuts of about half the PDF - - -

Reduce pdf size - Objective c

I have a pdf generation project, it consist of some texts and an image which is already stored in db, i want to preview and mail the pdf generated, everything is ok when there is only text data.
Problem arises if there is image in our data. The mail receives
the pdf of size 10MB or above even if it have image of size 1MB or below.It is working fine in simulator.My code to draw image is shown below:
UIImage *plotImage=[[UIImage alloc]initWithContentsOfFile:[localPictureArray objectAtIndex:i]];
CGSize imageSize=plotImage.size;
CGFloat scaleFactor = 1.0;
if (imageSize.height>(maxHeight-currentPageY) || imageSize.width>maxWidth )
{
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
currentPageY = kMargin;
if (!((scaleFactor = (maxWidth / imageSize.width)) > ((maxHeight-currentPageY) / imageSize.height)))
{
scaleFactor = (maxHeight-currentPageY) /imageSize.height;
// scale to fit heigth.
}
CGRect rect = CGRectMake(kMargin,currentPageY,
imageSize.width * scaleFactor, imageSize.height * scaleFactor);
//Draw the image into the rect
[plotImage drawInRect:rect];
}
else
{
plotImage drawInRect:normal size)];//Normal size we need
NSLog(#"%#",NSStringFromCGSize(plotImage.size));
}
Since iam a starter iam struggling to solve it.
I struggled a lot.. at last when wrote image in jpeg format to pdf page using below code, size got reduced ten times!! Don't know it is the right method...
UIImage *lowResImage = [UIImage imageWithData:UIImageJPEGRepresentation(plotImage, 0.02)];
Instead of resizing the rect in the context, You need to change the CTM (Current Transform Matrix).
CGContextSaveGState(theContext);
CGContextScaleCTM(theContext, scaleFactor, scaleFactor);
... Drawing commands here ...
CGContextRestoreGState(theContext);
(http://macdevcenter.com/pub/a/mac/2004/11/02/quartz.html)

How can I generate a PDF with "real" text content on iOS?

I want to generate a good-looking PDF in my iOS 6 app.
I've tried:
UIView render in context
Using CoreText
Using NSString drawInRect
Using UILabel drawRect
Here is a code example:
-(CGContextRef) createPDFContext:(CGRect)inMediaBox path:(NSString *) path
{
CGContextRef myOutContext = NULL;
NSURL * url;
url = [NSURL fileURLWithPath:path];
if (url != NULL) {
myOutContext = CGPDFContextCreateWithURL ((__bridge CFURLRef) url,
&inMediaBox,
NULL);
}
return myOutContext;
}
-(void)savePdf:(NSString *)outputPath
{
if (!pageViews.count)
return;
UIView * first = [pageViews objectAtIndex:0];
CGContextRef pdfContext = [self createPDFContext:CGRectMake(0, 0, first.frame.size.width, first.frame.size.height) path:outputPath];
for(UIView * v in pageViews)
{
CGContextBeginPage (pdfContext,nil);
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0, (int)(v.frame.size.height));
transform = CGAffineTransformScale(transform, 1, -1);
CGContextConcatCTM(pdfContext, transform);
CGContextSetFillColorWithColor(pdfContext, [UIColor whiteColor].CGColor);
CGContextFillRect(pdfContext, v.frame);
[v.layer renderInContext:pdfContext];
CGContextEndPage (pdfContext);
}
CGContextRelease (pdfContext);
}
The UIViews that are rendered only contain a UIImageView + a bunch of UILabels (some with and some without borders).
I also tried a suggestion found on stackoverflow: subclassing UILabel and doing this:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());
if (!layer.shouldRasterize && isPDF)
[self drawRect:self.bounds]; // draw unrasterized
else
[super drawLayer:layer inContext:ctx];
}
But that didn't change anything either.
No matter what I do, when opening the PDF in Preview the text parts are selectable as a block, but not character per character, and zooming the pdf shows it is actually a bitmap image.
Any suggestions?
This Tutorial From Raywenderlich Saved my Day.Hope it will work for you too.
http://www.raywenderlich.com/6818/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-2
My experience when I did this last year was that Apple didn't provide any library to do it. I ended up importing an open source C library (libHaru). Then I added a function for outputting to it in each class in my view hierarchy. Any view with subviews would call render on its subviews. My UILabels, UITextFields, UIImageViews, UISwitches etc would output their content either as text or graphics accordingly I also rendered background colors for some views.
It wasn't very daunting, but libHaru gave me some problems with fonts so iirc I ended up just using the default font and font size.
It works good with UILabels except that you have to work around a bug:
Rendering a UIView into a PDF as vectors on an iPad - Sometimes renders as bitmap, sometimes as vectors

Convert PDF to UIImageView

I've found some code which gives me a UIImage out of a PDF-File. It works, but I have two questions:
Is there a possibility to achieve a better quality of the UIImage? (See Screenshot)
I only see the first page in my UIImageView. Do I have to embed the file in a UIScrollView to be complete?
Or is it better to render just one page and use buttons to navigate through the pages?
P.S. I know that UIWebView can display PDF-Pages with some functionalities but I need it as a UIImage or at least in a UIView.
Bad quality Image:
Code:
-(UIImage *)image {
UIGraphicsBeginImageContext(CGSizeMake(280, 320));
CGContextRef context = UIGraphicsGetCurrentContext();
CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("ls.pdf"), NULL, NULL);
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CGContextTranslateCTM(context, 0.0, 320);
CGContextScaleCTM(context, 1.0, -1.0);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 4);
CGContextSaveGState(context);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, CGRectMake(0, 0, 280, 320), 0, true);
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultingImage;
}
I know i'm a little late here, but i hope i can help someone else looking for an answer.
As to the questions asked:
I'm afraid the only way to achieve a better image quality is to render a bigger image, and letting the UIImageView resize it for you. I don't think you can set the resolution, but using a bigger image may be a good choice. It won't take too long for the page to render, and the image will have a better quality. PDF files are rendered on demand depending on the zoom level, that's why they seem to have "better quality".
As to rendering all the pages, you can get the number of pages in the document calling CGPDFDocumentGetNumberOfPages( pdf ) and using a simple for loop you can concat all the images generated in one single image. For displaying it, use the UIScrollVIew.
In my opinion, this approach is better than the above, but you should try to optimize it, for example rendering always the current, the previous and the next page. For nice scrolling transition effects, why not use a horizontal UIScrollView.
For more generic rendering code, i always do the rotation like this:
int rotation = CGPDFPageGetRotationAngle(page);
CGContextTranslateCTM(context, 0, imageSize.height);//moves up Height
CGContextScaleCTM(context, 1.0, -1.0);//flips horizontally down
CGContextRotateCTM(context, -rotation*M_PI/180);//rotates the pdf
CGRect placement = CGContextGetClipBoundingBox(context);//get the flip's placement
CGContextTranslateCTM(context, placement.origin.x, placement.origin.y);//moves the the correct place
//do all your drawings
CGContextDrawPDFPage(context, page);
//undo the rotations/scaling/translations
CGContextTranslateCTM(context, -placement.origin.x, -placement.origin.y);
CGContextRotateCTM(context, rotation*M_PI/180);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -imageSize.height);
Steipete already mentioned setting the white background:
CGContextSetRGBFillColor(context, 1, 1, 1, 1);
CGContextFillRect(context, CGRectMake(0, 0, imageSize.width, imageSize.height));
So the last thing to keep in mind is when exporting an image, set the quality to the maximum. For example:
UIImageJPEGRepresentation(image, 1);
What are you doing with the CGContextTranslateCTM(context, 0.0, 320); call?
You should extract the proper metrics form the pdf, with code like this:
cropBox = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
rotate = CGPDFPageGetRotationAngle(page);
Also, as you see, the pdf might has rotation info, so you need to use the CGContextTranslateCTM/CGContextRotateCTM/CGContextScaleCTM depending on the angle.
You also might wanna clip any content that is outside of the CropBox area, as pdf has various viewPorts that you usually don't wanna display (e.g. for printers so that seamless printing is possible) -> use CGContextClip.
Next, you're forgetting that the pdf reference defines a white background color. There are a lot of documents out there that don't define any background color at all - you'll get weird results if you don't draw a white background on your own --> CGContextSetRGBFillColor & CGContextFillRect.

Resources