0

我目前正在我希望创建的应用程序中对功能进行原型设计,这需要能够读取/修改/写入 jpeg 文件的元数据。

我认为可能适用的一种方法是使用 12-monkeys java API 读取所有段,修改我感兴趣的元数据段,并将所有段(其中大部分未修改)写回新文件。

在我的原型设计中,我遇到了一个障碍,它引发了一个问题,我不得不承认,主要针对 API 的作者。如果您不是作者,也可以提供一些见解,我当然不会拒绝;)

这是我的代码的摘录:

    ImageInputStream streamMoto = ImageIO.createImageInputStream(file1);

    /*
        Prove, for testing/learning purposes, that this is a jpeg file
     */
    streamMoto.mark();
    final int foundFileType = streamMoto.readUnsignedShort();

    if (JPEG_FILE_ID==foundFileType) { // yes, continue... because we have a jpeg file
        streamMoto.reset(); // back to the very start

        // Here, the plan is to get ALL the JPEGSegments, so that we can
        // 1. iterate over each
        // 2. write non-relevant simply to new file (non-meta-data)
        // 3. note the meta-data segments and modify as (per application requirements) necessary (in my case, I want to edit description and tags/labels)
        // 4. after modifying meta-data segments, write the modified metadata segments, appending, to the new file
        // 5. At the end, we should have a new file, pretty much identical to the first (encoding and all) with ONLY meta-data modified
        streamMoto.mark();
        try {
            List<JPEGSegment> allSegments = JPEGSegmentUtil.readSegments(streamMoto, JPEGSegmentUtil.ALL_SEGMENTS);

            // Ahh, but wait! At this stage, in specifying 'ALL_SEGMENTS' I see a discrepancy in what I see in the resulting list of JPEGSegments (only 10 segments)
            // and my, very likely faulty, understanding of what I should see in this list. Namely, a whole bunch of following FF DA, FF C4 segments which I suppose are the 
            // main image data. 
            System.out.println("");

        } finally {
            streamMoto.reset();
        }
    }

xcvxvx

在测试上面的代码时,我看到了 10 个段,如下所示:

FF E0  00 10   the JFIF marker, length 16 decimal
FF E1  07 A2   the Exif marker, length 1954 decimal
FF E1  OC 39   an adobe XMP section, length 3129 decimal
FF ED  00 82   some data in a Photoshop section, length 130 decimal
FF DB  00 43   unknown data; data available
FF DB  00 43   binary
FF C2  00 11   binary
FF C4  00 14   binary
FF C4  00 14   binary
FF DA  00 0c   binary

我尝试对 JPEG/Exif 文件的结构进行一些研究,并一直在阅读规范;例如,显然图像数据是文件中最后一个“FF D9”标记之前的最后一件事。如何读取(或至少找到)每个标记(各种标记,如 FFE0、FFE1、FFC2 等),其后跟 4 个字节,指示该标记段的长度。在像这样手动阅读文件时(例如,使用 Bless Hex 编辑器),我阅读了与该库相同的所有段......直到

上面列表中显示的最后一个“FF DA”标记之后,我看到(在文件中)一大堆其他标记,我假设(我需要做更多的研究)实际的主图像数据。尽管如此,它似乎仍被分成不同的部分,可以使用与上述相同的规则(读取标记、读取长度、跳过长度、查找下一个标记)进行排序,除了“FF DA”段之后的下一个标记是并不总是直接在该标记的指定长度之后。在阅读另一篇stackoverflow文章的一些建议时(对不起,我现在已经丢失了),有人被告知只需向前跳,直到找到下一个'FFxx'标记(在我的情况下为FFC4)并继续。

现在,我的问题是,如果这些是标记或片段(我仍然对术语感到困惑),为什么图书馆不选择它们?

好吧,我大概可以猜到答案;

它们不是通常意义上的标记……它们是主要的图像数据……这就是原因。

所以我的后续问题是;

  1. 那么,我是否可以在某个点(什么点)只考虑一个块的其余数据,并且由于我不需要修改它,所以将其写在所有段的末尾?

  2. 如何最好地读取该数据块(无需重置流并从头开始再次读取整个图像?

  3. 我可能会搞错这一切,但我一直在寻找一种有效的方法来生成带有修改后的元数据的图像文件,别无其他!我知道在使用 java 库读取整个文件然后重新编写它时,您基本上是在重新编码并更改整个文件。您可能只是在很小程度上降低了图像文件的质量,只是为了修改元数据。我错了吗?我不想要那个!必须有更好的方法(无需从头开始编写我自己的图像阅读器/写入器)!

感谢您的任何建议!

肖恩

4

1 回答 1

0

您面临的问题是,有几种常用的 JPEG 文件格式,它们以不同的方式存储元数据。最初的 JPEG 标准没有定义文件格式。创建 JFIF 是为了填补这些空白。Adobe 创建了自己的文件格式。然后JPEG引入了SPIFF格式。然后是相机的EXIF。

于 2019-03-27T15:34:31.907 回答