zoukankan      html  css  js  c++  java
  • Pillow不支持color emoji font!

    我想在MAC下面用pillow把一些文本转换成PNG图片,在转普通文字的时候都没问题,但在遇到emoji字符的时候就搞不定了,代码如下:

    import    loggingimport    PIL.Image
    import    PIL.ImageDraw
    import    PIL.ImageFont
            
    class    Main(object):def TestEmoji(self):
            text = u''
            fontName = '/System/Library/Fonts/Apple Color Emoji.ttf'
            pngPath = 'test.png'
            fontSize = 16
    
            font = PIL.ImageFont.truetype('/System/Library/Fonts/Apple Color Emoji.ttf', 16, encoding='unic')
            width, height = font.getsize(text)
            logging.debug('(width, height) = (%d, %d)' % (width, height))
            image = PIL.Image.new('RGBA', (width, height), (0, 0, 0, 0))  # 设置透明背景
            draw = PIL.ImageDraw.Draw(image)
            draw.text((0, 0), text, font = font, fill = '#000000')
            image.save(pngPath)
            image.show()

    得到如下错误:

      File "test.py", line 37, in TestEmoji
        font = PIL.ImageFont.truetype('/System/Library/Fonts/Apple Color Emoji.ttf', 16, encoding='unic')
      File "/Users/palance/Downloads/Pillow-master/PIL/ImageFont.py", line 291, in truetype
        return FreeTypeFont(fontpath, size, index, encoding)
      File "/Users/palance/Downloads/Pillow-master/PIL/ImageFont.py", line 140, in __init__
        self.font = core.getfont(font, size, index, encoding)
    IOError: invalid pixel size

    根据提示,追到ImageFont.py:

    ……
    try:
        from PIL import _imagingft as core
    except ImportError:
        core = _imagingft_not_installed()
    
    ……
    class FreeTypeFont(object):
        ……
    
        def __init__(self, font=None, size=10, index=0, encoding="", file=None):
            ……if isPath(font):
                self.font = core.getfont(font, size, index, encoding)  # 出错的140行
            else:
                ……

    根据头部代码可以找到core是来自PIL/_imagingft,找到Pillow-master/PIL/_imagingft.so,这是由C写的so文件.再去追这段C代码,找到Pillow-master/_imagingft.c的getfont函数:

    static PyObject*
    getfont(PyObject* self_, PyObject* args, PyObject* kw)
    {
        /* create a font object from a file name and a size (in pixels) */
    
        FontObject* self;
        int error = 0;
    
        char* filename = NULL;
        int size;
        int index = 0;
        unsigned char* encoding;
        unsigned char* font_bytes;
        int font_bytes_size = 0;
        static char* kwlist[] = {
            "filename", "size", "index", "encoding", "font_bytes", NULL
        };
        printf("1:%d\n", error);
    
        if (!library) {
            PyErr_SetString(
                PyExc_IOError,
                "failed to initialize FreeType library"
                );
            return NULL;
        }
        printf("2:%d\n", error);
    
        if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#", kwlist,
                                         Py_FileSystemDefaultEncoding, &filename,
                                         &size, &index, &encoding, &font_bytes,
                                         &font_bytes_size)) {
            return NULL;
        }
    
        printf("3:%d\n", error);
        self = PyObject_New(FontObject, &Font_Type);
        if (!self) {
            if (filename)
                PyMem_Free(filename);
            return NULL;
        }
    
        printf("4:%d\n", error);
        if (filename && font_bytes_size <= 0) {
            self->font_bytes = NULL;
            error = FT_New_Face(library, filename, index, &self->face);
            printf("4.1:%d\n, filename=%s, index=%d\n", error, filename, index);
        } else {
            /* need to have allocated storage for font_bytes for the life of the object.*/
            /* Don't free this before FT_Done_Face */
            self->font_bytes = PyMem_Malloc(font_bytes_size);
            if (!self->font_bytes) {
                error = 65; // Out of Memory in Freetype. 
            }
            if (!error) {
                memcpy(self->font_bytes, font_bytes, (size_t)font_bytes_size);
                error = FT_New_Memory_Face(library, (FT_Byte*)self->font_bytes, 
                                           font_bytes_size, index, &self->face);
            }
            printf("4.2:%d\n", error);
        }
    
        printf("5:%d\n", error);
        if (!error)
            error = FT_Set_Pixel_Sizes(self->face, 0, size);   # 定位到问题出在这里
    
        printf("6: error = %d, size = %d\n", error, size);
        if (!error && encoding && strlen((char*) encoding) == 4) {
            FT_Encoding encoding_tag = FT_MAKE_TAG(
                encoding[0], encoding[1], encoding[2], encoding[3]
                );
            error = FT_Select_Charmap(self->face, encoding_tag);
            printf("6.1:%d\n", error);
        }
        if (filename)
          PyMem_Free(filename);
    
        printf("7:%d\n", error);
        if (error) {
            if (self->font_bytes) {
                PyMem_Free(self->font_bytes);
            }  
            PyObject_Del(self);
            return geterror(error);
        }
    
        printf("8:%d\n", error);
        return (PyObject*) self;
    }

     我在代码里面插入了一些调试信息,定位到问题发生在函数调用 FT_Set_Pixel_Sizes 里面,这是一个freetype函数的调用。难道是freetype不支持emoji字体?

    继续追查freetype,我发现freetype是从2.5开始号称支持了color font,我用的是2.6,应该是没问题的。

    我从https://gist.github.com/jokertarot/7583938找到一段支持color font的代码,仔细查看了使用freetype的前三步:

    1、调用Init初始化库

    2、构造FreeTypeFace对象,生成typeface

    3、调用SetXXXFont,注意在这一步普通字体和Color字体是不一样的,普通字体调用了SetNormalFont,内部调用FT_Set_Pixel_Sizes;而Color字体调用SetColorFont,内部调用FT_Select_Size

    再回过头来看Pillow-master/_imagingft.c的getfont函数,他是没有区分NormalFont和ColorFont的,一律按照NormalFont来处理了,所以出错。

    这应该就是核心问题了:freetype支持color font,但在具体处理的时候需要使用不同的接口,在Pillow这一层没有考虑到这一点,因此是Pillow无法支持color font。要想解决问题,必须在Pillow-master/_imagingft.c的getfont里作出修改。

    freetype那段支持color font的代码我还没试过,回头再专门研究一下。

    
    
  • 相关阅读:
    解决Linux中Too many open files问题
    10个必需的iOS开发工具和资源
    @ModelAttribute跟@SessionAttributes的应用
    7个改变世界的Java项目
    Java序列化与反序列化
    微软推出“IE9梦幻任务栏Pin计划”
    java中replace和replaceAll的区别
    【转】hibernate中annotation方式SchemaExport无法生成表的原因(ORA02261)
    permgen space报错
    em和px
  • 原文地址:https://www.cnblogs.com/palance/p/4809872.html
Copyright © 2011-2022 走看看