Exemplo n.º 1
0
def convertIconToPNG(icon_path,
                     destination_path,
                     desired_pixel_height=350,
                     desired_dpi=72):
    '''Converts an icns file to a png file, choosing the representation
    closest to (but >= if possible) the desired_pixel_height.
    Returns True if successful, False otherwise'''
    icns_url = NSURL.fileURLWithPath_(icon_path)
    png_url = NSURL.fileURLWithPath_(destination_path)

    image_source = CGImageSourceCreateWithURL(icns_url, None)
    if not image_source:
        return False
    number_of_images = CGImageSourceGetCount(image_source)
    if number_of_images == 0:
        return False

    selected_index = 0
    candidate = {}
    # iterate through the individual icon sizes to find the "best" one
    for index in range(number_of_images):
        try:
            properties = CGImageSourceCopyPropertiesAtIndex(
                image_source, index, None)
            # perform not empty check for properties to prevent crash as CGImageSourceCopyPropertiesAtIndex sometimes fails in 10.15.4 and above
            if not properties:
                return False
            dpi = int(properties.get(kCGImagePropertyDPIHeight, 0))
            height = int(properties.get(kCGImagePropertyPixelHeight, 0))
            if (not candidate or (height < desired_pixel_height
                                  and height > candidate['height'])
                    or (height >= desired_pixel_height
                        and height < candidate['height'])
                    or (height == candidate['height'] and dpi == desired_dpi)):
                candidate = {'index': index, 'dpi': dpi, 'height': height}
                selected_index = index
        except ValueError:
            pass

    image = CGImageSourceCreateImageAtIndex(image_source, selected_index, None)
    image_dest = CGImageDestinationCreateWithURL(png_url, 'public.png', 1,
                                                 None)
    CGImageDestinationAddImage(image_dest, image, None)
    return CGImageDestinationFinalize(image_dest)
Exemplo n.º 2
0
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)