I am trying to crop an Image whenever the user touches the UIImageView on the screen. The UIImageView is 640 X 300 area and I allow user to touch anywhere in the UIImageView. Then I use the following code to view the croppedImage and it always show me the wrong image. I think I am having trouble getting the correct coordinates.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location = [[touches anyObject] locationInView:self.view];
UIImage *originalImage = self.imageView.image;
NSLog(#"x = %f, y = %f",location.x,location.y);
CGRect cropRegion = CGRectMake(location.x, location.y, 10, 10);
CGImageRef subImage = CGImageCreateWithImageInRect(originalImage.CGImage, cropRegion);
UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
}
You're getting the coordinates relative to self.view, not relative to the image view. Try:
CGPoint location = [[touches anyObject] locationInView:self.imageView];
Related
I have managed to get drawing on top of a recently captured UIImage working, but it only works when the UIImageView covers the entire screen. It begins to lose accuracy the moment I start drawing away from the horizontal center. Any idea how I can get it to only work on the ImageView itself and have it remain accurate?
- (void)viewDidLoad
{
[super viewDidLoad];
float height = (self.view.frame.size.width * self.chosenImage.size.height)/self.chosenImage.size.width;
self.imageView.frame = CGRectMake(0, self.navigationController.navigationBar.frame.size.height, self.view.frame.size.width, height);
self.imageView.center = self.imageView.superview.center;
self.imageView.image = self.chosenImage;
}
- (UIImage *)drawLineFromPoint:(CGPoint)from_Point toPoint:(CGPoint)to_Point image:(UIImage *)image
{
CGSize sizeOf_Screen = self.imageView.frame.size;
UIGraphicsBeginImageContext(sizeOf_Screen);
CGContextRef current_Context = UIGraphicsGetCurrentContext();
[image drawInRect:CGRectMake(0, 0, sizeOf_Screen.width, sizeOf_Screen.height)];
CGContextSetLineCap(current_Context, kCGLineCapRound);
CGContextSetLineWidth(current_Context, 1.0);
CGContextSetRGBStrokeColor(current_Context, 1, 0, 0, 1);
CGContextBeginPath(current_Context);
CGContextMoveToPoint(current_Context, from_Point.x, from_Point.y);
CGContextAddLineToPoint(current_Context, to_Point.x, to_Point.y);
CGContextStrokePath(current_Context);
UIImage *rect = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return rect;
}
- (void)touchesBegan:(NSSet *)_touches withEvent:(UIEvent *)_event
{
// retrieve the touch point
UITouch *_touch = [_touches anyObject];
CGPoint current_Point = [_touch locationInView:self.imageView];
// Its record the touch points to use as input to our line smoothing algorithm
self.drawnPoints = [NSMutableArray arrayWithObject:[NSValue valueWithCGPoint:current_Point]];
self.previousPoint = current_Point;
// we need to save the unmodified image to replace the jagged polylines with the smooth polylines
self.cleanImage = self.imageView.image;
}
- (void)touchesMoved:(NSSet *)_touches withEvent:(UIEvent *)_event
{
UITouch *_touch = [_touches anyObject];
CGPoint current_Point = [_touch locationInView:self.imageView];
[self.drawnPoints addObject:[NSValue valueWithCGPoint:current_Point]];
self.imageView.image = [self drawLineFromPoint:self.previousPoint toPoint:current_Point image:self.imageView.image];
self.previousPoint = current_Point;
}
EDIT: With these settings I have accuracy in the UIImageView, but the image blurs inwards as I am drawing.
When I edit [image drawInRect:CGRectMake(0, 0, sizeOf_Screen.width, sizeOf_Screen.height)]; to be [image drawInRect:CGRectMake(0, self.imageView.frame.origin.y, sizeOf_Screen.width, sizeOf_Screen.height)]; and try to draw, the image flies off out of the view when I try to draw.
I've tried tweaking the sizeOf_screen value and CGRectMake of image in the drawLineFromPoint method. I've also attempted to set the locationInView in both instances to self.imageView, but to no avail. It's very strange. Any ideas or code samples that might accomplish what I'm looking for? I can't seem to find anything.
I am Displaying Image in Imageview1 . on touch i am able to get X,Y CO-Ordinates of touch point , Now i a want to show the image area around touch points in another imageview2 ? my reference is Snap seed Application Feature Selective Adjust Zoom on click of button point on imageView1.
i Think you want to show the section of first image to second image depends on Touch! you have to get touch location on first image,
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:image1];
Guess the image you want to show is this
UIImage *imageToCrop = [UIImage imageNamed:#"Abc.png"];
First Create Rect From point
CGRect cropRect = CGRectMake(point.x, point.y,point.x-20,point.y-20);
UIImage *cropImage = [self crop:imageToCrop Rect:cropRect];
image2.image = cropImage;
(*image2 is a ImageView);
Call this Function which return cropped image from given rect
-(UIImage*)crop:(UIImage *)Imagecrop Rect:(CGRect)rect {
CGImageRef imageRef = CGImageCreateWithImageInRect([Imagecrop CGImage], rect);
UIImage *result = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return result;
}
All This stuff you must have to do on Touch Events!
May this Help You!
you Should also look at This Project
I have a UIImageView on the screen. It displays an image with several colors. When I click on the image it crops a small portion of the image and set the cropped image to a new small UIImageView. For some reason the cropped image is always wrong. Check out the screenshot below:
Here is the complete code for touchesBegin:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location = [[touches anyObject] locationInView:self.imageView];
UIImage *originalImage = self.imageView.image;
NSLog(#"x = %f, y = %f",location.x,location.y);
CGRect cropRegion = CGRectMake(location.x, location.y, 10, 10);
CGImageRef subImage = CGImageCreateWithImageInRect(originalImage.CGImage, cropRegion);
UIImage *croppedImage = [UIImage imageWithCGImage:subImage scale:originalImage.scale orientation:originalImage.imageOrientation];
[self.previewImageView setImage:croppedImage];
CGImageRelease(subImage);
}
The most likely explanation is that the image size is larger than the view size, and so the image has been shrunk to fit the view. The result is that the view coordinates do not match the image coordinates, and hence the point returned by locationInView cannot be used directly for the CGImageCreateWithImageInRect.
To solve this problem you need to determine the x and y scale factors based on the self.imageView.bounds.size and the originalImage.size, and then scale the location accordingly.
I'm trying create an application that allows the user to move a frame over an image, so that I can apply some effects on a selected region.
I need to allow the user to precisely drag and scale the masked-frame on the image. I need this to be exact, just like any other photo app does.
My strategy is to get the touch points of the user, on a touch-moved event, and scale my frame accordingly. That was pretty intuitive. I coded the following stuff for handling the touch moved event :
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:[self view]];
float currX = touchPoint.x;
float currY = touchPoint.y;
/*proceed with other operations on currX and currY,
which is coming out quite well*/
}
But the only problem is, the coordinates of the currX and currY variables are not quite where they are supposed to be. There is a parallax error, which keeps shifting from device to device. I also think the x and y coordinates gets swapped in the case of an iPad.
Could you please help me to figure out how to get the exact touch coordinates?
My background image is in one view (imageBG) and the masked frame is in a separate one (maskBG). I have tried out :
CGPoint touchPoint = [touch locationInView:[maskBG view]];
and
CGPoint touchPoint = [touch locationInView:[imageBG view]];
...but the same problem persists. I have also noticed the error on touch being worse on an iPad than on an iPhone or iPod.
image.center = [[[event allTouches] anyObject] locationInView:self.view];
Hi your issue is the image and the iPhone screen are not necessarily in same aspect ratio.Your touch point might not translate correctly to your actual image.
- (UIImage*) getCroppedImage {
CGRect rect = self.movingView.frame;
CGPoint a;
a.x=rect.origin.x-self.imageView.frame.origin.x;
a.y=rect.origin.y-self.imageView.frame.origin.y;
a.x=a.x*(self.imageView.image.size.width/self.imageView.frame.size.width);
a.y=a.y*(self.imageView.image.size.height/self.imageView.frame.size.height);
rect.origin=a;
rect.size.width=rect.size.width*(self.imageView.image.size.width/self.imageView.frame.size.width);
rect.size.height=rect.size.height*(self.imageView.image.size.height/self.imageView.frame.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, self.imageView.image.size.width, self.imageView.image.size.height);
// clip to the bounds of the image context
// not strictly necessary as it will get clipped anyway?
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
// draw image
[self.imageView.image drawInRect:drawRect];
// grab image
UIImage* croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
This is what i did to crop my moving view is the rect which i pass for cropping see how its being translated to reflect correctly on image.Make sure the image view on which the user sees image is aspectfit content mode.
Note:- I make the rect of image view fit the aspectFit image
use this to do it
- (CGSize)makeSize:(CGSize)originalSize fitInSize:(CGSize)boxSize
{
widthScale = 0;
heightScale = 0;
widthScale = boxSize.width/originalSize.width;
heightScale = boxSize.height/originalSize.height;
float scale = MIN(widthScale, heightScale);
CGSize newSize = CGSizeMake(originalSize.width * scale, originalSize.height * scale);
return newSize;
}
have you tried these:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:selectedImageView];
float currX = (touchPoint.x)/selectedImageView.frame.size.width;
float currY = (touchPoint.y)/selectedImageView.frame.size.height;
/*proceed with other operations on currX and currY,
which is coming out quite well*/
}
or you can also use UIPanGestureRecognizer..
What I want to do is move my finger across the screen (touchesMoved) and draw evenly spaced images (perhaps CGImageRefs) along the points generated by the touchesMoved. I can draw lines, but what I want to generate is something that looks like this (for this example I am using an image of an arrow but it could be any image, could be a picture of my dog :) ) The main thing is to get the images evenly spaced when drawing with a finger on an iPhone or iPad.
First of all HUGE props go out to Kendall. So, based on his answer, here is the code to take a UIImage, draw it on screen along a path (not a real pathRef, just a logical path created by the points) based on the distance between the touches and then rotate the image correctly based on the VECTOR of the current and previous points. I hope you like it:
First you need to load an image to be used as a CGImage over and over again:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"arrow.png" ofType:nil];
UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
image = CGImageRetain(img.CGImage);
make sure in your dealloc that you call
CGImageRelease(image);
then in touchesBegan, just store the starting point in a var that is scoped outside the method (declare it in your header like this :) in this case I am drawing into a UIView
#interface myView : UIView {
CGPoint lastPoint;
}
#end
then in touches Began:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];
}
and finally in touchesMoved, draw the bitmap to the screen and then when your distance has moved enough (in my case 73, since my image is 73 pixels x 73 pixels) draw that image to the screen, save the new image and set lastPoint equal to currentPoint
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self];
double deltaX = lastPoint.x - currentPoint.x;
double deltaY = lastPoint.y - currentPoint.y;
double powX = pow(deltaX,2);
double powY = pow(deltaY,2);
double distance = sqrt(powX + powY);
if (distance >= 73){
lastPoint = currentPoint;
UIGraphicsBeginImageContext(self.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSaveGState(UIGraphicsGetCurrentContext());
float angle = atan2(deltaX, deltaY);
angle *= (M_PI / 180);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(currentPoint.x, currentPoint.y, 73, 73),[self CGImageRotatedByAngle:image angle:angle * -1]);
CGContextRestoreGState(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
distance = 0;
}
}
- (CGImageRef)CGImageRotatedByAngle:(CGImageRef)imgRef angle:(CGFloat)angle
{
CGFloat angleInRadians = angle * (M_PI / 180);
CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);
CGRect imgRect = CGRectMake(0, 0, width, height);
CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL,
rotatedRect.size.width,
rotatedRect.size.height,
8,
0,
colorSpace,
kCGImageAlphaPremultipliedFirst);
CGContextSetAllowsAntialiasing(bmContext, FALSE);
CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
CGColorSpaceRelease(colorSpace);
CGContextTranslateCTM(bmContext,
+(rotatedRect.size.width/2),
+(rotatedRect.size.height/2));
CGContextRotateCTM(bmContext, angleInRadians);
CGContextTranslateCTM(bmContext,
-(rotatedRect.size.width/2),
-(rotatedRect.size.height/2));
CGContextDrawImage(bmContext, CGRectMake(0, 0,
rotatedRect.size.width,
rotatedRect.size.height),
imgRef);
CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
CFRelease(bmContext);
[(id)rotatedImage autorelease];
return rotatedImage;
}
this will create an image that looks like this :
Going to add the following (with some changes to the above code in order to try and fill in the voids where touchesMoved is missing some points when you move fast:
CGPoint point1 = CGPointMake(100, 200);
CGPoint point2 = CGPointMake(300, 100);
double deltaX = point2.x - point1.x;
double deltaY = point2.y - point1.y;
double powX = pow(deltaX,2);
double powY = pow(deltaY,2);
double distance = sqrt(powX + powY);
distance = 0;
for (int j = 1; j * 73 < distance; j++ )
{
double x = (point1.x + ((deltaX / distance) * 73 * j));
double y = (point1.y + ((deltaY / distance) * 73 * j));
NSLog(#"My new point is x: %f y :%f", x, y);
}
Assuming that you already have code that tracks the user's touch as they move their touch around the screen, it sounds like you want to detect when they have moved a distance equal to the length of your image, at which time you want to draw another copy of your image under their touch.
To achieve this, I think you will need to:
calculate the length (width) of your image
implement code to draw copies of your image onto your view, rotated to any angle
each time the user's touch moves (e.g. in touchesMoved:):
calculate the delta of the touch each time it moves and generate the "length" of that delta (e.g. something like sqrt(dx^2 + dy^2))
accumulate the distance since the last image was drawn
if the distance has reached the length of your image, draw a copy of your image under the touch's current position, rotated appropriately (probably according to the vector from the position of the last image to the current position)
How does that sound?