How to find back the real position on the image on iOS? - objective-c

Here is the view I got, I got a layer view, detect user touch, and a image view, which showing the image. The layer view is cover on top of the image view. The image view's image is aspect fit. So, it won't lost the ratio. If in my layer view touch on 100, 240, it is a layer view coordinate, but not the image's coordinate. I would like to know how to convert the layer view's coordinate to a image's coordinate. In this example, the image size may be 180*180, so, the coordinate in layer view in the image is 60, 90.
Thanks.

If I'm understanding this question correctly, you want to take a point, which is currently in relation to the layer's coordinate system, and convert it to the image view's coordinate system?
In that case, there are a couple of ways to do this.
Easiest is to use convertPoint:fromView: or convertPoint:toView:
CGPoint imageViewTouchPoint = [layerView convertPoint:touchPoint fromView:imageView];
CGPoint imageViewTouchPoint = [imageView convertPoint:touchPoint toView:layerView];
Either one should work.
EDIT - I realize now that this is only if the UIImageView has the same frame as the UIImage, which you said it might not, due to the UIViewContentModeScaleAspectFit property.
In this case, unless I'm mistaken, the image frame is calculated inside the UIImageView drawRect: method and isn't a property that gets set. This means you'll have to calculate this on your own.
Definitely get the imageViewTouchPoint from one of the methods above (just in case you want to use the same logic on a UIImageView which isn't the full screen size).
You will then need to calculate the scaled image frame. There are a couple of ways to do this. Some people go brute force and manually calculate based on which side of the image is longer, then determining which side should be scaled. Then they calculate the origin by by centering the image and subtracting the image and image view's sides and dividing by two.
I like to write as little code as possible if it's unnecessary, even if it means importing a framework. If you import AVFoundation you get a method AVMakeRectWithAspectRatioInsideRect which you can use to actually calculate the scaled rectangle in one line of code.
CGRect imageRect = AVMakeRectWithAspectRatioInsideRect(image.size, imageView.frame);
Whichever method you use, you will then simply translate your touched point with the scaled image origin:
CGPoint imageTouchPoint = CGPointMake(imageViewTouchPoint.x - imageRect.origin.x, imageViewTouchPoint.y - imageRect.origin.y);

You have to do the math yourself. Calculate the aspect ratio of your image and compare with the aspect ratio of the image view's bounds.
Look at this question: How to Get Image position in ImageView
After searching more, got a hack:
CGSize imageInViewSize = [photo resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:imageView.size interpolationQuality:kCGInterpolationNone].size;
CGRect overlayRect = CGRectMake((imageView.frame.size.width - imageInViewSize.width) / 2,
(imageView.frame.size.height - imageInViewSize.height) / 2,
imageInViewSize.width,
imageInViewSize.height);
NSLog(#"Frame of Image inside UIImageView: Left:%f Top:%f Width:%f Height:%f \n", overlayRect.origin.x, overlayRect.origin.y, overlayRect.size.width, overlayRect.size.height);

Related

Core Animation Bar

Currently I have an image... A battery Icon...
_MeterBar = [[UIImageView alloc] initWithFrame:CGRectMake(25, 40, 50, 40)];
_MeterBar.image = [UIImage imageNamed:#"battery-empty-icon.png"];
_MeterBar.backgroundColor = [UIColor clearColor];
I am attempting to add an animation that shows the battery loading to a specific point of the battery when a value is fetched from a web server.
Fetching the value is no problem but adding the animation is an issue. I basically copied and pasted some code a user answered before but I am stuck :/. When I add the animation, there is no image.....
CABasicAnimation *scaleToValue = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
scaleToValue.toValue = [NSNumber numberWithFloat:100.0f];
scaleToValue.fromValue = [NSNumber numberWithFloat:0];
scaleToValue.duration = 1.0f;
scaleToValue.delegate = self;
_MeterBar.layer.anchorPoint = CGPointMake(0.5, 1);
[_MeterBar.layer addAnimation:scaleToValue forKey:#"scaleRight"];
CGAffineTransform scaleTo = CGAffineTransformMakeScale(1.0f, 50.0f);
_MeterBar.transform = scaleTo;
[_PowerNowView addSubview:_MeterBar];
The battery icon is more wide than tall so I'm animating from 0 -> a percentage on the x axis.
If anyone has any hints, tips, or sample examples that does this exact animation, I would greatly appreciate your help :)
Thank you.
P.S. Heres the URL of the battery Icon i found : Battery Icon
Sorry for not being clear but I would like to have a color layer seperate of the battery icon...
I would like to create a bar over the battery image and have the bar dynamically animate with respect to the size of the battery.... not actually resize the battery image itself....
So there would be two layers, one for the battery that is mainly static in size and the other layer being the colored BAR, maybe a green color to represent the amount of the BATTERY image that is filled.
A good reference of what I would like to do is what the MINT application does, whose purpose is to record your bank statements.
The final animated battery above is very nice but I would just like to show a bar within the battery and animate it with respect to the pulled data value.
A couple of things.
Your scale of 100 would make your layer 100 times larger than normal. If it's 300 pixels on a side, a scale of 100 would display it as 30,000 pixels on a side.
You want your to scale value to 1.0, not 100.
Also, I'm not sure if scaling the transform multiplies the previous scale by a growing factor. If it does, then a starting scale value of 0 would prevent it from ever growing, since anything times zero is still zero. Try a from value of .0001 instead of 0.0,
If you want your battery image to grow from left to right, wouldn't you want your anchor point to be (0,.5) rather than (.5, 1)?
And, when you change the anchor point, it not only changes the center for transforms, but it moves the position of the image. You will need to adjust the position to compensate. I always have to scratch my head and think about it really hard (and usually get it wrong anyway) but I think you would want to shift the X position of your view to the right by half of it's width.
Note that scaling your image will cause it to stretch oddly. It will start out short and fat and stretch out to normal size.
It might be better to attach a CAShapeLayer to the view as a mask layer, and animate the shape layer's path from an empty rectangle (Width = 0, height = full height of view) to a rectangle that is the full size of the view. That would cause the view to animate in a "wipe" animation where it is revealed from left to right without stretching.

Change NSImage Origin

Is it possible to change the origin of an NSImage? If so how would I go about doing this. I have coordinates in regular cartesian system some of them with negative values and I am trying to draw them at the corresponding point in the NSImage but since the origin is at (0,0) there are some missing.
EDIT:Say I have an drawing aspect that needs to be done to an image at the point (-10,-10), currently this doesn't show up. Is there a way to fix that?
If it's like in iOS (you may have to adapt a little the code) and if my memory is still good, you have to do this, since origin is readOnly:
CGRect myFrame = yourImage.frame;
myFrame.origin.x=newX; myFrame.origin.y=newY;
yourImage.frame = myFrame;
I think you are confusing an NSImage with it's container. An NSImage has no bounds or frame, and thus no origin. It does have a size which may represent the pixel dimensions of its birtmap representation ( if it has one) or otherwise could represent it's bounding box ( if it is a vector image). Drawing in an image at a pixel location of (-10,-10) doesn't really make sense.
An NSImage is displayed in a container ( typically an NSImageView), and the container's bounds.origin will dictate the placement of the image relative to the imageView, but you can't modify pixels beyond the edge of the bitmap plane.
In any case you probably want to be using a subclassed NSView in which you would override the drawRect method for your custom drawing. NSView does have a bounds.origin but this is not relevant to your in-drawing coordinates, but rather to the position of the drawn content as a whole to the view's bounding box. The coordinate system that you will be drawing into will be referenced to your graphics context which will (usually) pin the origin (0,0) to the bottom left corner (OSX) or top left corner (iOS). If you are trying to represent negative points on a Cartesian plane, you will need to apply a translation transform to map your points into this positive coordinate space.
I'm trying to explain in a few words, badly, something which Apple explains in great detail in their Quartz 2D Programming Guide.

How do I override the Points to Pixels iOS specificity and have my image drawn at the right size?

I have a 64px by 64px redSquare.png file at a 326ppi resolution. I'm drawing it at the top left corner of my View Controller's window as follows:
myImage = [UIImage imageNamed:#"redSquare.png"];
myImageView = [[UIImageView alloc] initWithImage:myImage];
[self.view addSubview:myImageView];
Given that the iPhone 4S has a screen resolution of 960x640 (326ppi) there should be enough room for 9 more squares to fit next to the first one. However there's only room for 4 more. i.e. the square is drawn larger than what it should given my measurements.
// even tried resizing UIImageView in case it was
// resizing my image to a different size, by adding
// this next line, but no success there either :
myImageView.frame = CGRectMake(0, 0, 64, 64);
I believe it has to do with the way the device is "translating" my pixels. I read about the distinction between Points Versus Pixels in Apple's documentation but it doesn't mention how one can work around this problem. I know I'm measuring in pixels. Should I be measuring in points? And how could I do that? How exactly am I to resize my image so that it can hold 9 more same-sized squares next to it (i.e. on the same horizontal..) ?
Thank you
To display an image at full resolution on a Retina display, it needs to have #2x appended to the end of its name. In practice, this means you should save the image you're currently using as redSquare#2x.png and a version of that image in 32x32 pixels as redSquare.png.
Once you have done this, there is no need to change your code. The appropriate image will be displayed depending on the device's capabilities. This will allow your app to render correctly on both Retina and non-Retina devices.

Rotate image to point

I have the following:
CGPoint pos //center of an image
CGPoint target //a point, somewhere in the coordinate system
float rotation //the current rotation of the image to the x-axis, clockwise, so "right" would be 90°
Now I want the image to rotate around it's centerpoint (pos) so that it looks directly towards the targetpoint.
My idea was: Calculate the angle corresponding to the x-axis, subtract rotation, and then rotate it.
Two things:
1.) I fail at calculating the angle. (Yes, I know it's all in rad...)
2.) What's best for rotating?
CGAffineTransform? But then I'd need an imageView
Or: save context, set origin to center of image, rotate context, draw image, restore context? More complicated, but no imageview neeeded...
Draw it on a CALayer, and move the layer around anyway you like.

Complex CATransition

I am trying to create a CATransition to a UIView.
I want to move the UIView to the right, and at the same time (and always on the same point), rotate it.
It is better explained by the image.
I am able to move it with a CATransition, and also to rotate it with a CABasicAnimation, but I don't know how to do those together.
Thanks.
-(void)scaleAndRotate:(UIImageView*)myView andAngle:(float)angle {
CGAffineTransform scaleTrans = CGAffineTransformMakeScale(1.5,1.5);
CGAffineTransform rotateTrans =CGAffineTransformMakeRotation(angle * M_PI / 180);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
myView.transform = CGAffineTransformConcat(scaleTrans, rotateTrans);
[UIView commitAnimations];
}
In the above method : replace & with what u want ...
It'll work ,,, surely :)
All the best
You should consider making two copies of the image, rotating one, and masking them both so that they can be placed next to each other in the L shape.
Using this technique, you'll be doing two translations at once (moving the mask and the underlying image) to both images A and T. But, notice that rotation will not be animated. You'll put image T into the rotated state immediately and just reveal it by moving it under the mask (while simultaneously doing the opposite on image A to hide it). So you're not actually combining translation and rotation into one animation, but rather using just translation with a mask on both the original image (A) and a rotated copy (T).
You'll need to mask the left side of one and the right side of the other. The shape of the mask should have an opposite 45 degree angle on both, then you can bring those angled edges together to form the L. As time progress, you just move the mask in each until the first image is totally gone and you're left with your end state.
The masking part is the hard part. See this answer on masking a UIImage with CoreGraphics: masking a UIImage
The mask PNG would basically just be a rectangle with one side at a 45 degree angle. You could create that in the image editor of your choice (Photoshop, GIMP, Acorn).
Note: this approach will create a sharp edge at the corner. The other approach would be to warp the pixels around that corner as they move from the vertical downward motion to the horizontal rightward motion. (I think) This would be much more involved.