【图像处理】Golang 获取JPG图像的宽高
一、背景
有些业务需要判断图片的宽高,来做一些图片相关缩放,旋转等基础操作。
但是图片缩放,旋转,拼接等操作需要将图片从 JPG 格式转成 RGBA 格式操作,操作完毕后,再转回 JPG 图片。
那如何不做 RGBA 的转换就能得到 JPG 图片的宽和高呢?
如下通过 JPG 文件的分析,并编写一个简单的代码,从 JPG 文件中获取宽度和高度。
二、JPG 图片信息分析
分析一张 JPG 图片时,关键的信息如下,部分来自维基百科:
三、JPG开始,宽高分析
3.1 JPG格式判断方法
JPG 图片的开头是0xFF 0xD8
因此,判断 JPG 图片的魔法文件 magic 标识就是0xFF 0xD8
在 golang 中也是通过0xFF 0xD8判断图片是否为 JPG 文件,如下所示:
&exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"},
3.2 JPG 图片宽高获取
本文通过分析JPG 图片的开始帧SOF 获取图片的宽高。
预览一张图片获取图像的宽高基本信息。
宽:1200,高:1002
可以使用二进制方式打开文件,查看 JPG 图片的头部信息,获取 JPG 图片开始帧信息如SOF0, SOF1, SOF2。
SOF0 表示baseline DCT, 基线 DCT(离散余弦变换),开头的标识是 0xFF 0xC0
SOF1 表示extended sequential DCT,扩展序列 DCT ,开头的标识是 0xFF 0xC1
SOF2 表示progressive DCT,升级 DCT, 开头的标识是 0xFF 0xC2
如下是一个 JPG 的头部信息:
从上图中可以看到开始帧信息是 SOF0,即 绿色标记的 ffc0。
找到 SOF 后,向后偏移5个字节得到高和宽
高:03 ea,计算得到高等于 3<<8|0xea = 1002
宽:04 b0,计算得到宽等于4<<8|0xb0 = 1200
得到的宽高和预览时的宽高一致。
3.3. JPG 宽高计算原理
eg: [ff c0] 00 11 08 [03 ea] [04 b0]
| | |
| | |
-> SOF1 ->height ->width
脚本计算宽高如下:
% expr 3<<8|0xea 1002 % expr 4<<8|0xb0 1200
3.4 通过golang 实现 JPG 图片宽高的获取
知道了 JPG 获取图片宽高的原理后,使用 golang代码或者 JPG 图片的宽高如下:
/** * 入参: JPG 图片文件的二进制数据 * 出参:JPG 图片的宽和高 **/ func GetWidthHeightForJpg(imgBytes []byte) (int, int) { var offset int imgByteLen := len(imgBytes) for i := 0; i < imgByteLen-1; i++ { if imgBytes[i] != 0xff { continue } if imgBytes[i+1] == 0xC0 || imgBytes[i+1] == 0xC1 || imgBytes[i+1] == 0xC2 { offset = i break } } offset += 5 if offset >= imgByteLen { return 0, 0 } height := int(imgBytes[offset])<<8 + int(imgBytes[offset+1]) width := int(imgBytes[offset+2])<<8 + int(imgBytes[offset+3]) return width, height }
总结
通过分析 JPG 图片的 SOF 信息,就可以提取图片的宽和高,而不用将其转换成 RGBA,再获取 RGBA 的宽高,可以节约一些计算资源。
后续再分析 JPG 图片的其他信息,如下离散余弦变换和哈夫曼编码等。
Done
祝玩的开心~
原文地址:https://www.cnblogs.com/voipman/p/16108320.html
- Android 表单验证框架:AValidations
- 推荐系统介绍
- Android WebView 上传文件支持全解析
- 网站管理软件 – AspxSpy2014 Final
- 特性分支与特性开关哪家强?
- Android快速开发框架 roboguice
- 悄悄的干活,打枪的不要!勒索+比特币挖矿木马
- 拥有可移动头像的折叠Android工具栏:CollapsingAvatarToolbar
- Android平台下的第一个Tor木马
- 利用代码实现自定义圆角+阴影按钮 android-flat-button
- 周末阅读:程序员的《权利法案》
- 对利用Adobe 0day – CVE-2014-0502进行攻击的行为分析
- Android系统更改状态栏字体颜色
- Android实现竖着的滑动刻度尺效果,选择身高(竖向的)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java汉字剪裁工具类
- Day20.python操作数据库
- python字典根据value排序
- Day17.String字符串处理库
- PHP安装配置(Windows和Linux)-一篇就够了
- JavaSE面试深度剖析 第一讲
- JavaSE面试深度剖析 第二讲
- JavaSE面试深度剖析 第三讲
- docker+consul+ nginx集成分布式的服务发现与注册架构
- CWFF:一款针对模糊测试的自定义字典工具
- HMM、信号、时序、降噪(附代码)
- 原创 | 图解git,用手绘图带你理解git中分支的原理和应用
- Android 天气APP(二十四)地图天气(上)自动定位和地图点击定位
- 3分钟短文:可能是Laravel模板最直白的用法了,没有之一
- Android 天气APP(二十三)增加灾害预警、优化主页面UI