Skip to content
This repository has been archived by the owner on Jan 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #50 from jathu/transparency-fix
Browse files Browse the repository at this point in the history
Fix issue of considering semi-transparent pixels
  • Loading branch information
jathu committed Apr 29, 2017
2 parents 35abc35 + 13876fd commit 32e33e2
Show file tree
Hide file tree
Showing 30 changed files with 46 additions and 62 deletions.
2 changes: 1 addition & 1 deletion README.md
@@ -1,6 +1,6 @@
# UIImageColors

iTunes style color fetcher for UIImage. This is an *almost* identical port of [Panic's OS X ColorArt](https://github.com/panicinc/ColorArt/) for iOS Swift.
iTunes style color fetcher for UIImage. This is based on [Panic's OS X ColorArt](https://github.com/panicinc/ColorArt/) for iOS Swift.

In other words, it fetches the most dominant and prominent colors.

Expand Down
58 changes: 21 additions & 37 deletions Sources/UIImageColors.swift
Expand Up @@ -148,12 +148,12 @@ extension UIImage {
var result = UIImageColors()

let cgImage = self.resizeForUIImageColors(newSize: scaleDownSize).cgImage!
let width = cgImage.width
let height = cgImage.height
let width: Int = cgImage.width
let height: Int = cgImage.height

let blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
let whiteColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)

let bytesPerPixel: Int = 4
let bytesPerRow: Int = width * bytesPerPixel
let bitsPerComponent: Int = 8
let randomColorsThreshold = Int(CGFloat(height)*0.01)
let sortedColorComparator: Comparator = { (main, other) -> ComparisonResult in
let m = main as! PCCountedColor, o = other as! PCCountedColor
Expand All @@ -165,50 +165,34 @@ extension UIImage {
return ComparisonResult.orderedAscending
}
}
let blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
let whiteColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)

let colorSpace = CGColorSpaceCreateDeviceRGB()
let raw = malloc(bytesPerRow * height)
defer {
free(raw)
}
let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue
guard let ctx = CGContext(data: raw, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
fatalError("UIImageColors.getColors failed: could not create CGBitmapContext")

guard let data = CFDataGetBytePtr(cgImage.dataProvider!.data) else {
fatalError("UIImageColors.getColors failed: could not get cgImage data")
}
let drawingRect = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))
ctx.draw(cgImage, in: drawingRect)

let data = ctx.data?.assumingMemoryBound(to: UInt8.self)

let leftEdgeColors = NSCountedSet(capacity: height)
// Filter out and collect pixels from image
let imageColors = NSCountedSet(capacity: width * height)

for x in 0..<width {
for y in 0..<height {
let pixel = ((width * y) + x) * bytesPerPixel
let color = UIColor(
red: CGFloat((data?[pixel+1])!)/255,
green: CGFloat((data?[pixel+2])!)/255,
blue: CGFloat((data?[pixel+3])!)/255,
alpha: 1
)

// A lot of images have white or black edges from crops, so ignore the first few pixels
if 5 <= x && x <= 10 {
leftEdgeColors.add(color)
let pixel: Int = ((width * y) + x) * 4
// Only consider pixels with 50% opacity or higher
if 127 <= data[pixel+3] {
imageColors.add(UIColor(
red: CGFloat(data[pixel+2])/255,
green: CGFloat(data[pixel+1])/255,
blue: CGFloat(data[pixel])/255,
alpha: 1.0
))
}

imageColors.add(color)
}
}

// Get background color
var enumerator = leftEdgeColors.objectEnumerator()
var sortedColors = NSMutableArray(capacity: leftEdgeColors.count)
var enumerator = imageColors.objectEnumerator()
var sortedColors = NSMutableArray(capacity: imageColors.count)
while let kolor = enumerator.nextObject() as? UIColor {
let colorCount = leftEdgeColors.count(for: kolor)
let colorCount = imageColors.count(for: kolor)
if randomColorsThreshold < colorCount {
sortedColors.add(PCCountedColor(color: kolor, count: colorCount))
}
Expand Down
2 changes: 1 addition & 1 deletion Supporting Files/Info.plist
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.3.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion UIImageColors.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "UIImageColors"
spec.version = "1.2.1"
spec.version = "1.3.0"
spec.license = "MIT"
spec.summary = "iTunes style color fetcher for UIImage."
spec.homepage = "https://github.com/jathu/UIImageColors"
Expand Down
28 changes: 14 additions & 14 deletions UIImageColorsPlayground.playground/Contents.swift
Expand Up @@ -7,18 +7,18 @@ import UIImageColors
PlaygroundPage.current.needsIndefiniteExecution = true

let Albums: [Album] = [
Album(albumFile: "OK Computer.png", albumName: "OK Computer", artistName: "Radiohead", year: 1997),
Album(albumFile: "Nothing Was the Same.png", albumName: "Nothing Was the Same", artistName: "Drake", year: 2013),
Album(albumFile: "My Beautiful Dark Twisted Fantasy.png", albumName: "My Beautiful Dark Twisted Fantasy", artistName: "Kanye West", year: 2010),
Album(albumFile: "Kind of Blue.png", albumName: "Kind of Blue", artistName: "Miles Davis", year: 1959),
Album(albumFile: "If You're Reading This It's Too Late.png", albumName: "If You're Reading This It's Too Late", artistName: "Drake", year: 2015),
Album(albumFile: "New Morning.png", albumName: "New Morning", artistName: "Bob Dylan", year: 1970),
Album(albumFile: "Since I Left You.png", albumName: "Since I Left You", artistName: "The Avalanches", year: 2000),
Album(albumFile: "Random Access Memories.png", albumName: "Random Access Memories", artistName: "Daft Punk", year: 2013),
Album(albumFile: "The Eraser.png", albumName: "The Eraser", artistName: "Thome Yorke", year: 2006),
Album(albumFile: "Operation Doomsday.png", albumName: "Operation Doomsday", artistName: "MF Doom", year: 1999),
Album(albumFile: "Cupid Deluxe.png", albumName: "Cupid Deluxe", artistName: "Blood Orange", year: 2013),
Album(albumFile: "Black on Both Sides.png", albumName: "Black on Both Sides", artistName: "Mos Def", year: 1999)
Album(albumFile: "df.png", albumName: "My Beautiful Dark Twisted Fantasy", artistName: "Kanye West", year: 2010),
Album(albumFile: "nw.jpg", albumName: "Nothing Was the Same", artistName: "Drake", year: 2013),
Album(albumFile: "ok.png", albumName: "OK Computer", artistName: "Radiohead", year: 1997),
Album(albumFile: "yz.jpg", albumName: "Yeezus", artistName: "Kanye West", year: 2013),
Album(albumFile: "ab.jpg", albumName: "Ágætis byrjun", artistName: "Sigur Rós", year: 1999),
Album(albumFile: "cd.jpg", albumName: "Cupid Deluxe", artistName: "Blood Orange", year: 2013),
Album(albumFile: "ed.jpg", albumName: "Endtroducing.....", artistName: "DJ Shadow", year: 1996),
Album(albumFile: "dj.jpg", albumName: "Duke Ellington & John Coltrane", artistName: "Duke Ellington & John Coltrane", year: 1963),
Album(albumFile: "ph.jpg", albumName: "Purple Haze", artistName: "Cam'ron", year: 2004),
Album(albumFile: "rm.png", albumName: "Random Access Memories", artistName: "Daft Punk", year: 2013),
Album(albumFile: "sk.jpg", albumName: "Skream!", artistName: "Skream", year: 2006),
Album(albumFile: "b6.jpg", albumName: "Barter 6", artistName: "Young Thug", year: 2015)
]

func makeBox(_ asynchronous: Bool, completionHandler: @escaping (UIView) -> Void) {
Expand All @@ -30,7 +30,7 @@ func makeBox(_ asynchronous: Bool, completionHandler: @escaping (UIView) -> Void
let c = Container(album: Albums[Int(i)])
c.frame.origin = CGPoint(x: sample.frame.width*(i.truncatingRemainder(dividingBy: 2)), y: sample.frame.height*floor(i/2))
box.addSubview(c)

if asynchronous {
c.albumImageView.image!.getColors { colors in
c.backgroundColor = colors.backgroundColor
Expand All @@ -55,7 +55,7 @@ func makeBox(_ asynchronous: Bool, completionHandler: @escaping (UIView) -> Void
}

// Make a box of albums
makeBox(true) { box in
makeBox(false) { box in
box.alpha = 1
PlaygroundPage.current.finishExecution()
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion UIImageColorsPlayground.playground/contents.xcplayground
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' last-migration='0800'>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false' last-migration='0800'>
<timeline fileName='timeline.xctimeline'/>
</playground>
14 changes: 7 additions & 7 deletions UIImageColorsPlayground.playground/timeline.xctimeline
Expand Up @@ -3,37 +3,37 @@
version = "3.0">
<TimelineItems>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=23&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=497787292.509668"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=23&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=515104523.006536"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=20&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=497787292.509811"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=20&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=515104523.00672"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=19&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=497787292.509913"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=19&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=515104523.00685"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=22&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=497787292.51001"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=22&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=515104523.006985"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=3&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=497787292.510102"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=3&amp;EndingLineNumber=59&amp;StartingColumnNumber=1&amp;StartingLineNumber=59&amp;Timestamp=515104523.007109"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=3117&amp;EndingColumnNumber=8&amp;EndingLineNumber=59&amp;StartingColumnNumber=5&amp;StartingLineNumber=59&amp;Timestamp=497787292.510192"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=2917&amp;EndingColumnNumber=8&amp;EndingLineNumber=59&amp;StartingColumnNumber=5&amp;StartingLineNumber=59&amp;Timestamp=515104523.007231"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=3&amp;CharacterRangeLoc=3113&amp;EndingColumnNumber=8&amp;EndingLineNumber=58&amp;StartingColumnNumber=5&amp;StartingLineNumber=58&amp;Timestamp=497787293.750125"
documentLocation = "#CharacterRangeLen=3&amp;CharacterRangeLoc=2913&amp;EndingColumnNumber=8&amp;EndingLineNumber=58&amp;StartingColumnNumber=5&amp;StartingLineNumber=58&amp;Timestamp=515104523.007466"
lockedSize = "{546, 444}"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
Expand Down
Binary file modified preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 32e33e2

Please sign in to comment.