简单易用的图像解码库介绍 —— stb_image
说到图像解码库,最容易想起的就是 libpng
和 libjpeg
这两个老牌图像解码库了。
libpng
和 libjpeg
分别各自对应 png
和 jpeg
两种图像格式。这两种格式的区别如下:
png
支持透明度,无损压缩的图片格式,能在保证不失真的情况下尽可能压缩图像文件的大小,因此图像质量高,在一些贴纸应用中也大部分用的是 png 图片。
jpg
不支持透明度,有损压缩的图片格式,有损压缩会使得原始图片数据质量下载,也因此它占用的内存小,在网页应用中加速速度快。
要想在工程中同时解码 png
和 jpeg
格式图片,就必须同时引用这两种库,而且还得经过一系列编译步骤才行。
在这里,介绍一个简单易用的图像库:stb_image
。Github 地址为:https://github.com/nothings/stb ,目前已经有了 9600+ Star 。它的使用非常简单,看看 README 可能你就会了。
看看它的源码,你会发现全是 .h
头文件。这就是它的强大之处了,仅需在工程中加入头文件就可以解析图像了(实际上是函数实现等内容都放在头文件了而已)。
重点关注如下三个头文件:
- stb_image.h
- 用于图像加载
- stb_image_write.h
- 用于写入图像文件
- stb_image_resize.h
- 用于改变图像尺寸
下面就开始实践吧,先给出一个完整的例子:
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
int main() {
std::cout << "Hello, STB_Image" << std::endl;
string inputPath = "/Users/glumes/Pictures/input.png";
int iw, ih, n;
// 加载图片获取宽、高、颜色通道信息
unsigned char *idata = stbi_load(inputPath.c_str(), &iw, &ih, &n, 0);
int ow = iw / 2;
int oh = ih / 2;
auto *odata = (unsigned char *) malloc(ow * oh * n);
// 改变图片尺寸
stbir_resize(idata, iw, ih, 0, odata, ow, oh, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0,
STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
STBIR_FILTER_BOX, STBIR_FILTER_BOX,
STBIR_COLORSPACE_SRGB, nullptr
);
string outputPath = "/Users/glumes/Pictures/output.png";
// 写入图片
stbi_write_png(outputPath.c_str(), ow, oh, n, odata, 0);
stbi_image_free(idata);
stbi_image_free(odata);
return 0;
}
这个例子很简单也很全面,主要就是加载了一张图片,并将它的宽高都缩小一倍,并保存缩小后图片。
stb_image
首先是调用 stbi_load
方法去加载图像数据,并获取相关信息。传入的参数除了图片文件地址,还有宽、高、颜色通道信息的引用。
变量 n
就代表图片的颜色通道值,通常有如下的情况:
- 1 : 灰度图
- 2 : 灰度图加透明度
- 3 : 红绿蓝 RGB 三色图
- 4 : 红绿蓝加透明度 RGBA 图
返回的结果就是图片像素数据的指针了。
stbi_load
不仅仅支持 png
格式,把上面例子中的图片改成 jpg
格式后缀的依旧可行。
它支持的所有格式如下:
- png
- jpg
- tga
- bmp
- psd
- gif
- hdr
- pic
格式虽多,不过一般用到 png 和 jpg 就好了。
除了从文件加载图片,stb_image 还支持从内存中加载图片,通过该方法 stbi_load_from_memory
,在后续文章中会用到它的。
加载完图片之后,stb_image 还提供了相应的释放方法 stbi_image_free
,实际上就是把 free
封装了一下而已。
sbt_image_resize
加载完图片像素数据之后,就可以通过 stbir_resize
方法改变图片的尺寸。
stbir_resize
方法参数有很多:
STBIRDEF int stbir_resize(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
// stb 中提供了多种模式,但是修改后并没有见很明显的效果
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context)
stbir_edge
和 stbir_filter
类型的参数,stb_image_resize 提供了多种类型:
typedef enum
{
STBIR_EDGE_CLAMP = 1,
STBIR_EDGE_REFLECT = 2,
STBIR_EDGE_WRAP = 3,
STBIR_EDGE_ZERO = 4,
} stbir_edge;
typedef enum
{
STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
} stbir_filter;
但实际上调整不同类型组合得到的图片并没有太多的变化 ┑( ̄Д  ̄)┍。
真正有用的可能还是前面那几个参数,指定了要将图片缩放后的宽高数据。
stb_image_write
最后就是调用 stbi_write_png
方法将像素数据写入文件中,除此之外,stb_image_write 还提供了 stbi_write_jpg
方法来保存 jpg 格式图片。
根据两者格式的不同,方法调用的参数也是不一样的。
int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
总结
以上就是关于 stb_image 图像解码库的小介绍。
总的来说,它还是挺简单易用的,在平常做一些 Demo 以及需要快速实现、验证功能的情况下都可以考虑考虑。
但是在一些大型的项目中,还是要深思熟虑一些,从性能方面考虑,它肯定不如老牌的图像解码库了,像 libjpeg-turbo
解码用到了 NEON
这样 SIMD (单指令流多数据流)的操作,才是大型项目的首选了。
参考
关于 stb_image 在 Android 中的使用实践,可以参考我的项目:
欢迎关注微信公众号:【纸上浅谈】,获得最新文章推送~~~
简单易用的图像解码库介绍 —— stb_image的更多相关文章
- 推荐一个c++小巧开源且跨平台的图像解码库
该图像解码库仅仅三个文件. 图像处理封装: spot.cpp spot.h 解码库实现: spot.c 支持图片文件格式如下: File format Read Write BMP files yes ...
- 极力推荐一个简单好用的C++JSON库
极力推荐一个简单好用的C++JSON库CJsonObject,让使用json如使用C++原生的结构体那般方便,随心所欲.CJsonObject是个优秀的C++JSON库,也许会是你见过的最为简单易 ...
- EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)
ffmpeg是一套开源的,完整的流媒体解决方案.基于它可以很轻松构建一些强大的应用程序.对于流媒体这个行业,ffmpeg就像圣经一样的存在.为了表达敬意,在这里把ffmpeg官网的一段简介搬过来,ff ...
- 玩node-images模块---Node.js轻量级跨平台图像编解码库
Node.js轻量级跨平台图像编解码库 github:https://github.com/zhangyuanwei/node-images Features 功能特性 轻量级:无需安装任何图像处理库 ...
- SDAutoLayout:比masonry更简单易用的自动布局库
SDAutoLayout:一行代码搞定自动布局!支持Cell和Tableview高度自适应,Label和ScrollView内容自适应,致力于做最简单易用的AutoLayout库. [SDAutoLa ...
- SaltStack介绍——SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流
SaltStack介绍和架构解析 简介 SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位.SaltSta ...
- 简单易用的字符串模糊匹配库Fuzzywuzzy
简单易用的字符串模糊匹配库Fuzzywuzzy 阅读目录 FuzzyWuzzy 简介 安装 用法 已知移植 FuzzyWuzzy 简介 FuzzyWuzzy 是一个简单易用的模糊字符串匹配工具包.它依 ...
- 分享一个简单易用的软件定时器模块(MultiTimer)——基于keil+stm32f103zet+hal库(裸机实现)
公众号上看到一个比较好的一个github项目:https://github.com/0x1abin/MultiTimer 今天看了看,简单的,就移植了- 且看文档的说明, ============== ...
- 开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发
[原][开源框架]Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位... 时间 2015-01-05 10:08:18 我是程序猿,我为自己代言 原文 http: ...
随机推荐
- [LC] 5. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- mysqli存储过程
<?php$link = mysqli_connect('localhost','root','','chinatupai'); $sql = "call getEmail('000 ...
- [LC] 359. Logger Rate Limiter
Design a logger system that receive stream of messages along with its timestamps, each message shoul ...
- echart封装,前端简单路由,图表设置自动化
https://github.com/cclient/EhartDemoSetByAngular 后端node.js 前端插件 echart,jquery,jqueryui,datapicker,an ...
- python3爬虫:利用urllib与有道翻译获得翻译结果
在实现这一功能时遇到了一些困难,由于按照<零基础入门python>中的代码无法实现翻译,会爆出“您的请求来源非法,商业用途使用请关注有道翻译API官方网站“有道智云”: http://ai ...
- Java完成生产者消费者模型
生产者和消费者模型,是多线程中的典型模型,这里使用Java完成该模型 ServerTest.java 生产者代码 package com.orange.threadmodel; import java ...
- estt
1.路由控制的定义 1.1.IP地址与路由控制 互联网是由路由器连接的网络组合而成的.为了能让数据包正确地到达目标主机,路由器必须在途中进行正确地转发.这种向"正确的方法"转发数据 ...
- 吴裕雄--天生自然 R语言开发学习:功效分析
#----------------------------------------# # R in Action (2nd ed): Chapter 10 # # Power analysis # # ...
- mac安装并配置nexus3.5.1版本
一.安装nexus 前置条件 :已经安装了JDK 1:下载nexus(http://www.sonatype.com/download-oss-sonatype) 最新版本(我的是3.5.1). 2: ...
- JXJJOI2018_T3_catch
题目描述 Lemon因为偶然的原因,当上了警察局长.而一上任,他就碰到了个大麻烦:追捕周克华. 周克华是人尽皆知的抢劫杀人犯,而就在几天前,他在Lemon辖区内的银行门口,枪杀了一名储户后逃之夭夭.L ...