-
Notifications
You must be signed in to change notification settings - Fork 18
[Sad Trombone] Image pixel data access #57
base: master
Are you sure you want to change the base?
Changes from 1 commit
f19f22b
f7911f3
af7c2a7
47f0183
d641ae5
7a9e403
964c459
c0a5541
ea36d2d
355256c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,4 +34,108 @@ public struct Image { | |
init(_ image: UIImage) { | ||
uiImage = image | ||
} | ||
|
||
public func toPixels() -> PixelBitmap { | ||
return PixelBitmap(image: self) | ||
} | ||
} | ||
|
||
public struct PixelBitmap : MutableCollectionType { | ||
typealias Index = Int | ||
|
||
init(image: Image) { | ||
width = Int(image.size.width) | ||
height = Int(image.size.height) | ||
|
||
data = UnsafeMutablePointer<Pixel>.alloc(width*height) | ||
|
||
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB() | ||
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue) | ||
let bytesPerRow = width * 4 | ||
|
||
let context = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, colorSpace, bitmapInfo) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This context is leaking :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right you are, @NachoSoto, thanks! I added a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh you're right, I was thinking of |
||
|
||
CGContextDrawImage(context, CGRect(origin: CGPointZero, size: image.uiImage.size), image.uiImage.CGImage) | ||
} | ||
|
||
var data: UnsafeMutablePointer<Pixel> | ||
let width: Int | ||
let height: Int | ||
|
||
public let startIndex: Int = 0 | ||
|
||
public var endIndex: Int { return height * width } | ||
|
||
public subscript (position: Int) -> Pixel { | ||
get { return data[position] } | ||
set { data[position] = newValue } | ||
} | ||
|
||
public func pixelAt(row: Int, column: Int) -> Pixel { | ||
let idx = row * width + column | ||
return self[idx] | ||
} | ||
|
||
public func generate() -> IndexingGenerator<PixelBitmap> { | ||
return IndexingGenerator(self) | ||
} | ||
|
||
public func toImage() -> Image { | ||
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB() | ||
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue) | ||
let context = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, bitmapInfo) | ||
let cgImage = CGBitmapContextCreateImage(context) | ||
|
||
return Image(UIImage(CGImage: cgImage)!) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto note about scale here. |
||
} | ||
|
||
public func transform(transform: Pixel -> Pixel) -> PixelBitmap { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we call these |
||
var newBitmap = self | ||
for idx in startIndex..<endIndex { | ||
newBitmap[idx] = transform(self[idx]) | ||
} | ||
|
||
return newBitmap | ||
} | ||
|
||
public func transform(transform: (position: Int, Pixel) -> Pixel) -> PixelBitmap { | ||
var newBitmap = self | ||
for idx in startIndex..<endIndex { | ||
newBitmap[idx] = transform(position: idx, self[idx]) | ||
} | ||
|
||
return newBitmap | ||
} | ||
|
||
public func transform(transform: (row: Int, column: Int, Pixel) -> Pixel) -> PixelBitmap { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the multiple API endpoints here. |
||
var newBitmap = self | ||
for idx in startIndex..<endIndex { | ||
let row = idx % width | ||
let column = idx - (row * width) | ||
newBitmap[idx] = transform(row: row, column:column, self[idx]) | ||
} | ||
|
||
return newBitmap | ||
} | ||
} | ||
|
||
|
||
/** A representation of a single pixel in an RGBA bitmap image. */ | ||
public struct Pixel { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To hide the |
||
public var red: UInt8 | ||
public var green: UInt8 | ||
public var blue: UInt8 | ||
public var alpha: UInt8 | ||
|
||
public var color: Color { | ||
get { return Color(red: Double(red/255), green: Double(green/255), blue: Double(blue/255), alpha: Double(alpha/255)) } | ||
set { | ||
let (r, g, b, a) = newValue.getRGBAValues() | ||
self.red = UInt8(r*255) | ||
self.green = UInt8(g*255) | ||
self.blue = UInt8(b*255) | ||
self.alpha = UInt8(a*255) | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Careful:
Image.size
reports sizes in points, but for these CG APIs, you'll need to work in pixels.