'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