Python读取图片属性信息的实现方法


Posted in Python onSeptember 11, 2016

本文是利用Python脚本读取图片信息,有几个说明如下:

     1、没有实现错误处理

     2、没有读取所有信息,大概只有 GPS 信息、图片分辨率、图片像素、设备商、拍摄设备等

     3、简单修改后应该能实现暴力修改图片的 GPS 信息

     4、但对于本身没有 GPS 信息的图片,实现则非常复杂,需要仔细计算每个描述符的偏移量

脚本运行后,读取结果如下

Python读取图片属性信息的实现方法
脚本读取的信息

这里和 Windows 属性查看器读到的内容完全一致

Python读取图片属性信息的实现方法
图片信息1

Python读取图片属性信息的实现方法
图片信息2

源码如下

# -*- coding:utf-8 -*-
import binascii

class ParseMethod(object):
  @staticmethod
  def parse_default(f, count, offset):
    pass

  @staticmethod
  def parse_latitude(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)

    latitude = [0,0,0]
    for i in xrange(count):
      byte = f.read(4)
      numerator = byte.encode('hex')

      byte = f.read(4)
      denominator = byte.encode('hex')

      latitude[i] = float(int(numerator, 16)) / int(denominator, 16)


    print 'Latitude:\t%.2f %.2f\' %.2f\"' % (latitude[0], latitude[1], latitude[2])
    f.seek(old_pos)  


  @staticmethod
  def parse_longtitude(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)

    longtitude = [0,0,0]
    for i in xrange(count):
      byte = f.read(4)
      numerator = byte.encode('hex')

      byte = f.read(4)
      denominator = byte.encode('hex')

      longtitude[i] = float(int(numerator, 16)) / int(denominator, 16)


    print 'Longtitude:\t%.2f %.2f\' %.2f\"' % (longtitude[0], longtitude[1], longtitude[2])
    f.seek(old_pos) 

  @staticmethod
  def parse_make(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)
    byte = f.read(count)
    a = byte.encode('hex')
    print 'Make:\t\t' + binascii.a2b_hex(a)
    f.seek(old_pos) 

  @staticmethod
  def parse_model(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)
    byte = f.read(count)
    a = byte.encode('hex')
    print 'Model:\t\t' + binascii.a2b_hex(a)
    f.seek(old_pos)     

  @staticmethod
  def parse_datetime(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)
    byte = f.read(count)
    a = byte.encode('hex')
    print 'DateTime:\t' + binascii.a2b_hex(a)
    f.seek(old_pos)

  # rational data type, 05
  @staticmethod
  def parse_xresolution(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)

    byte = f.read(4)
    numerator = byte.encode('hex')
    byte = f.read(4)
    denominator = byte.encode('hex')
    xre = int(numerator, 16) / int(denominator, 16)

    print 'XResolution:\t' + str(xre) + ' dpi'
    f.seek(old_pos)

  @staticmethod
  def parse_yresolution(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)

    byte = f.read(4)
    numerator = byte.encode('hex')
    byte = f.read(4)
    denominator = byte.encode('hex')
    xre = int(numerator, 16) / int(denominator, 16)

    print 'YResolution:\t' + str(xre) + ' dpi'
    f.seek(old_pos)

  @staticmethod
  def parse_exif_ifd(f, count, offset):
    old_pos = f.tell()
    f.seek(12 + offset)

    byte = f.read(2)
    a = byte.encode('hex')    
    exif_ifd_number = int(a, 16)

    for i in xrange(exif_ifd_number):
      byte = f.read(2)
      tag_id = byte.encode('hex')
      #print tag_id,

      byte = f.read(2)
      type_n = byte.encode('hex')
      #print type_n,

      byte = f.read(4)
      count = byte.encode('hex')
      #print count,

      byte = f.read(4)
      value_offset = byte.encode('hex')
      #print value_offset

      value_offset = int(value_offset, 16)
      EXIF_IFD_DICT.get(tag_id, ParseMethod.parse_default)(f, count, value_offset)

    f.seek(old_pos)  

  @staticmethod
  def parse_x_pixel(f, count, value):
    print 'X Pixels:\t' + str(value)

  @staticmethod
  def parse_y_pixel(f, count, value):
    print 'y Pixels:\t' + str(value)

  @staticmethod
  def parse_gps_ifd(f, count, offset):
    old_pos = f.tell()    
    f.seek(12 + offset)
    byte = f.read(2)
    a = byte.encode('hex')  
    gps_ifd_number = int(a, 16)

    for i in xrange(gps_ifd_number):
      byte = f.read(2)
      tag_id = byte.encode('hex')
      #print tag_id,

      byte = f.read(2)
      type_n = byte.encode('hex')
      #print type_n,

      byte = f.read(4)
      count = byte.encode('hex')
      #print count,

      byte = f.read(4)
      value_offset = byte.encode('hex')
      #print value_offset

      count = int(count, 16)
      value_offset = int(value_offset, 16)
      GPS_IFD_DICT.get(tag_id, ParseMethod.parse_default)(f, count, value_offset)

    f.seek(old_pos) 

IFD_dict = {
  '010f' : ParseMethod.parse_make ,
  '0110' : ParseMethod.parse_model ,
  '0132' : ParseMethod.parse_datetime ,
  '011a' : ParseMethod.parse_xresolution ,
  '011b' : ParseMethod.parse_yresolution ,
  '8769' : ParseMethod.parse_exif_ifd ,
  '8825' : ParseMethod.parse_gps_ifd
}

EXIF_IFD_DICT = {
  'a002' : ParseMethod.parse_x_pixel ,
  'a003' : ParseMethod.parse_y_pixel
}

GPS_IFD_DICT = {
  '0002' : ParseMethod.parse_latitude ,
  '0004' : ParseMethod.parse_longtitude
}


with open('image.jpg', 'rb') as f:
  byte = f.read(2)
  a = byte.encode('hex')
  print 'SOI Marker:\t' + a

  byte = f.read(2)
  a = byte.encode('hex')
  print 'APP1 Marker:\t' + a

  byte = f.read(2)
  a = byte.encode('hex')
  print 'APP1 Length:\t' + str(int(a, 16)) + ' .Dec'

  byte = f.read(4)
  a = byte.encode('hex')
  print 'Identifier:\t' + binascii.a2b_hex(a)

  byte = f.read(2)
  a = byte.encode('hex')
  print 'Pad:\t\t' + a 

  print 

  print 'Begin to print Header.... '
  print 'APP1 Body: '

  byte = f.read(2)
  a = byte.encode('hex')
  print 'Byte Order:\t' + a  

  byte = f.read(2)
  a = byte.encode('hex')
  print '42:\t\t' + a 

  byte = f.read(4)
  a = byte.encode('hex')
  print '0th IFD Offset:\t' + a 

  print 'Finish print Header'

  print 'Begin to print 0th IFD....'
  print
  #print 'Total: ',
  byte = f.read(2)
  a = byte.encode('hex')
  interoperability_number = int(a, 16)
  #print interoperability_number


  for i in xrange(interoperability_number):
    byte = f.read(2)
    tag_id = byte.encode('hex')
    #print tag_id,

    byte = f.read(2)
    type_n = byte.encode('hex')
    #print type_n,

    byte = f.read(4)
    count = byte.encode('hex')
    #print count,

    byte = f.read(4)
    value_offset = byte.encode('hex')
    #print value_offset

    count = int(count, 16)
    value_offset = int(value_offset, 16)

    # simulate switch
    IFD_dict.get(tag_id, ParseMethod.parse_default)(f, count, value_offset)


  print
  print 'Finish print 0th IFD....'

总结

利用Python读取图片属性信息的实现方法到这就基本结束了,大家都学会了吗?希望这篇文章对大家的学习或者工作带来一定的帮助,

Python 相关文章推荐
Python实现的检测网站挂马程序
Nov 30 Python
Python利用Nagios增加微信报警通知的功能
Feb 18 Python
Python使用迭代器打印螺旋矩阵的思路及代码示例
Jul 02 Python
python中类变量与成员变量的使用注意点总结
Apr 29 Python
Python 将RGB图像转换为Pytho灰度图像的实例
Nov 14 Python
简述Python2与Python3的不同点
Jan 21 Python
Python解决抛小球问题 求小球下落经历的距离之和示例
Feb 01 Python
python实现通过队列完成进程间的多任务功能示例
Oct 28 Python
Ranorex通过Python将报告发送到邮箱的方法
Jan 12 Python
Python双链表原理与实现方法详解
Feb 22 Python
基于Python绘制个人足迹地图
Jun 01 Python
Python数据分析之绘图和可视化详解
Jun 02 Python
python开发环境PyScripter中文乱码问题解决方案
Sep 11 #Python
基于asyncio 异步协程框架实现收集B站直播弹幕
Sep 11 #Python
asyncio 的 coroutine对象 与 Future对象使用指南
Sep 11 #Python
Python中使用asyncio 封装文件读写
Sep 11 #Python
Python 如何访问外围作用域中的变量
Sep 11 #Python
Python优化技巧之利用ctypes提高执行速度
Sep 11 #Python
Python 中的with关键字使用详解
Sep 11 #Python
You might like
Smarty Foreach 使用说明
2010/03/23 PHP
PHP插入排序实现代码
2013/04/04 PHP
php创建多级目录的方法
2015/03/24 PHP
Js 订制自己的AlertBox(信息提示框)
2009/01/09 Javascript
javascript arguments使用示例
2014/12/16 Javascript
使用jQuery+EasyUI实现CheckBoxTree的级联选中特效
2015/12/06 Javascript
你知道setTimeout是如何运行的吗?
2016/08/16 Javascript
jQuery 选择器(61种)整理总结
2016/09/26 Javascript
js以分隔符分隔数组中的元素并转换为字符串的方法
2016/11/16 Javascript
微信小程序 获取session_key和openid的实例
2017/08/17 Javascript
javascript使用正则实现去掉字符串前面的所有0
2018/07/23 Javascript
JS多个异步请求 按顺序执行next实现解析
2019/09/16 Javascript
Vue常用的全选/反选的示例代码
2020/02/19 Javascript
Node.js API详解之 repl模块用法实例分析
2020/05/25 Javascript
JavaScript语法约定和程序调试原理解析
2020/11/03 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
[13:18]《一刀刀一天》之DOTA全时刻21:详解TI新赛制 A队再露獠牙
2014/06/24 DOTA
[01:57]2018DOTA2亚洲邀请赛赛前采访-iG
2018/04/03 DOTA
python如何通过protobuf实现rpc
2016/03/06 Python
python验证码识别的示例代码
2017/09/21 Python
mac安装scrapy并创建项目的实例讲解
2018/06/13 Python
python图形开发GUI库wxpython使用方法详解
2020/02/14 Python
利用Python中的Xpath实现一个在线汇率转换器
2020/09/09 Python
pycharm 实现光标快速移动到括号外或行尾的操作
2021/02/05 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
2021/03/04 Python
New delete 与malloc free 的联系与区别
2013/02/04 面试题
经销商培训邀请函
2014/01/21 职场文书
《小山羊和小灰兔》教学反思
2014/02/19 职场文书
自我鉴定标准格式
2014/03/19 职场文书
心理健康日活动总结
2014/05/08 职场文书
会计求职信范文
2014/05/24 职场文书
2014年学校工作总结
2014/11/20 职场文书
青年教师听课心得体会
2016/01/15 职场文书
《日月潭》教学反思
2016/02/20 职场文书
2016年小学“感恩教师”主题队日活动总结
2016/04/01 职场文书
python APScheduler执行定时任务介绍
2022/04/19 Python