5

我使用这种方法来调整 png 图像的大小:

将 PNG 转换为预乘 alpha 的方法

但是这个图像仍然失去了透明度:

import Image, numpy

def resize(filename, img,height, width):
    if filename.endswith(".png"):
        img = img.convert('RGBA')
        premult = numpy.fromstring(img.tostring(), dtype=numpy.uint8)
        alphaLayer = premult[3::4] / 255.0
        premult[::4] *= alphaLayer
        premult[1::4] *= alphaLayer
        premult[2::4] *= alphaLayer
        img = Image.fromstring("RGBA", img.size, premult.tostring())
    img = img.resize((height,width), Image.ANTIALIAS)
    return img

http://i.stack.imgur.com/oPV5q.pnghttp://i.stack.imgur.com/jzmT9.png

4

3 回答 3

4

这是一个更复杂的调整大小(保持透明度)的功能:它允许您仅使用新的宽度值、新的宽度和高度值或参考文件来获取新的大小。您也可以更改重采样方法:

## PngResizeTransparency.py
#
## Resize PNG image by keeping the transparency
## thanks to https://stackoverflow.com/users/1453719/nicolas-barbey
#
## Use:
##   - using a reference file to get new sizes:
#        PNG_ResizeKeepTransparency(SourceFile, ResizedFile, RefFile ='YourRefFile.png')
##   - using only the resized width:
#        PNG_ResizeKeepTransparency(SourceFile, ResizedFile, new_width)
##   - using resized width and hight:
#        PNG_ResizeKeepTransparency(SourceFile, ResizedFile, new_width, new_height)
##   - using resample mode: add param resample="NEAREST"/"BILINEAR"/"BICUBIC"/"ANTIALIAS"

from PIL import Image

def PNG_ResizeKeepTransparency(SourceFile, ResizedFile, new_width=0, new_height=0, resample="ANTIALIAS", RefFile =''):
    # needs PIL
    # Inputs:
    #   - SourceFile  = initial PNG file (including the path)
    #   - ResizedFile = resized PNG file (including the path)
    #   - new_width   = resized width in pixels; if you need % plz include it here: [your%] *initial width
    #   - new_height  = resized hight in pixels ; default = 0 = it will be calculated using new_width
    #   - resample = "NEAREST", "BILINEAR", "BICUBIC" and "ANTIALIAS"; default = "ANTIALIAS"
    #   - RefFile  = reference file to get the size for resize; default = ''

    img = Image.open(SourceFile) # open PNG image path and name
    img = img.convert("RGBA")    # convert to RGBA channels
    width, height = img.size     # get initial size

    # if there is a reference file to get the new size
    if RefFile != '':
        imgRef = Image.open(RefFile)
        new_width, new_height = imgRef.size
    else:
        # if we use only the new_width to resize in proportion the new_height
        # if you want % of resize please use it into new_width (?% * initial width)
        if new_height == 0:
            new_height = new_width*width/height

    # split image by channels (bands) and resize by channels
    img.load()
    bands = img.split()
    # resample mode
    if resample=="NEAREST":
        resample = Image.NEAREST
    else:
        if resample=="BILINEAR":
            resample = Image.BILINEAR
        else:
            if resample=="BICUBIC":
                resample = Image.BICUBIC
            else:
                if resample=="ANTIALIAS":
                    resample = Image.ANTIALIAS
    bands = [b.resize((new_width, new_height), resample) for b in bands]
    # merge the channels after individual resize
    img = Image.merge('RGBA', bands)
    # save the image
    img.save(ResizedFile)
    return

#######################################################

if __name__ == "__main__":
    sFile = './autumn-png-leaf.png'
    # resize using new width value (new height is calculated by keeping image aspect)
    PNG_ResizeKeepTransparency(sFile, sFile[:-4]+'_resized.png', 400)
    # resize using a reference file to get the new image dimension 
    PNG_ResizeKeepTransparency(sFile, sFile[:-4]+'_resized.png', RefFile = 'autumn-png-leaf_starry-night-van-gogh_fchollet_10.png')
于 2018-01-11T17:03:04.307 回答
3

该问题与链接的问题无关,而是您必须修补 PIL 以便它tRNS正确读取 PNG 块。PIL 假设这个块有一个值,但是这个显示的图像对调色板中的每个值都有一个透明度描述。处理完之后,解决问题就很简单了:将图像转换为'LA'模式并调整大小:

import sys
from PIL import Image

img = Image.open(sys.argv[1])
pal = img.getpalette()
width, height = img.size
actual_transp = img.info['actual_transparency'] # XXX This will fail.

result = Image.new('LA', img.size)

im = img.load()
res = result.load()
for x in range(width):
    for y in range(height):
        t = actual_transp[im[x, y]]
        color = pal[im[x, y]]
        res[x, y] = (color, t)

result.resize((64, 64), Image.ANTIALIAS).save(sys.argv[2])

所以我们从这个在此处输入图像描述,到这个:在此处输入图像描述

针对这种特定情况的 PIL 补丁实际上非常简单。打开你的PIL/PngImagePlugin.py,转到函数chunk_tRNS,输入if检查im_mode == "P"和随后检查的语句i >= 0,然后添加该行self.im_info["actual_transparency"] = map(ord, s)

于 2013-01-31T22:45:37.893 回答
1

我已经解决了这个问题,不再需要来自 mmgp 的漂亮 hack。PIL 现在将正确读取并应用透明度。

https://github.com/d-schmidt/Pillow/commit/5baa1ac1b8d41fcedce7b12ed1c4a8e87b4851bc

于 2013-02-01T19:24:38.713 回答