I am using CAGradientLayer to add a gradient to my UIView. I am setting the gradient ad a solid red colourful testing, and when I check the color that is being displayed, it is showing different RGB values to those I have specified. Is there a way that I can make sure the gradient is showing the colours that I set.
let gradientLayer2 = CAGradientLayer()
gradientLayer2.frame.size = colourPickerView.frame.size
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
]
gradientLayer2.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer2.endPoint = CGPoint(x: 1, y: 0)
gradientLayer2.cornerRadius = 20
colourPickerView.layer.insertSublayer(gradientLayer2, at: 0)
This shows the red color as: <CGColor 0x283c8e400> [<CGColorSpace 0x283c989c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0.14902 0 1 )
(Please note, it is showing the green value as ‘0.14902’)
When I add a solid background colour to the layer, instead of a gradient, it does show the correct RGB values.
let layer = CALayer()
layer.frame.size = colourPickerView.frame.size
layer.backgroundColor = UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
colourPickerView.layer.insertSublayer(layer, at: 0)
Here is the code that I am using to get the colour of a certain pixel:
extension UIView {
func colorOfPointView(point: CGPoint) -> UIColor {
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
var pixelData: [UInt8] = [0, 0, 0, 0]
let context = CGContext(data: &pixelData, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context!.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context!)
let red: CGFloat = CGFloat(pixelData[0]) / CGFloat(255.0)
let green: CGFloat = CGFloat(pixelData[1]) / CGFloat(255.0)
let blue: CGFloat = CGFloat(pixelData[2]) / CGFloat(255.0)
let alpha: CGFloat = CGFloat(pixelData[3]) / CGFloat(255.0)
let color: UIColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
return color
}
2
Answers
that’s odd! Is this the only code that involves with this part of code? I just tested and got true result :
Copy and paste this code in a new Xcode project and check if you still get the wrong result.
The issue you are running into is the difference between
RGBA
andDisplay P3
orExtended sRGBA
.Using your approach with
CGContext
and aCAGradientLayer
, for example, we get back the Display P3 values.To get the "traditional" 8-bits-per-component values, we can first render the view to a
UIImage
and then get the RGBA values from a point in the image.Using these two extensions:
We can call:
and we’ll get back what we were expecting.
Because of the need to "capture as
UIImage
" we don’t want to be calling that over and over – such as if we’re dragging along a gradient to get the current color… Instead, if possible, we’d want to render the view to aUIImage
once and then repeatedly callprerenderedImage.getPixelColor(point: pt)
.Here’s a quick example…
It will look like this when running:
We have 2
CAGradientLayer
views… the first one usingRed -> secondColor
and the second one usingsecondColor -> secondColor
(so it appear solid).The 3rd view has a "left-half"
CALayer
and a "right-half"CALayer
and the 4th view is a plainUIView
with the.backgroundColor
set.The button cycles through Red, Green, Blue, Yellow as the second-colors.
When we touch / drag the dashed-line, we’ll get the RGBA values from the same x-coordinate on each view (at center-y) and show the results in the label below the button.
Use the above extensions with this code…
View Controller
UIView subclasses