JPEG 图像的第二个和第三个字节是否始终是 APP0 或 APP1 标记?

发布于 2024-10-26 03:09:19 字数 251 浏览 1 评论 0原文

我已经测试过一些不同的 JPEG 图像。据我所知,第 0 个和第一个字节始终是 0xFF 和 0xD8。

第二个和第三个通常是 0xFF0xE0 ( APP0 ),表示 JFIF 段或 JFIF 扩展段或 0xFF0xE1 ( APP1 ) 表示 EXIF 段。

我的问题:总是这样吗?第二个和第三个字节总是 APP0 或 APP1 吗?

I have a few different JPEG images I've been testing with. As far as I've seen the 0th and first bytes are always 0xFF and 0xD8.

The second and third are usually either 0xFF and 0xE0 ( APP0 ) indicating either a JFIF segment or JFIF extension segment or 0xFF and 0xE1 ( APP1 ) indicating an EXIF segment.

My question: is this always the case? Are the 2nd and 3rd bytes always APP0 or APP1?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

谁的年少不轻狂 2024-11-02 03:09:23

理论上是的。根据 JFIF 规范(pdf),其APP0 部分应位于文件的首位。 Exif 规范 (pdf) 对其要求相同APP1 部分。

但是您不应该指望 APPn 部分的顺序(甚至不存在);那里有疯狂的 JPEG 编写者。从 SOI 开始,阅读各个部分。

In theory, yes. According to the JFIF spec (pdf), its APP0 section should come first in the file. And the Exif spec (pdf) requires the same for its APP1 section.

But you shouldn't count on the order (or even the existance of) APPn sections; there are crazy JPEG writers out there. Start with the SOI and read the sections as they come by.

冷血 2024-11-02 03:09:23

不。有些程序可以删除一些标记。 ImageOptim 就是这样一个程序。您只需要一些标记。该程序还将优化霍夫曼表

No. There are programs that remove some markers. ImageOptim is such a program. You only need some of the markers. This program will also optimise the huffman tables

茶底世界 2024-11-02 03:09:22

通常是的,但是我对 JPEG 的理解是任何段类型都可以遵循标头。

Typically yes, however my understanding of JPEG is that any segment type can follow the header.

半﹌身腐败 2024-11-02 03:09:22

前两个字节是JPEG SOI 标记,因此始终存在。

第二个和第三个字节似乎存储元数据,这可能并不存在于每个 JPEG 中。

进一步阅读

Those first two bytes are the JPEG SOI marker so are always present.

The 2nd and 3rd bytes appear to store meta data, which probably isn't present in every JPEG.

Further Reading.

橘亓 2024-11-02 03:09:22

对于 JFIF 文件,JFIF 标头应该紧跟在 FFD8 之后。 JFIF 标头包含在 APP0 标记内。不过,该规范没有提及任何有关填充的内容。

如果没有 JFIF 标头,我们只能猜测使用的颜色格式。

For a JFIF file, a JFIF header should follow immediately after FFD8. The JFIF header is contained within an APP0 marker. The specification doesn't say anything about padding though.

Without the JFIF header we can only guess what color format is used.

铁轨上的流浪者 2024-11-02 03:09:21

不,当然不必如此。阅读维基百科

据我所知,APPn 段只是应用程序将任意数据嵌入到图像文件中的方法。显然,应用程序通常会利用这一点并将 0xFF 0xEO0xFF 0xE1 字节写入标头,但应用程序完全有可能不这样做 em> 执行此操作并继续处理图像数据。前两个字节(0xFF 和 0xD8)强制的,因为它们是 SOI(图像开始)标记。

No, it certainly doesn't have to be that way. Reading Wikipedia.

As far as I can tell, the APPn segments are just ways for applications to embed arbitrary data into the image file. Obviously, applications commonly take advantage of this and write 0xFF 0xEO or 0xFF 0xE1 bytes into the header, but it would be entirely plausible for an application to not do this and just go on with the image data. The first two bytes (0xFF and 0xD8) are mandatory, as they are the SOI (start-of-image) marker.

寻找我们的幸福 2024-11-02 03:09:21

这里的事情很复杂。由于我目前正在编写一个 javascript 文件标识符,因此我将尝试用 JPEG 的 javascript 对象来回答。
特别是因为这个问题有一个“javascript”标签。

基本答案已经给出(已接受的答案),但这更详细地介绍了如何检查不同的应用程序标记(带有后备)。

到目前为止,JFIF、EXIF、Adobe、Canon 和 Samsung 都有特殊的 APP0(但我们不知道未来会怎样)。因此 js 对象的逻辑是:

如果 SPECS[x].regex 之一匹配,则获胜(第一个获胜)。但如果没有匹配,则父对象(仅 FFd8)获胜。

SPECS 对象提供根据 PRONOM 标识符 - 您可以像这样查看它们

http://apps.nationalarchives.gov.uk/pronom/fmt/'.concat(PUID) [官方]
'http://apps.nationalarchives.gov.uk/pronom/x-fmt/< /a>'.concat(xPUID) [实验]

_FFD8: { 
    SPECS: [
        { 
            PUID: 112, 
            regex: /^FFD8FFE8(.{2})53504946460001/, 
            desc: 'jpeg: Still Picture Interchange Format file (SPIF)',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.00'
            }
        }, 
        { 
            PUID: 44, 
            regex: /^FFD8FFE0(.{2})4A464946000102/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.02',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.02',
            }
        },
        { 
            PUID: 43, 
            regex: /^FFD8FFE0(.{2})4A464946000101/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.01',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.01',
            }
        },
        { 
            PUID: 42, 
            regex: /^FFD8FFE0(.{2})4A464946000100/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.00',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.00',
            }
        },          
        { 
            PUID: 41, 
            xPUID: 398,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323030/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.0',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.0',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 398, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323030/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.0',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.0',
            }
        },              
        { 
            PUID: 41, 
            xPUID: 390,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323130/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.1',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.1',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 390, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323130/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.1',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.1',
            }
        },          
        { 
            PUID: 41, 
            xPUID: 391,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323230/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.2',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.2',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 391, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323230/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.2',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.2',
            }
        }, 
        // specific JPEG (all begin with FFD8FF, map them to PUID 41)
        { 
            PUID: 41, 
            regex: /^FFD8FFED/, 
            desc: 'jpeg: JPG Image File, Adobe JPEG, Photoshop CMYK buffer'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFE2/, 
            desc: 'jpeg: JPG Image File, Canon JPEG, Canon EOS-1D'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFE3/, 
            desc: 'jpeg: JPG Image File, Samsung JPEG, e.g. Samsung D500'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFDB/, 
            desc: 'jpeg: JPG Image File, Samsung JPEG, e.g. Samsung D807'
        }
    ],
    ext: ['JPG', 'JPE', 'JPEG', 'SPF', 'SPIFF'],
    signature: [ 255, 216 ],
    desc: 'jpeg: JPEG File Interchange Format file, App0 marker not known',
    mime: 'image/jpeg',
    specifications: [
        { text:'Specification for the JFIF file format', href:'http://www.w3.org/Graphics/JPEG/jfif3.pdf', type:'W3', format:'pdf' },
        { text:'The JPEG compression specification', href:'http://www.w3.org/Graphics/JPEG/itu-t81.pdf', type:'W3', format:'pdf' },
        { text:'Exchangeable image file format for digital still cameras', href:'http://home.jeita.or.jp/tsc/std-pdf/CP3451C.pdf', type:'vendor', format:'pdf' }
    ], 
    references: [
        { text:'JPEG JFIF W3 Info', href:'http://www.w3.org/Graphics/JPEG/', type:'W3', format:'html' },
        { text:'JPEG.org', href:'http://www.jpeg.org/', type:'info', format:'html' },
        { text:'JPEG Exif App markers', href:'http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html', type:'info', format:'html'}
    ]
}

Things are complicated here. Since I am currently writing a javascript file identifier, I'll try to answer with my javascript object for JPEG.
Especially because the question had a "javascript" tag.

The basic answer is already given (the accepted one) but this is more detailed about how to check the different App markers (with fallback).

There are special APP0s so far for JFIF, EXIF, Adobe, Canon and Samsung (but we don't know about the future). So the logic for the js object is:

If one of the SPECS[x].regex is matched it wins (first one wins). But if nothing is matched, the parent object (only FFd8) wins.

The SPECS object delivers according PRONOM identifiers - you can view them like so

'http://apps.nationalarchives.gov.uk/pronom/fmt/'.concat(PUID) [official]
'http://apps.nationalarchives.gov.uk/pronom/x-fmt/'.concat(xPUID) [experimental]

_FFD8: { 
    SPECS: [
        { 
            PUID: 112, 
            regex: /^FFD8FFE8(.{2})53504946460001/, 
            desc: 'jpeg: Still Picture Interchange Format file (SPIF)',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.00'
            }
        }, 
        { 
            PUID: 44, 
            regex: /^FFD8FFE0(.{2})4A464946000102/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.02',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.02',
            }
        },
        { 
            PUID: 43, 
            regex: /^FFD8FFE0(.{2})4A464946000101/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.01',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.01',
            }
        },
        { 
            PUID: 42, 
            regex: /^FFD8FFE0(.{2})4A464946000100/, 
            desc: 'jpeg: JPEG File Interchange Format file (JFIF), v. 1.00',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                version: '1.00',
            }
        },          
        { 
            PUID: 41, 
            xPUID: 398,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323030/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.0',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.0',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 398, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323030/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.0',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.0',
            }
        },              
        { 
            PUID: 41, 
            xPUID: 390,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323130/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.1',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.1',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 390, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323130/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.1',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.1',
            }
        },          
        { 
            PUID: 41, 
            xPUID: 391,
            regex: /^FFD8FFE1(.{2})45786966000049492A00(.+)009007000400000030323230/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), little endian, v. 2.2',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'little',
                version: '2.2',
            }
        }, 
        { 
            PUID: 41, 
            xPUID: 391, 
            regex: /^FFD8FFE1(.{2})4578696600004D4D002A(.+)900000070000000430323230/, 
            desc: 'jpeg: JPG Image File, using Exchangeable Image File Format (Exif), big endian, v. 2.2',
            regexCapture: [
                { key: 'recordedSignature' }, 
                { key: 'segmentLength', fn: function(h){ return { value:parseInt(h, 16), _val:h.toString() }; } }
            ], 
            valueCapture: {
                endian: 'big',
                version: '2.2',
            }
        }, 
        // specific JPEG (all begin with FFD8FF, map them to PUID 41)
        { 
            PUID: 41, 
            regex: /^FFD8FFED/, 
            desc: 'jpeg: JPG Image File, Adobe JPEG, Photoshop CMYK buffer'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFE2/, 
            desc: 'jpeg: JPG Image File, Canon JPEG, Canon EOS-1D'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFE3/, 
            desc: 'jpeg: JPG Image File, Samsung JPEG, e.g. Samsung D500'
        }, 
        { 
            PUID: 41, 
            regex: /^FFD8FFDB/, 
            desc: 'jpeg: JPG Image File, Samsung JPEG, e.g. Samsung D807'
        }
    ],
    ext: ['JPG', 'JPE', 'JPEG', 'SPF', 'SPIFF'],
    signature: [ 255, 216 ],
    desc: 'jpeg: JPEG File Interchange Format file, App0 marker not known',
    mime: 'image/jpeg',
    specifications: [
        { text:'Specification for the JFIF file format', href:'http://www.w3.org/Graphics/JPEG/jfif3.pdf', type:'W3', format:'pdf' },
        { text:'The JPEG compression specification', href:'http://www.w3.org/Graphics/JPEG/itu-t81.pdf', type:'W3', format:'pdf' },
        { text:'Exchangeable image file format for digital still cameras', href:'http://home.jeita.or.jp/tsc/std-pdf/CP3451C.pdf', type:'vendor', format:'pdf' }
    ], 
    references: [
        { text:'JPEG JFIF W3 Info', href:'http://www.w3.org/Graphics/JPEG/', type:'W3', format:'html' },
        { text:'JPEG.org', href:'http://www.jpeg.org/', type:'info', format:'html' },
        { text:'JPEG Exif App markers', href:'http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html', type:'info', format:'html'}
    ]
}
茶色山野 2024-11-02 03:09:20

不会。例如,有一些相机可以创建不带这些标记或带有其他 APP 标记的 JPEG。你唯一可以依赖的就是 SOI 序列,FF D8,甚至不是所有相机都会产生 EOI。另请注意,存在嵌入 JPEG 的 JPEG - 您可以在图像中嵌套 SOI/EOI。

如果您需要处理原始相机图像中嵌入的 JPEG 数据,有几种模型会生成类似 JPEG 的数据,只能通过稍微放松 jpeg 规范来解析这些数据 - 特别是与转义的 FF 字节相关在数据中。然后你就有了可以生成专有数据的相机,这些数据乍一看看起来像 jpeg 数据(例如索尼的一些“加密”原始格式)

No. There are e.g. several cameras that create JPEGs without these markers, or with other APP markers. The only thing you can rely on is the SOI sequence, FF D8, not even EOI is produced by all cameras. Also be aware that JPEGs with embedded JPEGs exist - you can have nested SOI/EOI within an image.

If you need to deal with embedded JPEG data in raw camera images, several models produce JPEG-like data that can only be parsed by being a bit slack with the jpeg spec - especially in relation to escaped FF bytes in data. And then you have cameras that produce proprietary data that at first glance looks like jpeg data (e.g. some of Sony's "encrypted" raw formats)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文