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

时间:2018-08-05 10:07:18

标签: image imagemagick jpeg pixel-density

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

  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    let text = searchText.trimmingCharacters(in: .whitespacesAndNewlines)

// Create a Timer in this or parent class.
    debounceTimer.invalidate() // just in case this button is tapped multiple times


    // start the timer
    debounceTimer = Timer.scheduledTimer(timeInterval: 0.8, target: self, selector: #selector(self.startSearch(_:)), userInfo: text, repeats: false)
}

func startSearch(_ timer: Timer) {
    if let searchText = timer.userInfo as? String {
        print("Searching: \(searchText)")

        // make your service call here ...
    }
}

设置JPG图像的dpi(据我所知,dpi基本上是不重采样,它只是指定像素大小的标签)。它可以工作,但是我不明白为什么它将文件大小增加了几千字节(我的图像最初从1658 kB扩展到1717 kB,增加了59 kB),而我希望增加(如果有的话)只是几个字节。

我弄错了吗?是否可以在不增加文件大小的情况下更改JPG的密度/ dpi(其他命令行工具也可以)?

预先感谢您提供任何线索。

4 个答案:

答案 0 :(得分:3)

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

exiftool

不同的人将不同的事物称为密度/分辨率,因此,如果以上命令不能满足您的期望/需要/希望/期望,则可以尝试:

exiftool -jfif:Xresolution=300 -jfif:Yresolution=300 YourImage.jpg

答案 1 :(得分:2)

尝试重现您的问题:

  • Gimp的隔行/逐行JPEG小于非隔行版本(也是Gimp制作的)
  • magick convert输出的JPEG不是隔行扫描的,实际上比Gimp自己的非隔行扫描的要小。无论是隔行版本还是隔行版本,该文件的大小都是相同的。

因此,我认为您正在转换隔行/逐行JPEG。请注意,这也表明IM正在重新编码文件,并且比较原始文件和在Gimp中重新编码的文件显示出明显的差异。

在JPEG格式中,H / V定义在标头中以4字节编码,修补应为任何编程语言中的SMOP。

答案 2 :(得分:0)

尝试使用the online tool https://convert.town/image-dpi。在我的JFIF jpg上,这仅更改了DPI,并且没有对图像重新采样。其他软件建议可以在on this Super User question中找到,但这是唯一对我有用的而不更改图像中任何其他内容的建议。

但是,我只有JFIF jpg,而您在其他评论中似乎有Adobe jpg,因此您的里程可能会有所不同。

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

答案 3 :(得分:0)

据我所知,有 several flavors of JPEG fileschange DPI metadata of JFIF flavor are explained here 所需的详细信息。基于此,我编写了自己的 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

用法:

python this_script.py some-image.jpg Xdpi Ydpi [quiet]

该脚本不会读取完整图像,也不会更改文件长度,它只是直接在 JPEG 文件上修改几个字节。 此外,没有制作临时/备份副本,因为我希望脚本能够处理硬链接文件,因此 JFIF JPEG 的整个过程非常快。

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

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