python - 如何正确创建具有所需大小和分辨率(PNG、JPG、JPEG)的新图像?

我想使用 Pillow 创建一个 PNG。 PNG 稍后用于标签打印。因此,我尝试使用 PIL 创建一个新图像,添加一些文本、一个多边形和一个二维码。但是,我发现很难获得合适的图像尺寸(与 7.5 cm x 5.5 cm 的标签尺寸相关)。我只是通过尝试和错误到达那里(它大致是 (275, 204))。保存时,PNG 的分辨率很差,打印时也是如此。

如何正确计算图像大小以及如何提高分辨率以将图像另存为 PNG(或 JPG 或 JPEG)。

到目前为止,这是我的代码:

import qrcode
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 

# Create qr code instance
qr = qrcode.QRCode(
    version = 1,
    error_correction = qrcode.constants.ERROR_CORRECT_H,
    box_size = 4,
    border = .2,
)

text = "test"
# Create new image

img = Image.new('RGB', (275, 204), color = (220,220,220))

# Add data
qr.add_data(text)
qr.make(fit=True)

# Create an image from the QR Code instance
qrc = qr.make_image(fill_color='black', back_color='white')

draw = ImageDraw.Draw(img)

font1 = ImageFont.truetype("arial.ttf", 25)
font2 = ImageFont.truetype("arial.ttf", 60)

draw.text((65, 150),text,(0,0,0),font=font1)
draw.text((115, 120),text,(0,0,0),font=font2)
draw.polygon(((5, 20), (50, 34), (50, 6)), fill=0)
img.paste(qrc, (80,25))

img.show()

#img.save("image.png", dpi = (300,300))

最佳答案

您需要为所有要绘制的元素设置相对(标签)坐标和大小(以厘米为单位),然后计算相应的图像坐标和大小(以像素为单位)w.r.t.所需的分辨率。这会以某种方式变得麻烦,但我想不出另一种独立于分辨率的方法。

在下文中,我省略了整个 QR 码,以确保内容至少具有一点可读性。

为了比较,您的代码(没有二维码)在我的机器上生成了这张图片:

如果我在 Photoshop 中打开该图像,它显示 9.7 cm x 7.2 cm at 72 dpi。如果我手动计算分辨率,我将得到以下结果:

275 pixels / 7.5 cm * (2.54 cm/inch) = ca. 93 dpi
204 pixels / 5.5 cm * (2.54 cm/inch) = ca. 94 dpi

稍后我们将需要 94 dpi。

我根据您的原始图像估算了相对(标签)坐标和大小。

现在,首先让我们看一下整个代码:

from PIL import Image, ImageDraw, ImageFont

# Set up parameters
w_cm, h_cm = (7.5, 5.5)             # Real label size in cm
res_x, res_y = (300, 300)           # Desired resolution
res_y_old = 94                      # Old y resolution (204 / 5.5 * 2.54)

# Inch-to-cm factor
f = 2.54

# Determine image size w.r.t. resolution
w = int(w_cm / f * res_x)
h = int(h_cm / f * res_y)

# Create new image with proper size
img = Image.new('RGB', (w, h), color=(220, 220, 220))

# Draw elements
draw = ImageDraw.Draw(img)


def draw_text(x_cm, y_cm, font_size):
    font = ImageFont.truetype('arial.ttf', int(font_size / (res_y_old / res_y)))
    x, y = (int(x_cm / f * res_x), int(y_cm / f * res_y))
    draw.text((x, y), 'test', (0, 0, 0), font=font)


# Draw texts
draw_text(1.875, 4, 25)
draw_text(3.15, 3.25, 60)

# Polygon
coords_cm = [(0.15, 0.5), (1.35, 0.9), (1.35, 0.1)]
coords = [(int(c[0] / f * res_x), int(c[1] / f * res_y)) for c in coords_cm]
draw.polygon(tuple(coords), fill=(0, 0, 0))

# Save image
img.save('image.png', dpi=(res_x, res_y))

然后,让我们看看输出:

如果我在 Photoshop 中打开该图像,它显示 7.5 cm x 5.5 cm at 300 dpi,这正是我们想要的。

关于字体大小:我想,您手动设置这些字体大小以获得特定的外观。不幸的是,以磅为单位的字体大小被调整为在显示器上具有一定的高度,但它们不会缩放以进行打印(或“打印”图像)。这就是为什么,我们需要缩放字体 w.r.t。旧分辨率和新分辨率,以保持原始图像所需的文本外观。

其他一切都是重复转换相对坐标和大小。如果需要进一步的解释,请随时询问!

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.5
Pillow:      8.1.0
----------------------------------------

https://stackoverflow.com/questions/62690745/

相关文章:

azure - 如何使用 terraform 创建 azure 事件网格系统主题?

java - Bootstrap 类路径未与 -source 8 一起设置

python-3.x - 无法在 Python 3.8 上运行 Supervisor

javascript - 在 Chrome 中将下/上填充应用于具有最小值和最大值的 "input

jsf - Primefaces Dynaform 奇怪的行为与 f :validateLength

python - 比较两个列表,如果相等则替换第三个列表中的值

oracle - 如何使用 UTF8 作为国家字符集在 docker 中创建 Oracle 数据库?

selenium - AWS Lambda 中的 Chrome Headless 返回空白页面

azure - 雪花 - Azure 事件目录集成

typescript - TypeScript 中任意数量类型的非析取联合