# -*- 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)