如何正确创建指定尺寸和分辨率的新图像(PNG、JPG、JPEG)?

4
我想使用Pillow创建一个PNG图片,该图片用于标签打印。 因此,我尝试使用PIL创建一个新的图片,添加一些文本,一个多边形和一个QR码。 但是,我发现很难获得适当的图像大小(与标签大小相关,即7.5厘米x 5.5厘米)。 我只通过不断尝试才得到了大概的大小(大约为(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))
1个回答

1

您需要为要绘制的所有元素设置相对(标签)坐标和尺寸(以厘米为单位),然后根据所需分辨率计算相应的图像坐标和尺寸(以像素为单位)。这可能会有些麻烦,但我想不到另一种独立于分辨率的方法。

以下是为了保持可读性而省略了整个QR码的内容。

为了比较,您的代码(不包括QR码)在我的机器上生成了此图像:

Comparison

如果我在 Photoshop 中打开那张图片,它会显示尺寸为 9.7 厘米 x 7.2 厘米,分辨率为 72 像素/英寸。如果我手动计算分辨率,将得到以下结果:

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))

现在,让我们看一下输出:

Output

如果我在Photoshop中打开该图像,它会显示300 dpi下的7.5厘米x 5.5厘米,正好是我们想要的。

关于字体大小:我猜您手动设置了这些字体大小以获得特定外观。不幸的是,以点为单位给出的字体大小被调整为在监视器上具有一定高度,但它们不会针对打印(或“打印”图像)进行缩放。因此,我们需要根据旧分辨率和新分辨率来缩放字体,以保持原始图像中所需的文本外观。

其他所有内容都是重复转换相对坐标和大小。如果需要进一步解释,请不要犹豫问!

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接