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根据给定文件返回文件名和扩展名的方法
Mar 27 Python
python中numpy的矩阵、多维数组的用法
Feb 05 Python
基于anaconda下强大的conda命令介绍
Jun 11 Python
Python Web编程之WSGI协议简介
Jul 18 Python
Python重新加载模块的实现方法
Oct 16 Python
selenium设置proxy、headers的方法(phantomjs、Chrome、Firefox)
Nov 29 Python
python基于socket进行端口转发实现后门隐藏的示例
Jul 25 Python
matlab中imadjust函数的作用及应用举例
Feb 27 Python
Django models文件模型变更错误解决
May 11 Python
浅析Python 字符编码与文件处理
Sep 24 Python
django注册用邮箱发送验证码的实现
Apr 18 Python
Python 中数组和数字相乘时的注意事项说明
May 10 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
桌面中心(三)修改数据库
2006/10/09 PHP
超级简单的发送邮件程序
2006/10/09 PHP
PHP 最大运行时间 max_execution_time修改方法
2010/03/08 PHP
PHP5中新增stdClass 内部保留类
2011/06/13 PHP
destoon首页调用求购供应信息的地区名称的方法
2014/08/21 PHP
php输出金字塔的2种实现方法
2014/12/16 PHP
PHP count_chars()函数讲解
2019/02/14 PHP
php判断某个方法是否存在函数function_exists (),method_exists()与is_callable()区别与用法解析
2020/04/20 PHP
js控制浏览器全屏示例代码
2014/02/20 Javascript
jQuery.holdReady()使用方法
2014/05/20 Javascript
javascript 原型链维护和继承详解
2014/11/26 Javascript
javascript实现点击商品列表checkbox实时统计金额的方法
2015/05/15 Javascript
jquery实现的缩略图预览滑块实例
2015/06/25 Javascript
jquery mobile开发常见问题分析
2016/01/21 Javascript
详解JavaScript的另类写法
2016/04/11 Javascript
使用ES6语法重构React代码详解
2017/05/09 Javascript
动态统计当前输入内容的字节、字符数的实例详解
2017/10/27 Javascript
基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法
2018/12/09 Javascript
JQuery样式操作、click事件以及索引值-选项卡应用示例
2019/05/14 jQuery
vue+elementUI实现表单和图片上传及验证功能示例
2019/05/14 Javascript
python socket多线程通讯实例分析(聊天室)
2016/04/06 Python
Python实现动态加载模块、类、函数的方法分析
2017/07/18 Python
python使用adbapi实现MySQL数据库的异步存储
2019/03/19 Python
使用Python发现隐藏的wifi
2020/03/04 Python
Django 404、500页面全局配置知识点详解
2020/03/10 Python
matlab、python中矩阵的互相导入导出方式
2020/06/01 Python
css3media响应式布局实例
2016/07/08 HTML / CSS
Html5实现单张、多张图片上传功能
2019/04/28 HTML / CSS
使用HTML5原生对话框元素并轻松创建模态框组件
2019/03/06 HTML / CSS
德国最大的拼图在线商店:Puzzle.de
2016/12/17 全球购物
《宋庆龄故居的樟树》教学反思
2014/04/07 职场文书
优秀党务工作者事迹材料
2014/05/07 职场文书
乡镇党委书记第三阶段个人整改措施
2014/09/16 职场文书
餐厅如何利用“营销策略”扭转亏本局面
2019/10/15 职场文书
教你用eclipse连接mysql数据库
2021/04/22 MySQL
铁拳制作人赞《铁拳7》老头环Mod:制作精良 但别弄了
2022/04/03 其他游戏