'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 |
