My objective is to map a character to a n x n grid - like an LED matrix. My current approach is to:
//1
func textToImage() -> UIImage? {
let text = "A"
let attributes = [
NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 10)
]
let textSize = text.size(withAttributes: attributes)
UIGraphicsBeginImageContextWithOptions(textSize, false, 0)
text.draw(at: CGPoint.zero, withAttributes: attributes)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
//2
func imageToMapping(_ inputImage: UIImage) -> [[UIColor]] {
guard let cgImage = inputImage.cgImage,
let data = cgImage.dataProvider?.data,
let pixelPointer = CFDataGetBytePtr(data) else {
fatalError("Couldn't access image data")
}
let bytesPerPixel = cgImage.bitsPerPixel / cgImage.bitsPerComponent
let byteCount = CFDataGetLength(data)
/*
let matrix = Pixel.createPixelMatrix(cgImage.width, cgImage.height)
return matrix.compactMap { yPixels in
return yPixels.compactMap { xPixels in
return xPixels.colorByPixel(pixelPointer)
}
}
*/
// update with for loops
let matrix = Pixel.createPixelMatrix(Int(cgImage.width), Int(cgImage.height))
var ledGrid = [[UIColor?]](repeating: [UIColor?](repeating: nil, count: 36), count: 21)
for (indexY, yPixels) in matrix.enumerated() {
for (indexX, xPixels) in yPixels.enumerated() {
ledGrid[indexY][indexX] = xPixels.colorByPixel(pixelPointer)
}
}
}
//3
func ledMap(colorMap: [[UIColor]], imageWidth: Int, imageHeight: Int) {
let yIndex = colorMap.count
let xIndex = colorMap[0].count
// cgImage size 177 36
let ledHeight = Int(view.frame.height) / imageHeight
let ledWidth = ledHeight
var y = 0
var x = 0
while y < colorMap.count {
while x < colorMap[y].count {
let led = UIView()
led.frame = CGRect(origin: CGPoint(x: 11 * x, y: 11 * y), size: CGSize(width: 11, height: 11))
led.backgroundColor = colorMap[y][x]
view.addSubview(led)
x = x + 1
}
x = 0
y = y + 1
}
}
struct Pixel {
/** The number of bytes a pixel occupies. 1 byte per channel (RGBA). */
static let bytesPerPixel = 4
fileprivate let offset: Int
fileprivate init(_ offset: Int) { self.offset = offset }
static func createPixelMatrix(_ width: Int, _ height: Int) -> [[Pixel]]
{
return (0..<height).map { row in
(0..<width).map { col in
let offset = (width * row + col) * Pixel.bytesPerPixel
return Pixel(offset)
}
}
}
}
Here you can see the output of the grid and not the left-center the actual UIImage of the string
As you can see it's not the result I'm look for. The output of the grid should map to the letter A. Any advice?
Updated with for loops however simulator still brings the same result
The solution was that the offset was incorrect, the following code will replace the colorByPixel method.
for (indexY, yPixels) in matrix.enumerated() {
for (indexX, xPixels) in yPixels.enumerated() {
let offset = (indexY * cgImage.bytesPerRow) + (indexX * bytesPerPixel)
let components = (r: pixelPointer[offset], g: pixelPointer[offset + 1], b: pixelPointer[offset + 2])
ledGrid[indexY][indexX] = UIColor(red: CGFloat(components.r/255), green: CGFloat(components.g), blue: CGFloat(components.b), alpha: 1.0)
ledGrid[indexY][indexX] = xPixels.colorByPixel(pixelPointer)
}
}
The colour isn't perfect but the shape is definitely there.