Finding RGB values at position inside UIImageView after scaling

I have a png image, dimensions 1214x1214 (and double that for retina) on the iPad and have it set up as a UIImageView located at screen co-ordinates (0,-20). In order that it fits the screen during a device rotation/orientation change I've set it to be of type Aspect Fit.

What I'd like to do is to be able to touch the screen and read off the RGB values of the pixel beneath my touch. I've implemented a UIGestureRecognizer and tied it to the UIImage and am getting touch co-ordinates back successfully.

What's giving me trouble is that I've tried implementing several of the ways of retrieving RGB values (for example [How to get the RGB values for a pixel on an image on the iphone])1 but my RGB values seem as if the image is skewed and mapped in a different place on the UIView.

My question is that, how can I cater for the fact that I've set the UIImageView to be Aspect Fit and the fact that the device may be in either landscape or portrait (upside down or rightway up) ?

Answers


Ok, so I worked it out, this may be helpful to someone who's trying to do something similar.

I calculated the scaled size of the Image using this function from another answer

-(CGRect)frameForImage:(UIImage*)image inImageViewAspectFit:(UIImageView*)imageView
{
    float imageRatio = image.size.width / image.size.height;

    float viewRatio = imageView.frame.size.width / imageView.frame.size.height;

    if(imageRatio < viewRatio)
    {
        float scale = imageView.frame.size.height / image.size.height;

        float width = scale * image.size.width;

        float topLeftX = (imageView.frame.size.width - width) * 0.5;

        return CGRectMake(topLeftX, 0, width, imageView.frame.size.height);
    }
    else
    {
        float scale = imageView.frame.size.width / image.size.width;

        float height = scale * image.size.height;

        float topLeftY = (imageView.frame.size.height - height) * 0.5;

        return CGRectMake(0, topLeftY, imageView.frame.size.width, height);
    }
}

took the touch points from registering a function as a listener

CGPoint tapPoint = [sender locationInView:imageMap];

altered the touch points based on where my image was moved to by rotation of the iPad

if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ||
   [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown )
  {
  // portrait (y has increased, x has stayed the same)
  tapPoint.y -= rectScaleSize.origin.y;
  }
else  
  {
  // landscape (x has increased, y has stayed the same)
  tapPoint.x -= rectScaleSize.origin.x;
  }

Then rescaled based upon the original size of the image and its Aspect Fit size

tapPoint.x = (tapPoint.x * imageMap.image.size.width) / rectScaleSize.size.width;
tapPoint.y = (tapPoint.y * imageMap.image.size.height) / rectScaleSize.size.height;

where imageMap.image was my original image and rectScaleSize was the return from the frameForImage function

and, finally got the RGB values

CGImageRef image  = [imageMap.image CGImage];
NSUInteger width  = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
// NSLog(@"RGB Image is %d x %d",width,height);

CGColorSpaceRef colorSpace  = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData      = malloc(height * width * 4);
NSUInteger bytesPerPixel    = 4;
NSUInteger bytesPerRow      = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;

CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height),image);
CGContextRelease(context);

int byteIndex = (bytesPerRow * (int)tapPoint.y) + (int)tapPoint.x * bytesPerPixel;
int red = rawData[byteIndex];
int green = rawData[byteIndex + 1];
int blue = rawData[byteIndex + 2];
//int alpha = rawData[byteIndex + 3];

NSLog(@"RGB is %d,%d,%d",red,green,blue);

Seems to work just fine, hope it comes in useful. Comments welcome if I did something terribly wrong!


Need Your Help

GridBagLayout elements not moving

java swing layout layout-manager gridbaglayout

I'm trying to move my buttons and label. I want the buttons down in the bottom right corner and the label right above them, but no matter how I change the layout system, they're all stuck on the same

How to Detect Right Click on the Taskbar

c# .net winforms taskbar right-click

I've got a Windows Forms application in C# that starts off with a loading dialog. As expected, a button for the app shows up in the Windows taskbar.