如何用PIL确定ICO图像的透明颜色指数?

发布于 2024-07-23 08:41:51 字数 469 浏览 14 评论 0原文

具体来说,这是来自 .ico 文件,因此不存在像 gif 中那样的“透明”“信息”属性。 下面的示例说明了使用正确的透明度索引“0”将 Yahoo! 的图标转换为 png,这是我猜测的。 如何检测 ico 实际上是透明的并且透明度指数为 0 ?

import urllib2
import Image
import StringIO

resp = urllib2.urlopen("http://www.yahoo.com/favicon.ico")
image = Image.open(StringIO.StringIO(resp.read()))

f = file("test.png", "w")

# I guessed that the transparent index is 0.  how to
# determine it correctly ?
image.save(f, "PNG", quality=95, transparency=0)

Specifically, this is from an .ico file, so there is no "transparent" "info" attribute like you would get in a gif. The below example illustrates converting Yahoo!'s favicon to a png using the correct transparency index of "0", which I guessed. how to detect that the ico is in fact transparent and that the transparency index is 0 ?

import urllib2
import Image
import StringIO

resp = urllib2.urlopen("http://www.yahoo.com/favicon.ico")
image = Image.open(StringIO.StringIO(resp.read()))

f = file("test.png", "w")

# I guessed that the transparent index is 0.  how to
# determine it correctly ?
image.save(f, "PNG", quality=95, transparency=0)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

Bonjour°[大白 2024-07-30 08:41:51

看起来有人认识到 PIL 并没有真正正确地读取 ICO(在将其源代码与 ICO 格式的一些研究进行协调后,我可以看到同样的事情 - 有一个 AND 位图决定透明度)
并提出了这个扩展:

http://www.djangosnippets.org/snippets/1287/

因为这对于非 django 应用程序很有用,所以我在此处重新发布了对其异常抛出的一些调整:

import operator
import struct

from PIL import BmpImagePlugin, PngImagePlugin, Image


def load_icon(file, index=None):
    '''
    Load Windows ICO image.

    See http://en.wikipedia.org/w/index.php?oldid=264332061 for file format
    description.
    '''
    if isinstance(file, basestring):
        file = open(file, 'rb')

    try:
        header = struct.unpack('<3H', file.read(6))
    except:
        raise IOError('Not an ICO file')

    # Check magic
    if header[:2] != (0, 1):
        raise IOError('Not an ICO file')

    # Collect icon directories
    directories = []
    for i in xrange(header[2]):
        directory = list(struct.unpack('<4B2H2I', file.read(16)))
        for j in xrange(3):
            if not directory[j]:
                directory[j] = 256

        directories.append(directory)

    if index is None:
        # Select best icon
        directory = max(directories, key=operator.itemgetter(slice(0, 3)))
    else:
        directory = directories[index]

    # Seek to the bitmap data
    file.seek(directory[7])

    prefix = file.read(16)
    file.seek(-16, 1)

    if PngImagePlugin._accept(prefix):
        # Windows Vista icon with PNG inside
        image = PngImagePlugin.PngImageFile(file)
    else:
        # Load XOR bitmap
        image = BmpImagePlugin.DibImageFile(file)
        if image.mode == 'RGBA':
            # Windows XP 32-bit color depth icon without AND bitmap
            pass
        else:
            # Patch up the bitmap height
            image.size = image.size[0], image.size[1] >> 1
            d, e, o, a = image.tile[0]
            image.tile[0] = d, (0, 0) + image.size, o, a

            # Calculate AND bitmap dimensions. See
            # http://en.wikipedia.org/w/index.php?oldid=264236948#Pixel_storage
            # for description
            offset = o + a[1] * image.size[1]
            stride = ((image.size[0] + 31) >> 5) << 2
            size = stride * image.size[1]

            # Load AND bitmap
            file.seek(offset)
            string = file.read(size)
            mask = Image.fromstring('1', image.size, string, 'raw',
                                    ('1;I', stride, -1))

            image = image.convert('RGBA')
            image.putalpha(mask)

    return image

looks like someone recognized that PIL doesn't really read ICO correctly (I can see the same thing after reconciling its source code with some research on the ICO format - there is an AND bitmap which determines transparency)
and came up with this extension:

http://www.djangosnippets.org/snippets/1287/

since this is useful for non-django applications, I've reposted here with a few tweaks to its exception throws:

import operator
import struct

from PIL import BmpImagePlugin, PngImagePlugin, Image


def load_icon(file, index=None):
    '''
    Load Windows ICO image.

    See http://en.wikipedia.org/w/index.php?oldid=264332061 for file format
    description.
    '''
    if isinstance(file, basestring):
        file = open(file, 'rb')

    try:
        header = struct.unpack('<3H', file.read(6))
    except:
        raise IOError('Not an ICO file')

    # Check magic
    if header[:2] != (0, 1):
        raise IOError('Not an ICO file')

    # Collect icon directories
    directories = []
    for i in xrange(header[2]):
        directory = list(struct.unpack('<4B2H2I', file.read(16)))
        for j in xrange(3):
            if not directory[j]:
                directory[j] = 256

        directories.append(directory)

    if index is None:
        # Select best icon
        directory = max(directories, key=operator.itemgetter(slice(0, 3)))
    else:
        directory = directories[index]

    # Seek to the bitmap data
    file.seek(directory[7])

    prefix = file.read(16)
    file.seek(-16, 1)

    if PngImagePlugin._accept(prefix):
        # Windows Vista icon with PNG inside
        image = PngImagePlugin.PngImageFile(file)
    else:
        # Load XOR bitmap
        image = BmpImagePlugin.DibImageFile(file)
        if image.mode == 'RGBA':
            # Windows XP 32-bit color depth icon without AND bitmap
            pass
        else:
            # Patch up the bitmap height
            image.size = image.size[0], image.size[1] >> 1
            d, e, o, a = image.tile[0]
            image.tile[0] = d, (0, 0) + image.size, o, a

            # Calculate AND bitmap dimensions. See
            # http://en.wikipedia.org/w/index.php?oldid=264236948#Pixel_storage
            # for description
            offset = o + a[1] * image.size[1]
            stride = ((image.size[0] + 31) >> 5) << 2
            size = stride * image.size[1]

            # Load AND bitmap
            file.seek(offset)
            string = file.read(size)
            mask = Image.fromstring('1', image.size, string, 'raw',
                                    ('1;I', stride, -1))

            image = image.convert('RGBA')
            image.putalpha(mask)

    return image
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文