Coreplot Library - Extract entire graph image - iphone

i am creating image for graph using this code
UIImage *newImage=[graph imageOfLayer]
NSData *newPNG= UIImageJPEGRepresentation(newImage, 1.0);
NSString *filePath=[NSString stringWithFormat:#"%#/graph.jpg", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
if([newPNG writeToFile:filePath atomically:YES])
NSLog(#"Created new file successfully");
But i get only visible area(320*460) in image, How can i get whole graph image with axis.
Please provide some code snippet, how can i do it with coreplot.
Thanks In Advance...

Make a new graph the size of the desired output image. It doesn't have to be added to a hosting view—that's only needed for displaying it on screen.
CPTXYGraph *graph = [(CPTXYGraph *)[CPTXYGraph alloc] initWithFrame:desiredFrame];
// set up the graph as usual
UIImage *newImage=[graph imageOfLayer];
// process output image

My approach to this problem was to create a method to extract the image.
In that method I momentarily make the hosting view, scroll view, graph bounds, and plot area frame bounds momentarily bigger. I then convert the graph to a an image.
I then remove the hosting view from its container to remove it from screen. I then call the doPlot method to reinitialise the plot and its data via the DoPlot method. My code is below.
There might be a visual jitter whilst this is carried out. However, you could always disguise this by using a alert either to enter an email for export, or just a simple alert saying image exported.
//=============================================================================
/**
Gets the image of the chart to export via email.
*/
//=============================================================================
-(UIImage *) getImage
{
//Temprorarilty make plot bigger.
// CGRect rect = self.hostingView.bounds;
CGRect rect = self.scroller.bounds;
rect.size.height = rect.size.height -100;
rect.origin.x = 0;
rect.size.width = rect.size.width + [fields count] * 100.0;
[self.hostingView setBounds:rect];
[scroller setContentSize: hostingView.frame.size];
graph.plotAreaFrame.bounds = rect;
graph.bounds = rect;
UIImage * image =[graph imageOfLayer];//get image of plot.
//Redraw the plot back at its normal size;
[self.hostingView removeFromSuperview];
self.hostingView = nil;
[self doPlot];
return image;
}//============================================================================

Related

divide image into two parts using divider

I'm working on one app where I need to divide a image into two part using a red line.
left part for labels
right part for prices
Question 1.
How can I draw a red line on image?
Question 2.
How can I divide image to two parts using red line ?( red line position is not fixed. user can move the position wherever it want)
Question 3.
How can I get line current position and how can I use that position two divide image
Thanks in advance
I would approach this in somewhat the same manner as koray was suggesting:
1) I am assuming that your above image/view is going to be managed by a view controller, which I will call ImageSeperatorViewController from here on.
Inside of ImageSeperatorViewController, insert koray's code in the -(void) viewDidLoad{} method. Make sure you change the imageToSplit variable to be an UIImageView instead of a plain UIView.
2) Next, I assume that you know how to detect user gestures. You will detect these gestures, and determine if the user has selected the view (i.e. bar in koray's code). Once you have determined if the user has selected bar, just update its origin's X position with the touch position.
CGRect barFrame = bar.frame;
barFrame.origin.x = *X location of the users touch*
bar.frame = barFrame;
3) For cropping, I would not use github.com/bilalmughal/NLImageCropper, it will not do what you need to do.
Try this on for size:
Header:
#interface UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor*)color;
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage;
- (NSArray*)imagesBySlicingAt:(CGFloat)position;
#end
Implementation:
#implementation UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage
{
//pattern image
UIColor *patternColor = [UIColor colorWithPatternImage:patternImage];
CGFloat width = patternImage.size.width;
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color from the pattern image color
CGContextSetFillColorWithColor(context, patternColor.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//the joy of image color patterns being based on 0,0 origin! must set phase
CGContextSetPatternPhase(context, CGSizeMake(dividerRect.origin.x, 0));
//fill the divider rect with the repeating pattern from the image
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor *)color
{
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color for your divider
CGContextSetFillColorWithColor(context, color.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//fill the divider's rect with the provided color
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (NSArray*)imagesBySlicingAt:(CGFloat)position
{
NSMutableArray *slices = [NSMutableArray array];
//first image
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
//second
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(self.size.width - position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointMake(-position, 0)];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
return slices;
}
The concept is simple - you want an image with the divider drawn over it. You could just overlay a view, or override drawRect:, or any number of any solutions. I'd rather give you this category. It just uses some quick Core Graphics calls to generate an image with your desired divider, be it pattern image or color, at the specified position. If you want support for horizontal dividers as well, it is rather trivial to modify this as such. Bonus: You can use a tiled image as your divider!
Now to answer your primary question. Using the category is rather self explanatory - just call one of the two methods on your source background to generate one with the divider, and then apply that image rather than the original source image.
Now, the second question is simple - when the divider has been moved, regenerate the image based on the new divider position. This is actually a relatively inefficient way of doing it, but this ought to be lightweight enough for your purposes as well as only being an issue when moving the divider. Premature optimization is just as much a sin.
Third question is also simple - call imagesBySlicingAt: - it will return an array of two images, as generated by slicing through the image at the provided position. Use them as you wish.
This code has been tested to be functional. I strongly suggest that you fiddle around with it, not for any purpose of utility, but to better understand the mechanisms used so that next time, you can be on the answering side of things
For Crop you can try this,
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
CGImageRef tmpImgRef = image.CGImage;
CGImageRef topImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, 0, image.size.width, image.size.height / 2.0));
UIImage *topImage = [UIImage imageWithCGImage:topImgRef];
CGImageRelease(topImgRef);
CGImageRef bottomImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, image.size.height / 2.0, image.size.width, image.size.height / 2.0));
UIImage *bottomImage = [UIImage imageWithCGImage:bottomImgRef];
CGImageRelease(bottomImgRef);
hope this can help you, :)
if you want to draw a line you could just use a UIView with red background and make the height the size of your image and the width around 5 pixels.
UIView *imageToSplit; //the image im trying to split using a red bar
CGRect i = imageToSplit.frame;
int x = i.origin.x + i.size.width/2;
int y = i.origin.y;
int width = 5;
int height = i.size.height;
UIView *bar = [[[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)] autorelease];
bar.backgroundColor = [UIColor redColor];
[self.view addSubview:bar];

Setting frame of CCTexture to fit into a predefined frame CCSprite

I am downloading an image from server and displaying it on game scene. I am able to get the CCTexture2D of the image from server and display it on game scene. The problem is that the image from server may vary in size. But I have to display that image on to a predefined frame CCSprite.
CCSprite *temp = [CCSprite spriteWithTexture:[[CCTexture2D alloc] initWithImage:[UIImage imageWithData:data] resolutionType:kCCResolutioniPhoneFourInchDisplay]];
CCRenderTexture *test=[CCRenderTexture renderTextureWithWidth:70 height:70]; //set proper width and height
[test begin];
[temp draw];
[test end];
UIImage *img=[test getUIImageFromBuffer];
sprite_Temp =[CCSprite spriteWithCGImage:img.CGImage key:#"1"];
sprite_Temp.tag = K_TagUserImage;
sprite_Temp.scale=1;
sprite_Temp.position=ccp(432,273);
[self addChild:sprite_Temp z:1];
I am using this code to resize the CCTexture2D to predefined frame CCSprite. But the image gets cropped to the desired frame which is not wanted. Can someone tell me how to get the original image from server to desired frame without getting cropped. Thanks.
try :
CCSprite *temp = [CCSprite spriteWithTexture:[[CCTexture2D alloc] initWithImage:[UIImage imageWithData:data] resolutionType:kCCResolutioniPhoneFourInchDisplay]];
float scaleX = 70./temp.contentSize.width;
float scaleY = 70./temp.contentSize.height;
// if you want to preserve the original texture's aspect ratio
float scale = MIN(scaleX,scaleY);
temp.scale = scale;
// or if you want to 'stretch-n-squeeze' to 70x70
temp.scaleX = scaleX;
temp.scaleY = scaleY;
// then add the sprite *temp
usual disclaimer : not tested, done from memory, beware of divides by 0 :)

Preloading a UIImageView animation using objective c for the iphone

I have an animated image which works great. It consists of 180 high quality images and it plays fine and loops continuously. My problem is that the first time I load the view containing these images it takes a long time to load. Every subsequent time after that it loads immediately as I am assuming that the images have been cached or preloaded!!! I come from a flash background and as I am sure you aware preloaders are as common as muck so I don't feel this should be difficult to find but after countless googling I cannot find any good examples on preloading or any articles on why there is a delay and what to do about it.
So my question(s) is this:
Is there a checkbox in the info.plist to preload all my images at the start of the app?
How can you preload images and are there any simple example projects that I could look at?
Is this the best way to implement what is essentially a video but has been output to a png sequence?
Is there another method as viewDidLoad does not work as I expect it to do. It traces "FINISHED LOADING IMAGES" (see code below) but the view does not show for a second or two after the images have been loaded so if the view does not show until the images have loaded then neither will the UIActivityIndicatorView which is also in the same view.
How do you do event listening in objective c?
Below is the code in the viewDidLoad which I believe is fairly standard:
Any help is greatly appreciated as I am banging my head on a brick wall on something that seems so basic in ui development. Help :)
- (void)viewDidLoad {
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] initWithCapacity:IMAGE_COUNT];
NSLog(#"START LOADING IMAGES");
// Build array of images, cycling through image names
for (int i = 0; i < IMAGE_COUNT; i++){
[imageArray addObject:[UIImage imageNamed: [NSString stringWithFormat:#"Main_%d.png", i]]];
}
animatedImages = [[UIImageView alloc] initWithFrame:CGRectMake(0,20,IMAGE_WIDTH, IMAGE_HEIGHT)];
animatedImages.animationImages = [NSArray arrayWithArray:imageArray];
animatedImages.animationDuration = 6.0;
animatedImages.animationRepeatCount = 0;
[self.view addSubview:animatedImages];
animatedImages.startAnimating;
[animatedImages release];
NSLog(#"FINISH LOADING IMAGES");
}
Cheers
M
In case someone finds this question, I have an answer, which is to pre-render the images like this.
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] init];
for (int aniCount = 1; aniCount < 21; aniCount++) {
NSString *fileLocation = [[NSBundle mainBundle] pathForResource: [NSString stringWithFormat: #"bg%i", aniCount + 1] ofType: #"png"];
// here is the code to load and pre-render the image
UIImage *frameImage = [UIImage imageWithContentsOfFile: fileLocation];
UIGraphicsBeginImageContext(frameImage.size);
CGRect rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
[frameImage drawInRect:rect];
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// then add the resulting image to the array
[menuanimationImages addObject:renderedImage];
}
settingsBackground.animationImages = menuanimationImages;
I have tried multiple other methods of pre-loading images, and this is the only thing I've found that works.
My problem is that the first time I load the view containing these images it takes a long time to load. Every subsequent time after that it loads immediately as I am assuming that the images have been cached or preloaded
you are right at this point ...... as you are using method imageNamed: for this method document quotes.....
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
so in my opinion, rather than doing following stuff in viewDidLoad, you should do it earlier where delay is of not considerable......
for (int i = 0; i < IMAGE_COUNT; i++)
{
[imageArray addObject:[UIImage imageNamed: [NSString stringWithFormat:#"Main_%d.png", i]]];
}
another approach
- (void)spinLayer:(CALayer *)inLayer duration:(CFTimeInterval)inDuration
direction:(int)direction
{
CABasicAnimation* rotationAnimation;
// Rotate about the z axis
rotationAnimation =
[CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
// Rotate 360 degress, in direction specified
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 * direction];
// Perform the rotation over this many seconds
rotationAnimation.duration = inDuration;
rotationAnimation.repeatCount = 100;
//rotationAnimation.
// Set the pacing of the animation
//rotationAnimation.timingFunction =
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// Add animation to the layer and make it so
[inLayer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
this method will help in animation call it as follow(I am assuming that you are putting above method in same class where you have imageView.
[self spinLayer:yourImageView.layer duration:5.0
direction:<-1 or 1 for anti clockwise or clockwise spin>];
remember just set only one image to that imageView(which you wish to animate.
thanks,

Retina display of images-iPhone 3 to 4

I have developed an application of tile game for iPhone 3.
In which I took an image from my resource and divided it into number of tiles using CGImageCreateWithImageInRect ( originalImage.CGImage, frame ); function.
It works great on all iPhones but now I want it to work on Retina Displays also.
So as per this link I have taken anothe image with its size double the current images size and rename it by adding suffix #2x. But the problem is it takes the upper half part of the retina display image only. I think thats because of the frame I have set while using CGImageCreateWithImageInRect. So What shall be done in respect to make this work.
Any kind of help will be really appreciated.
Thanks in advance...
The problem is likely that the #2x image scale is only automatically set up properly for certain initializers of UIImage... Try loading your UIImages using code like this from Tasty Pixel. The entry at that link talks more about this issue.
Using the UIImage+TPAdditions category from the link, you'll implement it like so (after making sure that the images and their #2x counterparts are in your project):
NSString *baseImagePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *myImagePath = [baseImagePath stringByAppendingPathComponent:#"myImage.png"]; // note no need to add #2x.png here
UIImage *myImage = [UIImage imageWithContentsOfResolutionIndependentFile:myImagePath];
Then you should be able to use CGImageCreateWithImageInRect(myImage.CGImage, frame);
Here's how I got it to work in an app I did:
//this is a method that takes a UIImage and slices it into 16 tiles (GridSize * GridSize)
#define GridSize 4
- (void) sliceImage:(UIImage *)image {
CGSize imageSize = [image size];
CGSize square = CGSizeMake(imageSize.width/GridSize, imageSize.height/GridSize);
CGFloat scaleMultiplier = [image scale];
square.width *= scaleMultiplier;
square.height *= scaleMultiplier;
CGFloat scale = ([self frame].size.width/GridSize)/square.width;
CGImageRef source = [image CGImage];
if (source != NULL) {
for (int r = 0; r < GridSize; ++r) {
for (int c = 0; c < GridSize; ++c) {
CGRect slice = CGRectMake(c*square.width, r*square.height, square.width, square.height);
CGImageRef sliceImage = CGImageCreateWithImageInRect(source, slice);
if (sliceImage) {
//we have a tile (as a CGImageRef) from the source image
//do something with it
CFRelease(sliceImage);
}
}
}
}
}
The trick is using the -[UIImage scale] property to figure out how big of a rect you should be slicing.

Saving UIView contents in iOS 4 with real size of the images inside (i.e. scale contentes up for save)

I have an UIView with many UIImageViews as subviews. The app runs on iOS4 and I use images with retina display resolution (i.e. the images load with scale = 2)
I want to save the contents of the UIView ... BUT ... have the real size of the images inside. I.e. the view has size 200x200 and images with scale=2 inside, I'd like to save a resulting image of 400x400 and all the images with their real size.
Now what comes first to mind is to create a new image context and load again all images inside with scale=1 and that should do, but I was wondering if there is any more elegant way to do that? Seems like a waist of memory and processor time to reload everything again since it's already done ...
p.s. if anyone has an answer - including code would be nice
Implementation for rendering any UIView to image (working also for retina display).
helper.h file:
#interface UIView (Ext)
- (UIImage*) renderToImage;
#end
and belonging implementation in helper.m file:
#import <QuartzCore/QuartzCore.h>
#implementation UIView (Ext)
- (UIImage*) renderToImage
{
// IMPORTANT: using weak link on UIKit
if(UIGraphicsBeginImageContextWithOptions != NULL)
{
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(self.frame.size);
}
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
0.0 is the scale factor. The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
QuartzCore.framework also should be put into the project because we are calling function on the layer object.
To enable weak link on UIKit framework, click on the project item in left navigator, click the project target -> build phases -> link binary and choose "optional" (weak) type on UIKit framework.
Here is library with similar extensions for UIColor, UIImage, NSArray, NSDictionary, ...
I've performed such thing to save the pins from the MKMapView as a PNG file (in retina display): MKPinAnnotationView: Are there more than three colors available?
Here's an extract of the crucial part that performs the saving of a UIView (theView) using its retina definition:
-(void) saveMyView:(UIView*)theView {
//The image where the view content is going to be saved.
UIImage* image = nil;
UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, 2.0);
[theView.layer renderInContext: UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData* imgData = UIImagePNGRepresentation(image);
NSString* targetPath = [NSString stringWithFormat:#"%#/%#", [self writablePath], #"thisismyview.png" ];
[imgData writeToFile:targetPath atomically:YES];
}
-(NSString*) writablePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return documentsDirectory;
}
The key is that the third parameter to UIGraphicsBeginImageContextWithOptions is the scale, which determines how the image will ultimately be written out.
If you always want the real pixel dimensions, use [[UIScreen mainScreen] scale] to get the current scale of the screen:
UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);
If you use scale=1.0 on iPhone4, you will get an image with its dimension in points and the result is scaled down from the true pixel count. If you manually write the image out to a 640x960 dimension (eg: passing pixels as the first parameter), it will actually be the scaled-down image that is scaled back up which looks about as terrible as you imagine it would look.
Couldn't you just create a new graphics context at the desired size, use a CGAffineTransform to scale it down, render the root UIView's root layer, restore the context to the original size and render the image? Haven't tried this for retina content, but this seems to work well for large images that have been scaled down in UIImageViews...
something like:
CGSize originalSize = myOriginalImage.size; //or whatever
//create context
UIGraphicsBeginImageContext(originalSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context); //1 original context
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, originalSize.height);
CGContextScaleCTM(context, 1.0, -1.0);
//original image
CGContextDrawImage(context, CGRectMake(0,0,originalSize.width,originalSize.height), myOriginalImage.CGImage);
CGContextRestoreGState(context);//1 restore to original for UIView render;
//scaling
CGFloat wratio = originalSize.width/self.view.frame.size.width;
CGFloat hratio = originalSize.height/self.view.frame.size.height;
//scale context to match view size
CGContextSaveGState(context); //1 pre-scaled size
CGContextScaleCTM(context, wratio, hratio);
//render
[self.view.layer renderInContext:context];
CGContextRestoreGState(context);//1 restore to pre-scaled size;
UIImage *exportImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Import QuartzCore (Click main project, Build Phases, import) and where you need it add:
#import <QuartzCore/QuartzCore.h>
My imageViews are properties, if your are not, ignore the .self and pass the imageViews into the function as parameters, then call renderInContext on the two images in a new UIGraphicsCurrentContext
- (UIImage *)saveImage
{
UIGraphicsBeginImageContextWithOptions(self.mainImage.bounds.size, NO, 0.0);
[self.backgroundImage.layer renderInContext:UIGraphicsGetCurrentContext()];
[self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *savedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return savedImage;
}