使用Python的PIL,如何在加载图像之前设置DPI? [英] With Python`s PIL, how to set DPI before loading an image?

查看:1952
本文介绍了使用Python的PIL,如何在加载图像之前设置DPI?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用PIL打开(Illustrator).eps文件,进行一些更改并保存。我想将文档设置为300 dpi,将颜色模式设置为cmyk ,然后再打开,创建或解释对象。

I was trying to use PIL to open an (Illustrator) .eps-file, do some changes and save it. I want to set the document to 300 dpi, and color mode to cmyk before opening, creating or interpreting the object.

首先我尝试了与PythonMagick相同,它的工作原理如下:

First I tried the same with PythonMagick and it worked like this:

import PythonMagick
# That's NOT what I want
img72 = PythonMagick.Image()
img_file = 'epstest.eps'
img.read(img_file)
img_dens = img72.density()
print 'W: %d, H: %d' % (img.size().width(), img.size().height())
# W: 403, H: 2475 <-- See here
print 'Density Width: %r' % img_dens.width() # 72
print 'Density Height: %r' % img_dens.height() # 72

# THAT is what I want
img300 = PythonMagick.Image()
img_file = 'epstest.eps'
img300.density('300')      # set density / resolution
img300.read(img_file)      # opens with defined density
img_dens = img300.density()
print 'W: %d, H: %d' % (img.size().width(), img.size().height())
# W: 1679, H: 10312 <-- See here!
print 'Density Width: %r' % img_dens.width() # 300
print 'Density Height: %r' % img_dens.height() # 300

PythonMagick的问题:转换颜色模式不起作用,所以我尝试使用PIL,我更喜欢它:

Problem with PythonMagick: Converting Color Modes is not working, so i tried the same with PIL, which I would prefer:

from PIL import Image

img = Image.open('epstest.eps')

我知道可以在保存时设置dpi。

I know that it is possible to set dpi while saving.

给那个没有工作:

img = Image() # TypeError: 'module' object is not callable
img = Image.new() # TypeError: new() takes at least 2 arguments (0 given)
# .new() would create a different object anyway..
img = Image.open('epstest.eps', dpi = 300)
img = Image.open('epstest.eps', dpi = (300, 300) )
# After opening an Image
img.load(dpi=(300,300))

关于输入:我的.eps文件 - 我f它用72dpi解释(似乎是PIL默认值)它以403x2475 px结束,300dpi它应该是1677x10311 px。此外,.eps文件不包含预览位图,也不包含任何位图数据。只有2种颜色(黑色和白色),普通矢量。制作大量以颜色分隔的.eps文件的目录会很有用。

Regarding the input: My .eps file - if it is interpreted with 72dpi (seems to be PIL default) it ends up with 403x2475 px, with 300dpi it should be 1677x10311 px. Also, the .eps-file does not contain a preview-bitmap, nor any bitmap-data. Only 2 colors (black and white), plain vectors. It would be useful to make a catalogue of a huge amount of color-separated .eps-files.

关于输出:将是一个png。

Regarding the output: will be a png.

非常感谢Paulo - 这是他的解决方案,只有很小的变化:

Many thanks to Paulo - this is his solution with very small changes:

from PIL import Image
from PIL import EpsImagePlugin
import math
filename = 'epstest.eps'
def open_eps(filename, dpi=300.0):
    img = Image.open(filename)
    original = [float(d) for d in img.size]
    # scale = width / original[0] # calculated wrong height
    scale = dpi/72.0            # this fixed it
    if dpi is not 0:
        img.load(scale = math.ceil(scale))
    if scale != 1:
        img.thumbnail([round(scale * d) for d in original], Image.ANTIALIAS)
    return img

img = open_eps(filename, dpi=300.0)
img.save('pil_test.png', dpi=(300.0, 300.0))


推荐答案

AFAIK虽然可以包含嵌入式位图和预览缩略图,但EPS是一种基于矢量的格式。如果以位图格式生成输出,则设置DPI才有意义。

AFAIK, while it can contain embedded bitmaps and a preview thumbnail, EPS is a vector-based format. It only makes sense to set DPI if you are generating output in a bitmap format.


你是对的 - 我正在尝试生成位图来自eps的图片。但是打开(解析?)具有特定分辨率的.eps文件确定了实际的像素大小(给定一定的文档大小)。 PythonMagick做得对,但我想尽可能使用PIL。 - OP

You are right - I am trying to generate a bitmap picture from the eps. But opening (parsing?) an .eps-file with a certain resolution determines the actual pixel-size (given a certain document size). PythonMagick does this right but i would like to use PIL if possible. – OP

这是因为PythonMagick中的EPS驱动程序将EPS转换为输入上的位图表示(记住IM,底层库,是一个'光栅图像处理器') - 在PIL中,EPS驱动程序也可以写入EPS图像。

That is because the EPS driver in PythonMagick converts the EPS to a bitmap representation on input (remember IM, the underlying library, is a 'raster image processor') - while in PIL the EPS driver can also write EPS images.

请参阅关于矢量图像的一句话格式在ImageMagick中:

See "A word about Vector Image formats" in ImageMagick:


为什么这很重要?因为IM是一个光栅图像处理器,虽然它可以读取或写入以其中一种矢量格式存储的图像,但它通过将图像转换为内部光栅图像和从内部光栅图像转换图像来实现。
因此,如果您尝试将图像从矢量格式转换为另一种矢量格式,IM将基本上以当前定义的分辨率或密度光栅化此图像,这有望(但不太可能)适合您的输出设备打算用它。
换句话说,IM的任何输出都不会是真正的矢量格式。虽然它可以将其内部栅格格式转换为矢量格式文件,但结果只是光栅格式图像周围的表面矢量图像包装。除非为输出设备正确定义光栅图像(以正确的分辨率),否则结果将不会特别好。
不幸的是IM的新用途对此一无所知。他们将IM视为可以将PDF转换为Postscript的转换器,在预期的输出设备上生成具有块状混叠效果,褪色颜色或模糊图像的图像,这些图像看起来并不好看。
这对我想说的内容有用...
避免使用ImageMagick将矢量图像转换为矢量图像转换
EG:之间转换格式如:PDF,PS,SVG
换句话说,使用正确的工具来完成正确的工作。对于这种情况,ImageMagick不是正确的工具。

Why is this important? Because IM is a 'raster image processor', and while it can read or write images stored in one of the vector formats it does so by converting the image to and from a internal raster image. Consequently if you are trying to convert a image from a vector format, to another vector format, IM will essentially rasterize this image at the currently defined resolution or density which will hopefully (but unlikely) be suitable for the output device you intend to use it on. In other words, any output from IM will never be a true vector format. While it can convert its internal raster format into a vector format file, the result is only a superficial vector image wrapper around an image in raster format. And unless the raster image is defined properly (at the right resolution) for the output device, the result will not be particularly good. Unfortunately new uses to IM do not know anything about this. They see IM as a converter that can convert say PDF to Postscript, producing images with 'blocky' aliasing effects, 'washed out' colors, or blurry images that just do not look good at all, on the intended output device. Which brings use to what I am trying to say... Avoid using ImageMagick for 'Vector Image' to 'Vector Image' conversions EG: converting between formats like: PDF, PS, SVG In other words, use the right tool for the right job. And for this situation, ImageMagick is not the right tool.

另请参阅关于 PIL上的EPS


PIL识别EPS包含图像数据的文件,可以读取包含嵌入式光栅图像的文件(ImageData描述符)。如果Ghostscript可用,也可以读取其他EPS文件。 EPS驱动程序也可以写EPS图像

[Update 1]

[Update 1]

来自枕头文档的信息在PIL文档中缺少


如果Ghostscript可用,您可以使用以下参数调用load()方法影响Ghostscript呈现EPS的方式

If Ghostscript is available, you can call the load() method with the following parameter to affect how Ghostscript renders the EPS

影响合成栅格化图像的比例。如果EPS建议以100px x 100px渲染图像,则将此参数设置为2将使Ghostscript渲染200px x 200px图像。保留边界框的相对位置:

Affects the scale of the resultant rasterized image. If the EPS suggests that the image be rendered at 100px x 100px, setting this parameter to 2 will make the Ghostscript render a 200px x 200px image instead. The relative position of the bounding box is maintained:



im = Image.open(...)
im.size #(100,100)
im.load(scale=2)
im.size #(200,200)

[更新2]

与我的初步猜测相反,PIL还会对图像进行栅格化处理。当我保存为EPS时,它只是围绕位图创建了一个包装器。根据OP,默认分辨率在他的环境下似乎是72 ppi。

Contrary to my initial guess, PIL also rasterizes the image. When I saved as EPS it just made a wrapper around a bitmap. According to the OP the default resolution seems to be 72 ppi at his environment.

如果你知道默认分辨率是72 ppi(每英寸像素数),计算比例您想要的任何密度都是一个简单的比例 - 给定 r 作为您想要的分辨率, s 是比例: 1:s = 72:r ergo:

if you know the default resolution is 72 ppi (pixels per inch), calculating the scale for any density you want is a matter of simple proportion - given r as the resolution you want, s is the scale: 1 : s = 72 : r ergo:

im.load(scale=300.0/72.0)

可能最好只指定所需的宽度而不是分辨率 - 例如,如果你想要1677像素宽:

May be it is best if you just specify the desired width instead of the resolution - for example if you want to have it 1677 pixels wide:

def open_eps(filename, width=None):
    original_width = float(Image.open(filename).size[0])
    im = Image.open(filename)
    if width is not None:
        im.load(scale=width/original_width)
    return im

im = open_eps('testfile.eps', 1677)

所以最后的答案是:虽然没有要指定的内置参数加载EPS文件时所需的ppi分辨率,您可以使用scale参数以您想要的任何分辨率加载它。如果你足够关心,我猜枕头维护者会很高兴收到PR。

So the final answer is: although there is no built-in parameter to specify the desired resolution in ppi while loading an EPS file, you can use the scale parameter to load it at any resolution you want. If you care enough, I guess the Pillow maintainers would be glad to receive a PR for this.


Paolo,方式很好,但看起来scale只接受普通整数... 4,166666667(300.0 / 72.0)舍入为4。

Paolo, the way is good, but it looks like scale is only accepting plain integers... 4,166666667 (300.0/72.0) is rounded to 4.

因为没有测试我感到很遗憾。

Shame on me for not testing.

def open_eps(filename, width=None):
    original = [float(d) for d in Image.open(filename).size]
    scale = width / original[0]
    im = Image.open(filename)
    if width is not None:
        im.load(scale=math.ceil(scale))
    if scale != 1:
        im.thumbnail([int(scale * d) for d in original], Image.ANTIALIAS)
    return im

im = open_eps('testfile.eps', 1677)

不确定我是否应该使用 math.round 而不是 int 但你明白了。

Not sure if I should use math.round instead of int but you got the idea.

这篇关于使用Python的PIL,如何在加载图像之前设置DPI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆