如何将字体呈现为与显示的完全相同?

2024-05-29 04:55:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我在一个游戏中发现了一个脚本,它肯定使用了Microsoft YaHei字体(当我将在游戏文件夹中找到的字体文件替换为我自己的字体文件时,脚本字体也会更改)

enter image description here

但是,即使更改了“大小”和“位置”参数,渲染结果也总是有点不同

from PIL import Image, ImageDraw, ImageFont
import numpy as np

i = 12
text = '我是王中王'

font = ImageFont.truetype('mysh.ttf', i)
PIL_image = Image.new('RGB', (100, 100), color=0xffffff)
draw = ImageDraw.Draw(PIL_image)
draw.text((31, 11), text, font=font, fill=10, anchor='mm')
Image.fromarray(np.array(PIL_image)).save('out.png')

这是我正在使用的一段代码,通过更改font_size参数,最接近的结果如下:

enter image description here

尝试使用windows paint,获得与PIL相同的字体:

enter image description here

有一些细微的差别,您应该能够找到它:

enter image description here

我意识到位置参数可能是十进制的,但pillow text方法似乎将十进制位置参数截断为整数,将位置参数更改为十进制没有任何区别。我该怎么办


Tags: 文件textimageimport脚本游戏参数pil
1条回答
网友
1楼 · 发布于 2024-05-29 04:55:18

问题既不在PIL中,也不在您的代码中,您做得对,但请记住,在处理图像中的字体渲染时

你的问题

  1. 它是一个非常复杂的问题,实施了很多次,改进了很多次,仍然是一个非常庞大的研究课题
  2. PIL使用自己的字体渲染引擎,“MicrosoftYahei”意味着您很可能正在windows中运行代码;它有自己的渲染引擎,这只是一个假设
  3. PIL&;如果您为这两个对象提供相同的参数,Windows将始终发挥一定的作用

解决方案

  1. 使用python中的Win32API使用python中的windows渲染引擎 获得几乎相同的结果或至少最接近的结果

  2. 或者尝试使用gamming库pygame进行实验,因为它是用来开发的 因此,它将更精确地处理字体渲染,并使用 实现可靠性的复杂方法

使用Windows API

import ctypes
import struct
import win32con
import win32gui
import win32ui

from PIL import Image


def RGB(r, g, b):    
    return r | (g << 8) | (b << 16)

def native_bmp_to_pil(hdc, bitmap_handle, width, height):
    bmpheader = struct.pack("LHHHH", struct.calcsize("LHHHH"),
                            width, height, 1, 24) #w,h, planes=1, bitcount)
    c_bmpheader = ctypes.c_buffer(bmpheader)

    #3 bytes per pixel, pad lines to 4 bytes    
    c_bits = ctypes.c_buffer(" " * (height * ((width*3 + 3) & -4)))

    res = ctypes.windll.gdi32.GetDIBits(
        hdc, bitmap_handle, 0, height,
        c_bits, c_bmpheader,
        win32con.DIB_RGB_COLORS)
    if not res:
        raise IOError("native_bmp_to_pil failed: GetDIBits")

    im = Image.frombuffer(
        "RGB", (width, height), c_bits,
        "raw", "BGR", (width*3 + 3) & -4, -1)
    return im    


class Win32Font:
    def __init__(self, name, height, weight=win32con.FW_NORMAL,
                 italic=False, underline=False):
        self.font = win32ui.CreateFont({
            'name': name, 'height': height,
            'weight': weight, 'italic': italic, 'underline': underline})

        #create a compatible DC we can use to draw:
        self.desktopHwnd = win32gui.GetDesktopWindow()
        self.desktopDC = win32gui.GetWindowDC(self.desktopHwnd)
        self.mfcDC = win32ui.CreateDCFromHandle(self.desktopDC)         
        self.drawDC = self.mfcDC.CreateCompatibleDC()

        #initialize it
        self.drawDC.SelectObject(self.font)

    def renderText(self, text):
        """render text to a PIL image using the windows API."""
        self.drawDC.SetTextColor(RGB(255,0,0))

        #create the compatible bitmap:
        w,h = self.drawDC.GetTextExtent(text)
        
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(self.mfcDC, w, h)        
        self.drawDC.SelectObject(saveBitMap)

        #draw it
        self.drawDC.DrawText(text, (0, 0, w, h), win32con.DT_LEFT)

        #convert to PIL image
        im = native_bmp_to_pil(self.drawDC.GetSafeHdc(), saveBitMap.GetHandle(), w, h)

        #clean-up
        win32gui.DeleteObject(saveBitMap.GetHandle())

        return im        

    def __del__(self):
        self.mfcDC.DeleteDC()
        self.drawDC.DeleteDC()
        win32gui.ReleaseDC(self.desktopHwnd, self.desktopDC)
        win32gui.DeleteObject(self.font.GetSafeHandle())

    def __del__(self):
        win32gui.DeleteObject(self.font.GetSafeHandle())

用这个

f = Win32Font("Your Font Name e.g. Microsoft YaHei", 15) #to use your font file install the font in windows
im = f.renderText("your text") #render your text
im.save("/path/to/image") #save your image if needed

使用Pygame

pygfont = pygame.font.Font(r"c:\windows\fonts\yourcustomfont.ttf", 15)
surf = pygfont.render("your text to render", False, (0,0,0), (255,255,255)) #False means anti aliasing disabled, you can experiment with enabled flag also
pygame.image.save(surf, r"/path/to/your/image")

要安装pygame,请为python2运行pip install pygame,或为python3运行pip3 install pygame

相关问题 更多 >

    热门问题