- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个灰度图像像素矩阵,例如:
[ [0, 0, 125],
[10, 50, 255],
[90, 0, 255] ]
我的目标是对其应用色调 (UIColor
) 并从包含它的结构中导出 CGImage
/UIImage
。
public typealias Pixel = UInt8
extension UIColor {
var red: Float { return Float(CIColor(color: self).red * 255) }
var green: Float { return Float(CIColor(color: self).green * 255) }
var blue: Float { return Float(CIColor(color: self).blue * 255) }
var alpha: Float { return Float(CIColor(color: self).alpha * 255) }
}
public struct PixelData {
let r: UInt8
let g: UInt8
let b: UInt8
let a: UInt8
}
public struct Map {
let pixelCount: UInt
let pixels: [Pixel] //all pixels of an image, linear
let dimension: UInt //square root of pixel count
let tintColor: UIColor = UIColor(red: 9/255, green: 133/255, blue: 61/255, alpha: 1)
public var image: UIImage? {
var pixelsData = [PixelData]()
pixelsData.reserveCapacity(Int(pixelCount) * 3)
let alpha = UInt8(tintColor.alpha)
let redValue = tintColor.red
let greenValue = tintColor.green
let blueValue = tintColor.blue
let red: [PixelData] = pixels.map {
let redInt: UInt8 = UInt8((Float($0) / 255.0) * redValue)
return PixelData(r: redInt, g: 0, b: 0, a: alpha)
}
let green: [PixelData] = pixels.map {
let greenInt: UInt8 = UInt8((Float($0) / 255.0) * greenValue)
return PixelData(r: 0, g: greenInt, b: 0, a: alpha) }
let blue: [PixelData] = pixels.map {
let blueInt: UInt8 = UInt8((Float($0) / 255.0) * blueValue)
return PixelData(r: 0, g: 0, b: blueInt, a: alpha) }
pixelsData.append(contentsOf: red)
pixelsData.append(contentsOf: green)
pixelsData.append(contentsOf: blue)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
let bitsPerComponent = 8
let bitsPerPixel = 32
let dimension: Int = Int(self.dimension)
var data = pixelsData
guard let providerRef = CGDataProvider(
data: NSData(bytes: &data, length: data.count * MemoryLayout<PixelData>.size)
) else { return nil }
if let cgim = CGImage(
width: dimension,
height: dimension,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: dimension * MemoryLayout<PixelData>.size,
space: rgbColorSpace,
bitmapInfo: bitmapInfo,
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent
) {
return UIImage(cgImage: cgim)
}
return nil
}
}
问题是输出看起来乱码。我用过this tutorial和 this SO thread但没有成功。 Playground 上的结果是:
(输出在那里,只是勉强可见)
感谢任何帮助!
最佳答案
有两个关键问题。
代码计算每个灰度像素的所有红色值并为每个创建四字节 PixelData
(即使只填充红色 channel )并将其添加到 pixelsData
数组。然后它对绿色值重复该操作,然后对蓝色值重复该操作。结果是图像所需数据的三倍,而且只使用了红色 channel 数据。
相反,我们应该计算一次 RGBA 值,为每个值创建一个 PixelData
,然后逐个像素地重复这个过程。
premultipliedFirst
表示 ARGB。但是您的结构使用的是 RGBA,因此您需要 premultipliedLast
。
因此:
func generateTintedImage(completion: @escaping (UIImage?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
let image = self.tintedImage()
DispatchQueue.main.async {
completion(image)
}
}
}
private func tintedImage() -> UIImage? {
let tintRed = tintColor.red
let tintGreen = tintColor.green
let tintBlue = tintColor.blue
let tintAlpha = tintColor.alpha
let data = pixels.map { pixel -> PixelData in
let red = UInt8((Float(pixel) / 255) * tintRed)
let green = UInt8((Float(pixel) / 255) * tintGreen)
let blue = UInt8((Float(pixel) / 255) * tintBlue)
let alpha = UInt8(tintAlpha)
return PixelData(r: red, g: green, b: blue, a: alpha)
}.withUnsafeBytes { Data($0) }
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let bitsPerComponent = 8
let bitsPerPixel = 32
guard
let providerRef = CGDataProvider(data: data as CFData),
let cgImage = CGImage(width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: width * MemoryLayout<PixelData>.stride,
space: rgbColorSpace,
bitmapInfo: bitmapInfo,
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent)
else {
return nil
}
return UIImage(cgImage: cgImage)
}
我还重命名了一些变量,使用 stride
而不是 size
,将 dimension
替换为 width
和 height
这样我就可以处理非方形图像等。
我还建议不要对这种计算密集型的任何东西使用计算属性,所以我给了它一个异步方法,您可以按如下方式使用它:
let map = Map(with: image)
map.generateTintedImage { image in
self.tintedImageView.image = image
}
无论如何,上面的结果如下,其中最右边的图像是您的着色图像:
不用说,要将您的矩阵转换为您的像素
数组,您只需展平数组的数组即可:
let matrix: [[Pixel]] = [
[0, 0, 125],
[10, 50, 255],
[90, 0, 255]
]
pixels = matrix.flatMap { $0 }
这是一个并行化的再现,它在内存缓冲区方面也稍微更有效:
private func tintedImage() -> UIImage? {
let tintAlpha = tintColor.alpha
let tintRed = tintColor.red / 255
let tintGreen = tintColor.green / 255
let tintBlue = tintColor.blue / 255
let alpha = UInt8(tintAlpha)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
let bitsPerComponent = 8
let bytesPerRow = width * MemoryLayout<PixelData>.stride
guard
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo),
let data = context.data
else {
return nil
}
let buffer = data.bindMemory(to: PixelData.self, capacity: width * height)
DispatchQueue.concurrentPerform(iterations: height) { row in
let start = width * row
let end = start + width
for i in start ..< end {
let pixel = pixels[i]
let red = UInt8(Float(pixel) * tintRed)
let green = UInt8(Float(pixel) * tintGreen)
let blue = UInt8(Float(pixel) * tintBlue)
buffer[i] = PixelData(r: red, g: green, b: blue, a: alpha)
}
}
return context.makeImage()
.flatMap { UIImage(cgImage: $0) }
}
关于swift - 从灰度矩阵创建 CGImage/UIImage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56427766/
我正在尝试将 cgImage 从旧函数转换为新函数,但我不确定最后一个参数的参数应该是什么。基于旧函数的 param alphaType: 参数为 .alphaIsOne,新参数 param isOp
我尝试通过填写自己的数据来创建 UIImage。到目前为止一切正常。但是,如果我尝试多次调用此函数,它似乎会填满内存,直到应用程序崩溃。使用 VM Tracker,我发现当应用程序崩溃时,脏内存会增长
这是 Apple 的代码(来自技术问答 QA1702),用于从视频缓冲区获取 UIImage。不幸的是,返回的图像旋转了 90 度。如何编辑它以使返回的图像方向正确? - (UIImage *) im
使用标准图像格式(jpeg、gif、png 等)从文件加载 CGImage 或 NSImage 非常简单。 但是,我现在需要从使用 libfreetype 生成的内存中的字节数组创建 CGImage。
我正在使用 CIBloom 模糊 CGImage 中的一些文本,但发生的情况是 CIBloom 过滤器似乎使我的图像变得非常小 . 当滤波器内核变大时效果更差。我有点预料到这一点,但我需要一种方法来关
我有一个内存泄漏,我只是不知道如何解决。 这是泄露的代码: [newImg release]; CGColorSpaceRef d_colorSpace = CGColorSpaceCreateDev
在 iOS 4.0 及更高版本中,有没有一种方法可以在不将整个图像加载到内存的情况下对 CGImage 进行分割?我试图做的是*以编程方式*分割图像,以便在使用大图像的 CATiledLayer 应用
在我的应用中,我想生成一个视频的多个缩略图,最好是质量好的缩略图。我的旧方法是执行一个循环 15 次,并在不同的时间复制一个 CGImage。如下图 func generateThumbnails(_
一种方法是: CGImageRef scaledImage(CGImageref, destination rect) { context = CGBitmapContextCreate(re
我有一个 UIView 子类,它呈现应用了 mask 的图像。它在所有设备(仅限 iPad)上都能完美运行,除了那些具有宽色域显示屏(最新的 iPad Pro)的设备,在这些设备上, mask 呈现完
我正在为 mac 开发一个类似放大镜的应用程序。我的目标是能够在放大时精确定位单个像素。我在 mouseMoved(with event: NSEvent) 中使用此代码: let captureSi
我希望将一个 CGImage 覆盖在另一个之上。 作为示例,第一个 CGImage 为 1024x768,并且想要在给定位置覆盖第二个 100x100 CGImage。 我已经了解了如何使用 NSIm
所以我一直在开发一个小的“绘图”应用程序,用户可以在网格 Canvas 上绘制图像(基本上创建像素艺术)。我想创建一个导出此 Canvas 的函数(将其视为 UIColor 数组,然后将其转换为 Ra
有没有一种方法可以在 iOS 中将原始图像数据存储和加载到磁盘上,以节省解压时间和内存并减少应用程序的脏内存占用? 保罗·哈达德已hinting to something like this我知道这项
我有一个手绘 View (用户可以用手指画线)。我只使用几种颜色,所以我有一个我写的压缩算法(想通过本地网络将它发送到另一台 iPad)但我似乎无法准确地从图形上下文中获取数据,即使使用这个简单的测试
我正在尝试编写一段代码来判断 CGPoint 是否位于图像的黑色区域内(成功的答案是 here )。在我的实现中,如果使用此代码触摸点为黑色,我可以成功返回 NSLog: -(void)touches
我正在通过网络连接接收一系列图像,并希望尽快显示它们,最高可达 30 FPS。我派生了一个 UIView 对象(因此我可以覆盖 drawRect)并公开了一个名为 cameraImage 的 UIIm
我有以下代码: UIImage *img = [UIImage imageNamed:@"BRBlueCircleMask"]; CGImageRef activeCirleMaskImage = i
对于物理缩放任何 UIImage 的方法,我需要创建位图上下文,它具有与图像完全相同的设置,除了目标宽度和高度。 到目前为止,这是我的代码。缺少什么:如何为 CGBitmapContextCreate
我有一个图像,其 RGB 分量是全白的,具有不同的 alpha -- 例如,RGBA 格式的 0xFFFFFF09。但是,当我使用 UIImage 或 CGImage API 加载此图像,然后在 CG
我是一名优秀的程序员,十分优秀!