'Create Random Pixel Images in Swift
I want to create a random pixel generator in swift.
How would I be able to create something like the below codes in swift?
Java program to demonstrate creation of random pixel image
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class RandomImage
{
public static void main(String args[])throws IOException
{
// Image file dimensions
int width = 640, height = 320;
// Create buffered image object
BufferedImage img = null;
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// file object
File f = null;
// create random values pixel by pixel
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int a = (int)(Math.random()*256); //generating
int r = (int)(Math.random()*256); //values
int g = (int)(Math.random()*256); //less than
int b = (int)(Math.random()*256); //256
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
// write image
try
{
f = new File("G:\\Out.jpg");
ImageIO.write(img, "jpg", f);
}
catch(IOException e)
{
System.out.println("Error: " + e);
}
}
}
This is what I was only able to achieve. From the below code, you'll have know that i'm definitely a swift newbie.
import Cocoa
class ViewController: NSViewController {
let height=500
let width=500
for y in 0..<height {
for x in 0..<width {
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
}
}
}
Solution 1:[1]
You can use below func to create random UIImage
public struct PixelData {
var a: UInt8
var r: UInt8
var g: UInt8
var b: UInt8
}
func createRandomUIImage(width: Int, height: Int) -> UIImage? {
var pixels = [PixelData]()
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
let bitsPerComponent = 8
let bitsPerPixel = 32
for _ in 0..<width {
for _ in 0..<height {
pixels.append(PixelData(a: .random(in: 0...255), r: .random(in: 0...255), g: .random(in: 0...255), b: .random(in: 0...255)))
}
}
guard let providerRef = CGDataProvider(data: NSData(bytes: &pixels,
length: pixels.count * MemoryLayout<PixelData>.size)
)
else { return nil }
guard let cgim = CGImage(
width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: width * MemoryLayout<PixelData>.size,
space: rgbColorSpace,
bitmapInfo: bitmapInfo,
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent
)
else { return nil }
return UIImage(cgImage: cgim)
}
Solution 2:[2]
Here's a solution for macOS (based on this iOS solution) that creates an NSImage
:
public struct Pixel {
var a,r,g,b: UInt8
}
extension NSImage {
convenience init?(pixels: [Pixel], width: Int, height: Int) {
guard width > 0 && height > 0, pixels.count == width * height else { return nil }
var data = pixels
guard let providerRef = CGDataProvider(data: Data(bytes: &data, count: data.count * MemoryLayout<Pixel>.size) as CFData)
else { return nil }
guard let cgim = CGImage(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 32,
bytesPerRow: width * MemoryLayout<Pixel>.size,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue),
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent)
else { return nil }
self.init(cgImage: cgim, size: NSSize(width: width, height: height))
}
}
To use this initializer, create an array of Pixel
and then call NSImage
passing in the pixels
, width
, and height
. It returns an optional NSImage
which is nil
if anything went wrong creating the image.
Example Usage:
let height = 500
let width = 500
var pixels: [Pixel] = .init(repeating: .init(a: 0, r: 0, g: 0, b: 0), count: width * height)
for index in pixels.indices {
pixels[index].a = 255
pixels[index].r = .random(in: 0...255)
pixels[index].g = .random(in: 0...255)
pixels[index].b = .random(in: 0...255)
}
let image = NSImage(pixels: pixels, width: width, height: height)
Thanks to @LeoDabus for suggesting making the function a convenience initializer of NSImage
.
Solution 3:[3]
Here's a super-fast solution that uses Accelerate's BNNS and vImage libraries. You can generate a UIImage
or an NSImage
from a CGImage
.
import Accelerate
let cgImage = makeRandomImage(width: 1024,
height: 640)!
let nsImage = NSImage(cgImage: cgImage,
size: CGSize(width: cgImage.width,
height: cgImage.height))
func makeRandomImage(width: Int, height: Int) -> CGImage? {
let imageFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 8 * 3,
colorSpace: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue))!
let arrayDescriptor = BNNSNDArrayDescriptor.allocate(
randomIn: Pixel_8(0) ... 255,
shape: .matrixRowMajor(width * imageFormat.componentCount,
height))
let imageBuffer = vImage_Buffer(data: arrayDescriptor.data,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: width)
return try? imageBuffer.createCGImage(format: imageFormat)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Taha Metin Bayi |
Solution 2 | |
Solution 3 | Flex Monkey |