简单易用的图像解码库介绍-stb_image

简介: 说到图像解码库,最容易想起的就是libpng和libjpeg这两个老牌图像解码库了。

作者:星陨

来源:音视频开发进阶


说到图像解码库,最容易想起的就是libpnglibjpeg这两个老牌图像解码库了。

libpnglibjpeg分别各自对应pngjpeg两种图像格式。这两种格式的区别如下:

png 支持清晰度,无损压缩的图片格式,能在保证不失真的情况下重新压缩压缩图像文件的大小,因此图像质量高,在一些贴纸应用中也大部分用的是png图片。

jpg 不支持垂直,有损压缩的图片格式,有损压缩会和原始图片数据质量下载,也因此它占用的内存小,在网页应用中加速速度快。

要想在工程中同时解码pngjpeg格式图片,就必须同时引用这两个库,而且还得通过分段编译步骤才行。

在这里,介绍一个简单易用的图像库:stb_image。Github地址为:https://github.com/nothings/stb,目前已经有了9600+ Star。它的使用非常简单,看看README可能你就会了。

看看它的源码,会你发现全的英文.h头文件。这就是它的强大之处了,仅需在工程中加入头文件就可以解析图像了(实际上是函数实现等内容都放在头文件了而已)。

重点关注如下三个头文件:

  • stb_image.h
  • 用于图像加载
  • stb_image_write.h
  • 用于写入图像文件
  • stb_image_resize.h
  • 用于改变图像尺寸

下面就开始实践吧,先称为一个完整的例子:

1#include <iostream>
 2
 3#define STB_IMAGE_IMPLEMENTATION
 4#include "stb_image.h"
 5#define STB_IMAGE_WRITE_IMPLEMENTATION
 6#include "stb_image_write.h"
 7#define STB_IMAGE_RESIZE_IMPLEMENTATION
 8#include "stb_image_resize.h"
 9#include <string>
10#include <stdio.h>
11#include <stdlib.h>
12#include <vector>
13
14using namespace std;
15
16int main() {
17    std::cout << "Hello, STB_Image" << std::endl;
18
19    string inputPath = "/Users/glumes/Pictures/input.png";
20    int iw, ih, n;
21
22    // 加载图片获取宽、高、颜色通道信息
23    unsigned char *idata = stbi_load(inputPath.c_str(), &iw, &ih, &n, 0);
24
25    int ow = iw / 2;
26    int oh = ih / 2;
27    auto *odata = (unsigned char *) malloc(ow * oh * n);
28
29    // 改变图片尺寸
30    stbir_resize(idata, iw, ih, 0, odata, ow, oh, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0,
31                 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
32                 STBIR_FILTER_BOX, STBIR_FILTER_BOX,
33                 STBIR_COLORSPACE_SRGB, nullptr
34    );
35
36    string outputPath = "/Users/glumes/Pictures/output.png";
37    // 写入图片
38    stbi_write_png(outputPath.c_str(), ow, oh, n, odata, 0);
39
40    stbi_image_free(idata);
41    stbi_image_free(odata);
42    return 0;
43}

这个例子很简单也很全面,主要就是加载了一张图片,变成它的宽高都缩小一倍,并保存缩小后图片。

stb_image

首先是调用stbi_load方法去加载图像数据,并获取相关信息。初始的参数除了图片文件地址,还有宽,高,颜色通道信息的引用。

变量n就代表图片的颜色通道值,通常有如下的情况:

  • 1:灰色图
  • 2:灰色图加双边  
  • 3:红绿蓝RGB三色图
  • 4:红绿蓝加同轴RGBA图

返回的结果就是图片预期数据的指针了。

stbi_load不仅仅支持png格式,把上面的例子中的图片改成jpg格式后缀的依旧可行。

它支持的所有格式如下:

  • png
  • jpg
  • ga
  • bmp
  • psd
  • gif
  • 人类发展报告
  • 图片

格式虽然多,不过一般用到png和jpg就好了。

除了从文件加载图片,stb_image还支持从内存中加载图片,通过该方法stbi_load_from_memory,在后续文章中会用到它的。

加载完图片之后,stb_image还提供了相应的释放方法stbi_image_free,实际上就是把free封装了一下而已。

sbt_image_resize

加载完图片估计数据之后,就可以通过stbir_resize方法更改图片的尺寸。

stbir_resize 方法参数有很多:

1STBIRDEF int stbir_resize(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2                             void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
3                             stbir_datatype datatype,
4                             int num_channels, int alpha_channel, int flags,
5                             // stb 中提供了多种模式,但是修改后并没有见很明显的效果
6                             stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, 
7                             stbir_filter filter_horizontal,  stbir_filter filter_vertical,
8                             stbir_colorspace space, void *alloc_context)
9

stbir_edgestbir_filter类型的参数,stb_image_resize提供了多种类型:

1typedef enum
 2{
 3    STBIR_EDGE_CLAMP   = 1,
 4    STBIR_EDGE_REFLECT = 2,
 5    STBIR_EDGE_WRAP    = 3,
 6    STBIR_EDGE_ZERO    = 4,
 7} stbir_edge;
 8
 9typedef enum
10{
11    STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
12    STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
13    STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
14    STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
15    STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
16    STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
17} stbir_filter;

但实际上调整不同类型组合得到的图片并没有太多的变化┑( ̄Д  ̄)┍。

真正有用的可能还是前面那几个参数,指定了预期的图片缩放后的宽高数据。

stb_image_write

最后就是调用stbi_write_png方法将数据写入文件中,另外,stb_image_write还提供了stbi_write_jpg方法来保存jpg格式图片。

根据两者格式的不同,方法调用的参数也是不一样的。

1int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
2
3int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
4

总结

以上就是关于stb_image图像解码库的小介绍。

总的来说,它还是挺简单易用的,在平常做一些Demo以及需要快速实现,验证功能的情况下都可以考虑考虑。

但是在一些大型的项目中,还是要深思熟虑一些,从性能方面考虑,它肯定不如老牌的图像解码库了,像libjpeg-turbo解码用到了NEON这样SIMD(单指令流多数据流)的操作,才是大型项目的首选了。

参考

关于stb_image在Android中的使用实践,可以参考我的项目:

https://github.com/glumes/InstantGLSL


安卓以及音视频杂谈

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。  

阿里云社区.png

相关文章
|
小程序 前端开发 JavaScript
宠托师微信小程序---开题报告分享
宠托师微信小程序---开题报告分享
275 0
|
2月前
|
存储 数据挖掘 Apache
浩瀚深度:从 ClickHouse 到 Doris, 支撑单表 13PB、534 万亿行的超大规模数据分析场景
浩瀚深度旗下企业级大数据平台选择 Apache Doris 作为核心数据库解决方案,目前已在全国范围内十余个生产环境中稳步运行,其中最大规模集群部署于 117 个高性能服务器节点,单表原始数据量超 13PB,行数突破 534 万亿,日均导入数据约 145TB,节假日峰值达 158TB,是目前已知国内最大单表。
462 10
浩瀚深度:从 ClickHouse 到 Doris, 支撑单表 13PB、534 万亿行的超大规模数据分析场景
|
3月前
|
弹性计算 缓存 监控
​带宽与宽带的本质区别:为什么测试服务器5M带宽足够?-优雅草卓伊凡
​带宽与宽带的本质区别:为什么测试服务器5M带宽足够?-优雅草卓伊凡
588 1
​带宽与宽带的本质区别:为什么测试服务器5M带宽足够?-优雅草卓伊凡
|
7月前
|
Linux 数据安全/隐私保护 Windows
文件传输告别龟速!1分钟搞定Windows↔CentOS高速通道 小白也能玩转的Xftp秘籍
Xftp 是一款便捷的远程文件传输工具,与 XShell 类似,支持通过 SFTP 协议实现文件上传和下载。首先需下载安装 Xftp,并获取目标 Linux 系统(如 CentOS)的 IP 地址。打开 Xftp 后,按 `Ctrl + N` 新建会话,输入主机 IP、协议(SFTP)、用户名和密码连接服务器。
392 15
文件传输告别龟速!1分钟搞定Windows↔CentOS高速通道 小白也能玩转的Xftp秘籍
|
开发工具 git 开发者
|
12月前
|
缓存 数据库
读写锁和互斥锁的区别
【10月更文挑战第6天】
556 58
|
10月前
|
Web App开发 数据采集 JavaScript
Selenium和Pyppeteer有什么区别?
Selenium和Pyppeteer均为浏览器自动化工具,适用于网页测试与爬虫开发。Selenium需手动配置环境,支持多浏览器;Pyppeteer自动下载Chromium,仅支持Chrome,但配置简便、性能更优,适合Chrome特定需求的用户。Selenium则适合跨浏览器、跨平台的复杂场景。
|
11月前
|
存储 自然语言处理 JavaScript
鸿蒙next字符串基础:掌握字符串操作与多语言支持
本文深入介绍了鸿蒙(HarmonyOS)开发中字符串处理的基础知识和高级技巧。涵盖字符串资源管理、多语言支持、基本操作(如拼接、替换、分割和大小写转换)以及在用户界面和交互中的应用。通过合理管理和使用字符串资源,提升应用的用户体验和国际化水平。
619 3
|
运维 关系型数据库 MySQL
阿里 P7 到底是怎样的水平?
大家好,我是锋哥,今天分享我楼仔兄弟的一篇好文,希望对大家有帮助 ! 前几天二哥找我,问我阿里 P7 是怎样的水平,在面试中如何才能拿到阿里 P7 的职级。
|
安全 数据库 数据格式
Python量化炒股的获取数据函数—get_fundamentals()
Python量化炒股的获取数据函数—get_fundamentals()
582 0