objective-c determine image resolution - objective-c

For some reason I could not figure it out.
UIImage *image = //initialize with some image, etc.
Is there a way to get the resolution of image?

Do you mean the width/height?
CGFloat width = image.size.width
CGFloat height = image.size.height

To find the dimensions of the image, you can use the size property on a UIImage. The DPI (resolution/scale) can be found through the scale attribute. Here is a reference from Apple's documentation:
The scale factor of the image. (read-only)
#property (nonatomic,readonly) CGFloat scale
Discussion
If you load an image from a file whose name includes the #2x modifier, the scale is set to 2.0. If the filename does not include the modifier but is in the PNG or JPEG format and has an associated DPI value, a corresponding scale factor is computed and reflected in this property. You can also specify an explicit scale factor when initializing an image from a Core Graphics image. All other images are assumed to have a scale factor of 1.0.
If you multiply the logical size of the image (stored in the size property) by the value in this property, you get the dimensions of the image in pixels.
For normal images, the scale will be 1.0. For JPG/PNG images, the scale may be different. Also, if your image name has '#2x' before the extension, UIImage assumes that its scale is 2.0.

Related

UIImage resizing - how scaleFactor value derived is unclear

This is possibly a dumb question, but I'm not seeing how the math works here. I have an image, 414w x 584h. To get an image scaled down to half this size (i.e., half the initial width and height), using [UIImage imageWithCGImage:scaleFactor:orientation], I have to set scaleFactor to 6.0.
Why is it 6.0? How does this value relate to say, a width scale of 414/207 = 2.0, or a height scale, same value, 584/292 = 2.0?
As I write this, I'm wondering... my app is running on an iPhone 6+. So could it have something to do with the 3x Retina display? I.e., normal scale factor of 2.0, which is dimensionless, but when applied to images on the 6+, to get to pixels, I have to do 3x this? Is this the logic?
And, I guess, while I'm here, is there a better way to resize an image, using available iOS facilities? E.g., some special affine transform, etc.? No particular concerns around memory or performance; the images are all no more than 1000 wide by 1500 or so high.
Thanks a lot!
You can find a grt tutorial at http://nshipster.com/image-resizing/
The Documentation says:
The scale factor to use when interpreting the image data. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property.
For Scale:
If you load an image from a file whose name includes the #2x modifier,
the scale is set to 2.0. You can also specify an explicit scale factor
when initializing an image from a Core Graphics image. All other
images are assumed to have a scale factor of 1.0.
If you multiply the logical size of the image (stored in the size
property) by the value in this property, you get the dimensions of the
image in pixels.
For size:
In iOS 4.0 and later, this value reflects the logical size of the
image and is measured in points. In iOS 3.x and earlier, this value
always reflects the dimensions of the image measured in pixels

How to find back the real position on the image on iOS?

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

How do I control the size of a UIViews background pattern colour?

I have set a patterned background on my UIView using:
myView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"backgroundImage.png"]];
But the image appears to be stretched or scaled up and doesn't appear at the desired resolution. Is there a way to set the size or scale of a background pattern? Or is the images size used as a default. Does the image DPI have an affect?
The pattern is constructed by tiling the image until it fills the given area.
So there is no control on tile size other than the original image dimensions.
Now, if you want to provide retina images you should just have a #2x version and iOS will take care of that automatically (btw change the method call to [UIImage imageNamed:#"backgroundImage"] - the file extension is optional for png images).
Do not provide higher dpi images for retina, instead provide an image that is twice the size of the non-retina one (and obviously not by oversampling the image).
Finally the only control you seem to have on the pattern (at least the only one that is documented) is the phase. Here is the relevant part from the official documentation:
By default, the phase of the returned color is 0, which causes the top-left corner of the image to be aligned with the drawing origin. To change the phase, make the color the current color and then use the CGContextSetPatternPhase function to change the phase.
Turns out I wasn't using the #2x naming convention so images were appearing stretched. I added it in and it fixed everything.

Scaling an image from the iPhone - iOS App

I let the user select a photo from the iPhone library, and I grab the UIImage.
I output the size of the image, and it says 320x480, but it doesn't seem to be, because when I draw the image on the screen using CGRectMake(0,0,320,480), it only shows the upper left portion of the image. Aren't the images much bigger than 320x480 because of the high resolution?
I'd like to scale the image to force it to be 320x480. If it is less than 320x480, it should not be rescaled at all. If the width is greater than 320 or the height is greater than 480, it should scale in a way so that it becomes as close to 320x480 as possible, but by keeping the proper proportion of width to height. So, for instance, if it scales to 320x420, that is fine, or 280x480.
How can I do this in Objective-C?
Setting the image view's content mode like this:
myView.contentMode = UIViewContentModeScaleAspectFit;
will preserve the aspect ratio.

Posterization effect when using CGContextDrawImage, float CGBitmapContext

To retrieve pixel values from CGImage I use CGContextDrawImage (like described here:
How to get pixel data from a UIImage (Cocoa Touch) or CGImage (Core Graphics)?). The only difference is that I create 128 bpp float components context, not usual 32 bpp context. The source CGImage obtained from CGImageSource created with option kCGImageSourceShouldAllowFloat. That way I hoped to get access to float pixel values color matched with my bitmap context's color space and use them in further image processing. The problem is that resulting image data seems to be loosing dynamic range. It can be seen in shadow, plain blue sky areas. They become contoured and lacking detail. Some investigation showed the problem occurs in CGContextDrawImage (Source CGImage contains full dynamic range, saving it through CGImageDestination proves it) and after CGContextDrawImage context contents become posterized.
After some more investigation I found this:
http://lists.apple.com/archives/quartz-dev/2007/mar/msg00026.html
That led me to conclusion that problem is not in my code but in core graphics or that is intended behaviour.
My question is: what is correct way to obtain floating point data from image using core graphics?
After some more investigation the problem is narrowed down to the following: posterization occurs when 8 bit image is drawn to the 128 bpp float context created with linear color space (kCGColorSpaceGenericRGBLinear). If I draw the same image to context created with kCGColorSpaceGenericRGB then retrieve CGImage from that context and draw that second image to linear color space context everything is ok.
Other solution (workaround ?) is to use Core Image: create CIImage from source CGImage and draw it to CIContext created with corresponding kCGColorSpaceGenericRGBLinear CGContext. But that only option on OS X (not on iOS).