Reputation: 396
I've tried to build reading RGB pixel data in Swift. Getting the basic Image Information is no problem, but I think I've got something wrong with the pointer and the byte-offset:
let provider:CGDataProviderRef = CGImageGetDataProvider(inImage)
let data:NSData = CGDataProviderCopyData(provider)
let bytes: COpaquePointer = data.bytes // Needs to be changed to ConstUnsafePointer<()> in xCode beta3
let bytePointer = UnsafePointer<UInt8>(bytes)
println("Pixel Data:\n")
var printString:String = ""
for var row:Int = 0; row < Int(height); row++ {
for var col:Int = 0; col < Int(width); col++ {
var pixel:UInt8 = bytePointer[row * Int(bytesPerRow) + col * Int(bytesPerPixel)]
printString += "("
for var x = 0; x < Int(bitsPerPixel); x++ {
printString += pixel[x]
}
printString += ")"
if col < Int(width) - 1 {
printString += ","
}
}
printString += "\n"
}
println(printString)
(I cast Int to the variables bytesPerRow, etc because they are UInt8)
I got a 4x2px Image wich contains two rows of following pixels: Red, Green, Blue, White. So I expect this output (There is no alpha):
(ff0000), (00ff00), (0000ff), (ffffff)
(ff0000), (00ff00), (0000ff), (ffffff)
I get a error when compiling at printString += pixel[x]
'UInt8' does not have a member named 'subscript'
I thought it could just be appended to a string in swift. I've tried to convert it to a string but this won't work either. So maybe I'm doing something wrong with the pointers.
How do i get a proper output?
edit:
@David got me on a right track I think. But after the first 8 Byte weird thing happen. Might this be padding byted @heinrich-giesen suggested?
My raw image data for 3 tests looks like this:
Pic1: 3Byte/Pixel, no Alpha, 4 pixelWidth, 2 pixelHeight, [red, green, blue white; red, green, blue white]
Raw Data: <ff000000 ff000000 ffffffff ff000000 ff000000 ffffffff>
Pic2: 4Byte/Pixel, Alpha, 4 pixelWidth, 2 pixelHeight, [red, green, blue white (alpha); red, green, blue white]
Raw Data: <ff000000 00ff0000 0000ff00 ffffff00 ff0000ff 00ff00ff 0000ffff ffffffff>
If you look at the raw data its pretty clear that I expect a output like:
Pic1
(ff,00,00), (00,ff,00), (00,00,ff), (ff,ff,ff)
(ff,00,00), (00,ff,00), (00,00,ff), (ff,ff,ff)
Pic2
(ff,00,00,00), (00,ff,00,00), (00,00,ff,00), (ff,ff,ff,00)
(ff,00,00,ff), (00,ff,00,ff), (00,00,ff,ff), (ff,ff,ff,ff)
But the real output my code generates is this:
Pic1
((ff, 00, 00, ), (00, 00, ff, ), (00, ff, ff, ), (ff, ff, 00, ))
((ff, 00, 00, ), (00, 00, ff, ), (00, ff, 00, ), (ff, 00, 00, ))
Pic2
((ff, 00, 00, ff, ), (00, 00, ff, ff, ), (00, ff, ff, 00, ), (ff, ff, 00, 00, ))
((ff, 00, 00, ff, ), (00, 00, ff, 00, ), (00, ff, 00, 00, ), (ff, 00, 00, 00, ))
The code to build the output is this now:
for var row:Int = 0; row < Int(height) ; row++ {
printString += "("
for var col:Int = 0; col < Int(width); col++ {
printString += "("
for var x = 0; x < Int(bytesPerPixel); x++ {
var pixel:UInt8 = bytePointer[row * Int(bytesPerRow) + col * Int(bytesPerPixel) + x * Int(bytesPerPixel)]
printString += NSString(format:"%02x, ", pixel)
}
printString += ")"
if col < Int(width) - 1 {
printString += ", "
}
}
printString += ")\n"
}
println(printString)
So is there a padding (Like the space in the output of the raw data)? I've tried to skip one and two after the initial 8 but this won't yield less confusing outputs. Something breaks after 8 Bytes. Suggestions?
Upvotes: 2
Views: 2204
Reputation: 521
Your code looks a bit strange. Are you sure the line:
for var x = 0; x < Int(bitsPerPixel); x++ {
is correct? Did you really mean bitsPerPixel
and not bytesPerPixel
? (or samplesPerPixel or whatever it is in swift). And are you sure a component (a sample) has 8 bits? And a pixel has no padding bytes?
Another point: what are height
and width
? Are they the components of the size
of an image? that is wrong. You have to use pixelsWide
and pixelsHigh
. The size
of an image says only how great --expressed in inch or centimeter or (1/72)of an inch (called a point)-- an image shall be depicted. That is independent of the number of pixels. But you work on pixels!
Upvotes: 1
Reputation: 41246
Change bytePointer to UnsafePointer<UInt32>
and update the loop to access the individual bytes of the word using shift (>>) and mask (& 0xff).
var pixel:UInt32 = bytePointer[row * Int(bytesPerRow) + col * Int(bytesPerPixel)]
printString += NSString(withFormat:"(%08x)", pixel)
That'll give you the alpha channel as well, but you get the drift.
Upvotes: 0