1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from Quartz import *
import math
_REMOVABLE_DISK_PATH = '/System/Library/Extensions/IOStorageFamily.kext/Contents/Resources/Removable.icns'
def badge_disk_icon(badge_file, output_file):
# Load the Removable disk icon
url = CFURLCreateWithFileSystemPath(None, _REMOVABLE_DISK_PATH,
kCFURLPOSIXPathStyle, False)
backdrop = CGImageSourceCreateWithURL(url, None)
backdropCount = CGImageSourceGetCount(backdrop)
# Load the badge
url = CFURLCreateWithFileSystemPath(None, badge_file,
kCFURLPOSIXPathStyle, False)
badge = CGImageSourceCreateWithURL(url, None)
assert badge is not None, 'Unable to process image file: %s' % badge_file
badgeCount = CGImageSourceGetCount(badge)
# Set up a destination for our target
url = CFURLCreateWithFileSystemPath(None, output_file,
kCFURLPOSIXPathStyle, False)
target = CGImageDestinationCreateWithURL(url, 'com.apple.icns',
backdropCount, None)
# Get the RGB colorspace
rgbColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)
# Scale
scale = 1.0
# Perspective transform
corners = ((0.2, 0.95), (0.8, 0.95), (0.85, 0.35), (0.15, 0.35))
# Translation
position = (0.5, 0.5)
for n in range(backdropCount):
props = CGImageSourceCopyPropertiesAtIndex(backdrop, n, None)
width = props['PixelWidth']
height = props['PixelHeight']
dpi = props['DPIWidth']
depth = props['Depth']
# Choose the best sized badge image
bestWidth = None
bestHeight = None
bestBadge = None
bestDepth = None
bestDPI = None
for m in range(badgeCount):
badgeProps = CGImageSourceCopyPropertiesAtIndex(badge, m, None)
badgeWidth = badgeProps['PixelWidth']
badgeHeight = badgeProps['PixelHeight']
badgeDPI = badgeProps['DPIWidth']
badgeDepth = badgeProps['Depth']
if bestBadge is None or (badgeWidth <= width
and (bestWidth > width
or badgeWidth > bestWidth
or (badgeWidth == bestWidth
and badgeDPI == dpi
and badgeDepth <= depth
and (bestDepth is None
or badgeDepth > bestDepth)))):
bestBadge = m
bestWidth = badgeWidth
bestHeight = badgeHeight
bestDPI = badgeDPI
bestDepth = badgeDepth
badgeImage = CGImageSourceCreateImageAtIndex(badge, bestBadge, None)
badgeCI = CIImage.imageWithCGImage_(badgeImage)
backgroundImage = CGImageSourceCreateImageAtIndex(backdrop, n, None)
backgroundCI = CIImage.imageWithCGImage_(backgroundImage)
compositor = CIFilter.filterWithName_('CISourceOverCompositing')
lanczos = CIFilter.filterWithName_('CILanczosScaleTransform')
perspective = CIFilter.filterWithName_('CIPerspectiveTransform')
transform = CIFilter.filterWithName_('CIAffineTransform')
lanczos.setValue_forKey_(badgeCI, kCIInputImageKey)
lanczos.setValue_forKey_(scale * float(width)/bestWidth, kCIInputScaleKey)
lanczos.setValue_forKey_(1.0, kCIInputAspectRatioKey)
topLeft = (width * scale * corners[0][0],
width * scale * corners[0][1])
topRight = (width * scale * corners[1][0],
width * scale * corners[1][1])
bottomRight = (width * scale * corners[2][0],
width * scale * corners[2][1])
bottomLeft = (width * scale * corners[3][0],
width * scale * corners[3][1])
out = lanczos.valueForKey_(kCIOutputImageKey)
if width >= 16:
perspective.setValue_forKey_(out, kCIInputImageKey)
perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*topLeft),
'inputTopLeft')
perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*topRight),
'inputTopRight')
perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*bottomRight),
'inputBottomRight')
perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*bottomLeft),
'inputBottomLeft')
out = perspective.valueForKey_(kCIOutputImageKey)
tfm = NSAffineTransform.transform()
tfm.translateXBy_yBy_(math.floor((position[0] - 0.5 * scale) * width),
math.floor((position[1] - 0.5 * scale) * height))
transform.setValue_forKey_(out, kCIInputImageKey)
transform.setValue_forKey_(tfm, 'inputTransform')
out = transform.valueForKey_(kCIOutputImageKey)
compositor.setValue_forKey_(out, kCIInputImageKey)
compositor.setValue_forKey_(backgroundCI, kCIInputBackgroundImageKey)
result = compositor.valueForKey_(kCIOutputImageKey)
cgContext = CGBitmapContextCreate(None,
width,
height,
8,
0,
rgbColorSpace,
kCGImageAlphaPremultipliedLast)
context = CIContext.contextWithCGContext_options_(cgContext, None)
context.drawImage_inRect_fromRect_(result,
((0, 0), (width, height)),
((0, 0), (width, height)))
image = CGBitmapContextCreateImage(cgContext)
CGImageDestinationAddImage(target, image, props)
CGImageDestinationFinalize(target)
|