JPEG图片解析

Preface

之前做了一些涉及对后缀为.JPEG格式的图片的解析工作,虽然最终证明是努力错了方向,但是对.JPEG图片解析也学到一些,整理一下,以备不时之需,同样也希望给有这个需求的人一定帮助。

XMP&Exif

这两种一般是我们常见的所谓的图片的“信息”,一般情况下,对与原始图片,我们单击右键属性,弹出来的相关信息即是储存在这两个文件中间。

Exif(Exchangeable image file format)与XMP(Extensible Metadata Platform)可以简单的理解XMP存储比Exif更多的信息,很多信息可以以XMP的形式存储于图片中,使用python3,两者分别可以使用exifread,以及libxmp进行相应信息读取:

#get the exif info from the image
def exif(infile):
    import sys
    import exifread
    image_content = open(infile, 'rb')
    tags = exifread.process_file(image_content)
    if tags is None:
        print('Could not open ' + infile)
        sys.exit(1)

    image_content.close()
    return tags
#read the relevant xmp information
 
def xmp_info(infile):
    from libxmp import XMPFiles, consts
    try:
        xmpfile = XMPFiles(file_path=infile, open_forupdate=True)
        xmp = xmpfile.get_xmp()
        return xmp
    except:
        print('Unable to get xmp information')

对于Exif信息,可以使用piexif进行相应编辑,例如可以将exif信息进行转移:

import piexif
piexif.transplant(src, dst)

可以参考包的相关描述

piexif.load(filename) - Get exif data as dict.
piexif.dump(exif_dict) - Get exif as bytes.
piexif.insert(exif_bytes, filename) - Insert exif into JPEG, or WebP.
piexif.remove(filename) - Remove exif from JPEG, or WebP.
piexif.transplant(filename, filename) - Transplant exif from JPEG to JPEG.

Marker

大部分的时候,对图像的一些简单信息提取,或者相应编辑,使用exif以及xmp中的metadata足以应付。对于图像更深度信息提取,需要对图像本身的结构做一定了解。所有的文件,不管是图片还是其他,都是数据,对JPEG文件而言,其使用了一些特定的字符来进行其数据的标记,即所谓的markers,一副图片的完整数据结构如下所示:

SOI(0xFFD8)代表Start Of Image,因此,所有的图片数据开始的字符均是FFD8。 

EOI(0xFFD9)代表End Of Image,一般图片的结尾应该是FFD9,但可能存在需要将一些额外信息写入图片,这种情况下,在FFD9之后还会存在其他markers。 

对于不同markers代表意思。详见此文章:List of JPEG Markers

狭义上,我们所关注的图片为图中红色部分,而广义部分则是包括header+payload,而我们所谓的exif或者xmp其实就是其头信息的一部分。而不同的markers(即图片中括号内FFD8等)是由2个字节组成。读取图片并以16进制显示:

#read images by bytes and return as in Hexadecimal System
 
def read_bytes(image): 
    with open(image, 'rb') as f:
        data = f.read()
    return data.hex()

在传统一般的ffd8-ffd9外还有ffe2—ffe5四个marker段,这四个markers即常被称为APP2-APP5(application segment),这四段一般为自定义段,一般的都是用户写入一些自定义的信息或者扩展信息。而我么熟悉的exif或者xmp一般即写在ffe1内,关于头文件内部的详细一些介绍,可以查看这篇文章:JPEG文件格式解析(一)Exif与JFIF

JPEG图片解析代码:

def image_parse(image):
    # read image and save as bytes in a list
    with open(image, 'rb') as f:
        image_data = f.read()
        image_data = ['%x' % image_data[i] for i in range(len(image_data))]

    # index = ['d8', 'e1', 'db', 'c4', 'c0', 'da', 'd9', 'e2', 'e3', 'e4', 'e5']
    # parse the image markers and save in dictionary
    tagmarker = dict()
    tag = ''
    tag_start = False
    data_start = False
    for i, b in enumerate(image_data):
        if len(b) == 1:
            b = '0' + b
        if b == 'ff':
            tag_start = True
            continue
        if tag_start:
            if b != 'ff' and (b != '00'):
            #if b in index:
                tag = 'ff' + b
                if not tag in tagmarker:
                    tagmarker[tag] = list()
                tag_start = False
                data_start = True
                continue
            else:
                tag_start = False
                tagmarker[tag].append('ff')
        if data_start:
            tagmarker[tag].append(b)

    # list the markers
    for tag, arr in tagmarker.items():
        s = len(arr)
        if s == 0:
            print(tag)
            continue
        print("{}:\t{}\tbytes".format(tag, s))
    # pdb.set_trace()
    return tagmarker

上述代码需要一定的优化,并非所有ff代表的就是marker开始,使用该方法粗略找到之后,可以再进行一次筛选(即自定义index即可以)。或者进行相应的优化即可。(由于这个也不是工作重点,所以代码也没进行普遍性优化),另:这段代码是在哪里copy来的,也不太记得了,所以就没参考了。

下图即为实际图片解析后结构:

ffd8
ffe1:	9364	bytes
ffdb:	432	bytes
ffc4:	1382	bytes
ffc0:	69	bytes
ffda:	228997	bytes
ffd9
ffe2:	180	bytes
ffe3:	655382	bytes
ffe4:	2561	bytes
ffe5:	32540	bytes

Refer

  1. 图像元数据(Metadata) 及 Exif信息分析
  2. piexif · PyPI
  3. python修改图片exif信息
  4. JPEG头部解析
  5. JPEG文件格式解析(一) Exif 与 JFIF
  6. List of JPEG Markers
  7. Corrupt JPEG Files and how to fix them
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在线将16进制转换为JPEG图片,首先需要了解JPEG图片的文件结构和编码方式。 JPEG是一种常见的图像压缩格式,它将图片分为若干个8x8的像素块,然后对每个块进行离散余弦变换(DCT)和量化。转换后的结果使用熵编码进行压缩,最终生成JPEG图片。 在将16进制转换为JPEG图片的过程中,需要将16进制数据按照JPEG文件的结构进行解析和转换。 首先,需要将16进制数据转换为二进制数据。这可以通过将每个16进制的字符转换为二进制的4位数来实现。然后,将得到的二进制数据按照JPEG文件结构进行拼接。 JPEG文件的结构由多个段(segment)组成,其中最重要的段是图像数据段(Image Data Segment),它包含了压缩后的图像数据。 将拼接好的二进制数据按照JPEG文件结构分割为各个段,并进行DCT和量化逆过程,得到还原后的像素块数据。 最后,将还原后的像素块数据重新拼接为完整的图像,即可得到转换后的JPEG图片。 在线实现16进制转换为JPEG图片可以借助一些编程语言的库或者在线工具。在使用工具时,只需将16进制数据输入工具,然后选择转换的方式和输出格式,即可在线将16进制转换为JPEG图片。 总之,要在线将16进制转换为JPEG图片,需要了解JPEG文件结构和编码方式,并将16进制数据按照文件结构进行解析和转换,最后重新拼接为完整的JPEG图片

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值