Reduce pdf size - Objective c - ios

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)

Related

Xcode Image cropping produces output which has pixel imperfections

Im using the following code to crop my UIImage:
-(UIImage*)cropWithRect:(CGRect)rect
{
if(self.scale > 1.0f){
rect = CGRectMake(rect.origin.x * self.scale,
rect.origin.y * self.scale,
rect.size.width * self.scale,
rect.size.height * self.scale);
}
CGImageRef imageRef = (CGImageCreateWithImageInRect(self.CGImage, rect));
return [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
}
But this gives me an output image which has wrong pixel colors which is noticeable when zoomed in. For instance, white input pixel sometimes becomes off-white (not always - only when the white pixels are close to other pixels of dark colors).
Can I get better results or is there another way to produce better cropped images?
Thanks.
May be this will help you FXImageView
Step 1: select Image
Step 2: Crop Image
Step 3: Result Image

Drawn image over PDF is upside-down

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

png image is not displaying after "reDraw"

I am using custom png images for items of .tabBarItem of my UITabBarController.
But my png images are too big (64x64), so I use the method below to redraw the image in a smaller rect (for example, make the size parameter (25,25) ).
-(UIImage*) getSmallImage:(UIImage*)image inSize: (CGSize)size
{
CGSize originalImageSize = image.size;
CGRect newRect = CGRectMake(0, 0, size.width, size.height);
float ratio = MAX(newRect.size.width/originalImageSize.width,
newRect.size.height/originalImageSize.height);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];
[path addClip];
CGRect projectRect;
projectRect.size.width = ratio * originalImageSize.width;
projectRect.size.height = ratio * originalImageSize.height;
//projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
//projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
// Draw the image on it
[image drawInRect:projectRect];
// Get the image from the image context
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup image context resources
UIGraphicsEndImageContext();
return smallImage;
}
Every image I use was returned by this method. Everything was fine on simulators, but those images were not displaying when I test them on my iphone.
But if I abandon the method above and import the image directly like this: self.tabBarItem.image = [UIImage imageNamed:#"Input"]; Then the images were correctly shown on my phone, but only too big.
How can I fix this problem?
I'll answer this question by myself.
After hours of debugging, here is the problem:
in the method given above, originproperty of CGRect projectRectwas not set.
After I set both origin.x & origin.y to 0, everything worked out.
Tip: every time you meet a WTF problem, be patient and try to test your code in different ways. 'Cause in 99.9% of this kind of cases, there is something wrong with your code in stead of a bug of Xcode.
Though I still don't know why the code in my question works well in simulators, I'll let it go because I guess someday when I become an expert, this kind of question would be easy as well as silly.

Resize image and maintain its aspect ratio in iOS

I am trying to select an image from photo library, this is the photo which I have downloaded from net and is stored in my photo lib.
So now I want to give user an option to select an image from photo lib and apply as a backgroundImage throught my app, but when I do it, I get the image this way on my iphone screen
Actually the image has been filled the screen, because the content mode specified is "scaleToFill".
1) I want to know how to make this image maintain its aspect ratio and also fill the screen?
Regards
Ranjit
check this blog. use these two files
UIImage+Resize.h
UIImage+Resize.m
UIImage *image = [UIImage imageNamed:#"SomeImage-900x675"]; // SomeImage-900x675.png
CGFloat targetWidth = 320.0;
CGFloat scaleFactor = targetWidth / image.size.width;
CGFloat targetHeight = image.size.height * scaleFactor;
CGSize targetSize = CGSizeMake(targetWidth, targetHeight);
UIImage *scaledImage = [image resizedImage:targetSize interpolationQuality:kCGInterpolationHigh];
though your image is taking all the screen size, Your image size is biger...You will try by scaling image with following resolutions
320*480,
640*960,
1240*2208

Can you load only a smaller rectangular portion of a larger on-disk image into memory?

On iOS and most mobile devices there is a restriction on the size of the image that you can load, due to memory contraints. Is it possible to have a large image on disk (say 5,000 pixels by 5,000 pixels) but only read a smaller rectangle within that image (say 100x100) into memory for display?
In other words, do you need to load the entire image into memory if you just want to see a small subsection of it? If it's possible to load just the smaller portion, how can we do this?
This way, one could save a lot of space like spritesheets do for repetitive content. It would be important to note that the overall goal is to minimize the file size so the large image should be compressed with jpeg or png or some other kind of compression. I suspect video formats are like this because you never load an entire video into the memory.
Although I have not utilized the techniques, you might find the following Apple Sample useful:
LargeImageDownsizing Sample
You could do something with mapped NSData like this:
UIImage *pixelDataForRect(NSString *fileName, const CGRect pixelRect)
{
// get the pixels from that image
uint32_t width = pixelRect.size.width;
uint32_t height = pixelRect.size.height;
// create the context
UIGraphicsBeginImageContext(CGSizeMake(width, height));
CGContextRef bitMapContext = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, height);
CGContextConcatCTM(bitMapContext, flipVertical);
// render the image (assume PNG compression)
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef) [NSData dataWithContentsOfMappedFile:fileName]);
CGImageRef image = CGImageCreateWithPNGDataProvider(provider, NULL, YES, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
uint32_t imageWidth = CGImageGetWidth(image);
uint32_t imageHeight = CGImageGetHeight(image);
CGRect drawRect = CGRectMake(-pixelRect.origin.x, -((imageHeight - pixelRect.origin.y) - height), imageWidth, imageHeight);
CGContextDrawImage(bitMapContext, drawRect, image);
CGImageRelease(image);
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return retImage;
}
Your best bet is using UIScrollView with CATiledLayer.
Check out the "Designing Apps with Scroll Views presentation from WWDC 2010 for a description of how to do this:
https://developer.apple.com/videos/wwdc/2010/
The idea is to take your large image and chop it down into tiles, and then use a UIScrollView to provide your user with a scrollable view of the image, only loading those sections of the image that are necessary based on the position of the scrollview. This is accomplished using CATiledLayer.

Resources