I originally wrote this application ( GitHub ) in Obj-C, but it needs to be converted to Swift. After the conversion, I had problems creating the context for the created bitmap.
Error message:
Whiteboard[2833] <Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 3-component color space; kCGImageAlphaNone; 1500 bytes/row.
I originally had this:
self.cacheContext = CGBitmapContextCreate (self.cacheBitmap, size.width, size.height, 8, bitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst);
And now I have:
self.cacheContext = CGBitmapContextCreate(self.cacheBitmap!, UInt(size.width), UInt(size.height), 8, bitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrder32Little);
I believe the problem is related CGBitmapInfo.ByteOrder32Little, but I'm not sure what to convey. Is there any way to convey kCGImageAlphaNoneSkipFirsthow CGBitmapInfo?
Full source code:
import Foundation
import UIKit
class WhiteBoard: UIView {
var hue: CGFloat
var cacheBitmap: UnsafeMutablePointer<Void>?
var cacheContext: CGContextRef?
override init(frame: CGRect) {
self.hue = 0.0;
super.init(frame: frame);
self.initContext(frame);
self.backgroundColor = UIColor.whiteColor();
let buttonFrame = CGRectMake(frame.size.width - 50, frame.size.height - 30, 40, 25);
let button = UIButton();
button.frame = buttonFrame;
button.setTitle("Save", forState: .Normal);
button.setTitleColor(UIColor.blueColor(), forState: .Normal);
button.addTarget(self, action: "downloadImage", forControlEvents: .TouchUpInside);
self.addSubview(button);
}
required init(coder aDecoder: NSCoder) {
self.hue = 0.0;
super.init(coder: aDecoder)
}
func initContext(frame: CGRect)-> Bool {
let size = frame.size;
var bitmapByteCount: UInt!
var bitmapBytesPerRow: UInt!
bitmapBytesPerRow = UInt(size.width * 4);
bitmapByteCount = UInt(CGFloat(bitmapBytesPerRow) * size.height);
self.cacheBitmap = malloc(bitmapByteCount);
self.cacheContext = CGBitmapContextCreate(self.cacheBitmap!, UInt(size.width), UInt(size.height), 8, bitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrder32Little);
CGContextSetRGBFillColor(self.cacheContext, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(self.cacheContext, frame);
CGContextSaveGState(self.cacheContext);
return true;
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch;
self.drawToCache(touch);
}
func drawToCache(touch: UITouch) {
self.hue += 0.005;
if(self.hue > 1.0) {
self.hue = 0.0;
}
let color = UIColor(hue: CGFloat(self.hue), saturation: CGFloat(0.7), brightness: CGFloat(1.0), alpha: CGFloat(1.0));
CGContextSetStrokeColorWithColor(self.cacheContext, color.CGColor);
CGContextSetLineCap(self.cacheContext, kCGLineCapRound);
CGContextSetLineWidth(self.cacheContext, CGFloat(15));
let lastPoint = touch.previousLocationInView(self) as CGPoint;
let newPoint = touch.locationInView(self) as CGPoint;
CGContextMoveToPoint(self.cacheContext, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(self.cacheContext, newPoint.x, newPoint.y);
CGContextStrokePath(self.cacheContext);
let dirtyPoint1 = CGRectMake(lastPoint.x-10, lastPoint.y-10, 20, 20);
let dirtyPoint2 = CGRectMake(newPoint.x-10, newPoint.y-10, 20, 20);
self.setNeedsDisplay();
}
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext();
let cacheImage = CGBitmapContextCreateImage(self.cacheContext);
CGContextDrawImage(context, self.bounds, cacheImage);
}
func downloadImage() {
let image = UIImage(CGImage: CGBitmapContextCreateImage(self.cacheContext));
UIImageWriteToSavedPhotosAlbum(image, self, "image:didFinishSavingWithError:contextInfo:", nil);
}
func image(image: UIImage, didFinishSavingWithError error: NSError, contextInfo: UnsafeMutablePointer<Void>) {
if(!error.localizedDescription.isEmpty) {
UIAlertView(title: "Error", message: "Error Saving Photo", delegate: nil, cancelButtonTitle: "Ok").show();
}
}
}