Image 在不增加文件大小的情况下设置JPG密度(dpi)

Image 在不增加文件大小的情况下设置JPG密度(dpi),image,imagemagick,jpeg,pixel-density,Image,Imagemagick,Jpeg,Pixel Density,我使用(在Windows下)以下命令 magick convert -units pixelsperinch file_in -density 600 file_out 设置JPG图像的dpi(无重采样,因为据我所知,dpi基本上只是一个指定像素大小的标签)。它可以工作,但我不明白为什么它会将文件大小增加几千字节(我的一幅图像最初是1658 kB,现在增加到1717 kB,这是59 kB),而我希望增加,如果有的话,只增加几个字节 我做错什么了吗?是否可以在不增加文件大小的情况下通过命令行(也

我使用(在Windows下)以下命令

magick convert -units pixelsperinch file_in -density 600 file_out
设置JPG图像的dpi(无重采样,因为据我所知,dpi基本上只是一个指定像素大小的标签)。它可以工作,但我不明白为什么它会将文件大小增加几千字节(我的一幅图像最初是1658 kB,现在增加到1717 kB,这是59 kB),而我希望增加,如果有的话,只增加几个字节

我做错什么了吗?是否可以在不增加文件大小的情况下通过命令行(也欢迎使用ImageMagick以外的工具)更改JPG的密度/dpi


提前感谢您提供的任何线索。

试图重现您的问题:

  • Gimp的隔行/渐进JPEG比非隔行版本(也由Gimp生成)小
  • magick convert
    输出的JPEG不是隔行的,实际上比Gimp自己的非隔行的要小一些。该文件大小相同,无论是从隔行扫描版本还是非隔行扫描版本生成的
因此,我认为您正在转换交错/渐进JPEG。请注意,这还表明IM正在对文件进行重新编码,比较Gimp中的原始编码和重新编码显示出显著的差异


在JPEG格式中,H/V定义在标题中以4个字节进行编码,这在任何编程语言中都应该是一个SMOP

您可以更改/设置密度,而无需重新编码文件(从而可能更改其大小或质量),使用更小、更轻、更易于安装的
exiftool
,它“只是”一个Perl脚本:

exiftool -jfif:Xresolution=300 -jfif:Yresolution=300 YourImage.jpg
不同的人将不同的东西称为“密度/分辨率”,因此,如果上面的命令不能满足您的需要,请尝试:

exiftool -XResolution=300 -YResolution=300 YourImage.jpg
尝试使用。在我的JFIF jpg上,这只改变了DPI,没有对图像重新采样。可以找到其他软件建议,但这是唯一一个在不改变图片中任何其他内容的情况下对我有效的建议

然而,我只有一个JFIF jpg,而你的其他评论中似乎有一个Adobe jpg,所以你的里程数可能会有所不同


我使用Windows十六进制编辑器HxD验证了DPI更改,并且没有重新采样,只是查看了xenoid链接的Wikipedia文章中详细介绍的4个字节。一旦你知道什么字节在变化,你可以跳过网站,直接使用十六进制编辑器来设置X和Y DPI

据我所知,有。需要详细说明的问题。基于此,我编写了自己的Python脚本,允许在不重新编码的情况下更改JFIF风格JPEG的DPI设置:

import sys,os

filename = sys.argv[1]
x_density = int(sys.argv[2])
y_density = int(sys.argv[3])

echo = True
if len(sys.argv) > 4:
    if sys.argv[4] == 'quiet':
        echo = False

assert x_density > 0 and x_density < 65536
assert y_density > 0 and y_density < 65536

# JPEG markers
APP0 = bytes.fromhex('FFD8FFE0') # JFIF
APP1 = bytes.fromhex('FFD8FFE1') # EXIF

with open(filename, 'rb+') as f: # 'w+b'
    chunk = f.read(4)
    if chunk == APP0:
        f.seek(2,1) # relative seek
        chunk = f.read(5)
        if chunk == bytes.fromhex('4A46494600'): # JFIF indentfier
            f.seek(2,1) # relative seek
            print('Setting density of ' + os.path.split(filename)[1] + ' to ' + str(x_density) + 'x' + str(y_density) + ' dpi.') if echo else None
            f.write(bytes.fromhex('01'))
            f.write(x_density.to_bytes(2,'big'))
            f.write(y_density.to_bytes(2,'big'))
        else:
            print('File hasn''t got the JFIF indentifier, nothing was done.')
    elif chunk == APP1:
        f.close() # needed otherwise exiftool cannot operate on file
        print('This is an EXIF-JPEG, using exiftool to set DPI...')
        os.system('exiftool -P -overwrite_original -XResolution={} -YResolution={} "{}"'.format(x_density,y_density,filename))
    else:
        print('File is not JFIF nor EXIF, cannot set DPI, nothing was done.')

print('Done.') if echo else None
脚本不会读取完整图像,也不会更改文件长度,它只是直接在JPEG文件上修改几个字节。 此外,没有创建临时/备份副本,因为我希望脚本能够处理硬链接文件,所以JFIF JPEG的整个过程相当快

该脚本能够识别EXIF JPEG,并使用exiftool更改DPI。如果您的计算机中没有安装exiftool,请记住相应地调整脚本。即使安装了exiftool,也要使用此脚本的一个原因是速度;在我的测试中,这个脚本比exiftool快得多


JFIF和EXIF是最常见的JPEG文件格式,但我希望有人能够改进此脚本或报告一种方法,为带有APP14标记的Adobe JPEG设置DPI(无需重新编码),这并不少见。

您能提供一些(简单)关于头中这些字节的参考,以便我可以尝试编写一个片段吗?请参阅(附件0 X密度/Y密度)。请参阅下面Mark Setchell的回答。文件大小出现的原因是Imagemagick将解压并重新压缩JPG。这本身可能会改变文件大小,但特别是如果您的输入JPG未指定其质量,则Imagemagick将以92的高质量级别分配和重新压缩。不同的JPG压缩表在inpu之间t和输出也可能导致差异以及不同的采样因子。因此,您应该使用
magick identification-verbose image.jpg检查输入和输出。还请注意,在Imagemagick 7中,仅使用magick,而不使用magick convert或convert。如果您压缩输入和输出图像并将其存放在其他位置,然后发布链接,以便此论坛不会对它们进行重新编码并可能更改图像,然后我们可以使用
magick identify-verbose image.jpg
@fmw42查看您的图像元数据。以下是dpi更改前后的图像链接:~还要注意,如果我使用JPERAN优化图像,原始dpi将丢失。@fmw42更多测试表明,如果我使用Image Magick更改dpi,在jpegtran无损优化后,文件大小会增加,dpi会丢失,而如果我使用Irfanview(通过命令行)更改dpi,文件大小会减小(可能是因为Irfanview将颜色空间从CMYK转换为sRGB)而且,在jpegtran无损优化后,dpi不会丢失。
@mmj
正如我前面所说的,Imagemagick将解压并重新压缩,即使您只是更改dpi。因此,您希望使用其他一些工具,但不会这样做。解压并重新压缩JPG时,文件大小会发生变化。exiftool看起来很不错sing,但不幸的是,我用我的图像得到了
警告:没有用Adobe APP14创建JPEG格式的JFIF。当然这是我的图像错误(它似乎是Adobe JPG而不是JFIF JPG),尽管如此,我还是能够通过命令行使用Irfanview在不增加大小的情况下更改此类图像的dpi:
I_view32.exe file_in.JPG/dpi=(600600)/convert=file_out.jpg
。Irfanview进行了一些编码/解码,但能够处理AdobeJPG,生成的文件更小。更多测试表明,Irfanview将颜色空间从CMYK转换为sRGB,这似乎减少了文件大小,并允许在jpegtran保留dpi信息的情况下进行无损优化(另见我对问题的评论)
python this_script.py some-image.jpg Xdpi Ydpi [quiet]