Skip to content

Instantly share code, notes, and snippets.

@wddwycc
Created January 21, 2016 14:05
Show Gist options
  • Select an option

  • Save wddwycc/d9f8079fa239d654829f to your computer and use it in GitHub Desktop.

Select an option

Save wddwycc/d9f8079fa239d654829f to your computer and use it in GitHub Desktop.
get RGBA data
//
// UIImageExtension.swift
// ImageFun
//
// Created by Neeraj Kumar on 11/11/14.
// Copyright (c) 2014 Neeraj Kumar. All rights reserved.
//
import Foundation
import UIKit
private extension UIImage {
private func createARGBBitmapContext(inImage: CGImageRef) -> CGContext {
//Get image width, height
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
let bitmapBytesPerRow = Int(pixelsWide) * 4
let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)
// Use the generic RGB color space.
let colorSpace = CGColorSpaceCreateDeviceRGB()
// Allocate memory for image data. This is the destination in memory
// where any drawing to the bitmap context will be rendered.
let bitmapData = UnsafeMutablePointer<UInt8>()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
let context = CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, bitmapInfo)!
return context
}
func sanitizePoint(point:CGPoint) {
let inImage:CGImageRef = self.CGImage!
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
precondition(CGRectContainsPoint(rect, point), "CGPoint passed is not inside the rect of image.It will give wrong pixel and may crash.")
}
}
// Internal functions exposed.Can be public.
extension UIImage {
typealias RawColorType = (newRedColor:UInt8, newgreenColor:UInt8, newblueColor:UInt8, newalphaValue:UInt8)
/*
Change the color of pixel at a certain point.If you want more control try block based method to modify pixels.
*/
func setPixelColorAtPoint(point:CGPoint, color: RawColorType) -> UIImage? {
self.sanitizePoint(point)
let inImage:CGImageRef = self.CGImage!
let context = self.createARGBBitmapContext(inImage)
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
//Clear the context
CGContextClearRect(context, rect)
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, inImage)
// Now we can get a pointer to the image data associated with the bitmap
// context.
var data = CGBitmapContextGetData(context)
var dataType = UnsafeMutablePointer<UInt8>(data)
let offset = 4*((Int(pixelsWide) * Int(point.y)) + Int(point.x))
dataType[offset] = color.newalphaValue
dataType[offset+1] = color.newRedColor
dataType[offset+2] = color.newgreenColor
dataType[offset+3] = color.newblueColor
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue
let bitmapBytesPerRow = Int(pixelsWide) * 4
let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)
let finalcontext = CGBitmapContextCreate(data, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, bitmapInfo)
let imageRef = CGBitmapContextCreateImage(finalcontext)!
return UIImage(CGImage: imageRef, scale: self.scale,orientation: self.imageOrientation)
}
/*
Get pixel color for a pixel in the image.
*/
func getPixelColorAtLocation(point:CGPoint)->UIColor? {
self.sanitizePoint(point)
// Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue
let inImage:CGImageRef = self.CGImage!
let context = self.createARGBBitmapContext(inImage)
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
//Clear the context
CGContextClearRect(context, rect)
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, inImage)
// Now we can get a pointer to the image data associated with the bitmap
// context.
let data = CGBitmapContextGetData(context)
let dataType = UnsafePointer<UInt8>(data)
let offset = 4*((Int(pixelsWide) * Int(point.y)) + Int(point.x))
let alphaValue = dataType[offset]
let redColor = dataType[offset+1]
let greenColor = dataType[offset+2]
let blueColor = dataType[offset+3]
let redFloat = CGFloat(redColor)/255.0
let greenFloat = CGFloat(greenColor)/255.0
let blueFloat = CGFloat(blueColor)/255.0
let alphaFloat = CGFloat(alphaValue)/255.0
return UIColor(red: redFloat, green: greenFloat, blue: blueFloat, alpha: alphaFloat)
// When finished, release the context
// Free image data memory for the context
}
// Get grayscale image from normal image.
func getGrayScale() -> UIImage? {
let inImage:CGImageRef = self.CGImage!
let context = self.createARGBBitmapContext(inImage)
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
let bitmapBytesPerRow = Int(pixelsWide) * 4
let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)
//Clear the context
CGContextClearRect(context, rect)
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, inImage)
// Now we can get a pointer to the image data associated with the bitmap
// context.
//拿到data
let data = CGBitmapContextGetData(context)
let dataType = UnsafeMutablePointer<UInt8>(data)
let point: CGPoint = CGPointMake(0, 0)
for var x = 0; x < Int(pixelsWide) ; x++ {
for var y = 0; y < Int(pixelsHigh) ; y++ {
let offset = 4*((Int(pixelsWide) * Int(y)) + Int(x))
let alpha = dataType[offset]
let red = dataType[offset+1]
let green = dataType[offset+2]
let blue = dataType[offset+3]
//(r+g+b)/3 to get the gray scale
let avg = (UInt32(red) + UInt32(green) + UInt32(blue))/3
dataType[offset + 1] = UInt8(avg)
dataType[offset + 2] = UInt8(avg)
dataType[offset + 3] = UInt8(avg)
}
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue
let finalcontext = CGBitmapContextCreate(data, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, bitmapInfo)
let imageRef = CGBitmapContextCreateImage(finalcontext)!
return UIImage(CGImage: imageRef, scale: self.scale,orientation: self.imageOrientation)
}
// Defining the closure.
typealias ModifyPixelsClosure = (point:CGPoint, redColor:UInt8, greenColor:UInt8, blueColor:UInt8, alphaValue:UInt8)->(newRedColor:UInt8, newgreenColor:UInt8, newblueColor:UInt8, newalphaValue:UInt8)
// Provide closure which will return new color value for pixel using any condition you want inside the closure.
func applyOnPixels(closure:ModifyPixelsClosure) -> UIImage? {
let inImage:CGImageRef = self.CGImage!
let context = self.createARGBBitmapContext(inImage)
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
let bitmapBytesPerRow = Int(pixelsWide) * 4
let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)
//Clear the context
CGContextClearRect(context, rect)
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, inImage)
// Now we can get a pointer to the image data associated with the bitmap
// context.
let data = CGBitmapContextGetData(context)
let dataType = UnsafeMutablePointer<UInt8>(data)
let point: CGPoint = CGPointMake(0, 0)
for var x = 0; x < Int(pixelsWide) ; x++ {
for var y = 0; y < Int(pixelsHigh) ; y++ {
let offset = 4*((Int(pixelsWide) * Int(y)) + Int(x))
let alpha = dataType[offset]
let red = dataType[offset+1]
let green = dataType[offset+2]
let blue = dataType[offset+3]
let (newRedColor, newGreenColor, newBlueColor, newAlphaValue): (UInt8, UInt8, UInt8, UInt8) = closure(point: CGPointMake(CGFloat(x), CGFloat(y)), redColor: red, greenColor: green, blueColor: blue, alphaValue: alpha)
dataType[offset] = newAlphaValue
dataType[offset + 1] = newRedColor
dataType[offset + 2] = newGreenColor
dataType[offset + 3] = newBlueColor
}
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue
let finalcontext = CGBitmapContextCreate(data, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, bitmapInfo)
let imageRef = CGBitmapContextCreateImage(finalcontext)!
return UIImage(CGImage: imageRef, scale: self.scale,orientation: self.imageOrientation)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment