原文链接:简单易用的图像解码库介绍 —— stb_image

说到图像解码库,最容易想起的就是 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
    • 用于改变图像尺寸

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

#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_edgestbir_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 中的使用实践,可以参考我的项目:

https://github.com/glumes/InstantGLSL

欢迎关注微信公众号:【纸上浅谈】,获得最新文章推送~~~

简单易用的图像解码库介绍 —— stb_image的更多相关文章

  1. 推荐一个c++小巧开源且跨平台的图像解码库

    该图像解码库仅仅三个文件. 图像处理封装: spot.cpp spot.h 解码库实现: spot.c 支持图片文件格式如下: File format Read Write BMP files yes ...

  2. 极力推荐一个简单好用的C++JSON库

      极力推荐一个简单好用的C++JSON库CJsonObject,让使用json如使用C++原生的结构体那般方便,随心所欲.CJsonObject是个优秀的C++JSON库,也许会是你见过的最为简单易 ...

  3. EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)

    ffmpeg是一套开源的,完整的流媒体解决方案.基于它可以很轻松构建一些强大的应用程序.对于流媒体这个行业,ffmpeg就像圣经一样的存在.为了表达敬意,在这里把ffmpeg官网的一段简介搬过来,ff ...

  4. 玩node-images模块---Node.js轻量级跨平台图像编解码库

    Node.js轻量级跨平台图像编解码库 github:https://github.com/zhangyuanwei/node-images Features 功能特性 轻量级:无需安装任何图像处理库 ...

  5. SDAutoLayout:比masonry更简单易用的自动布局库

    SDAutoLayout:一行代码搞定自动布局!支持Cell和Tableview高度自适应,Label和ScrollView内容自适应,致力于做最简单易用的AutoLayout库. [SDAutoLa ...

  6. SaltStack介绍——SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流

    SaltStack介绍和架构解析 简介 SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位.SaltSta ...

  7. 简单易用的字符串模糊匹配库Fuzzywuzzy

    简单易用的字符串模糊匹配库Fuzzywuzzy 阅读目录 FuzzyWuzzy 简介 安装 用法 已知移植 FuzzyWuzzy 简介 FuzzyWuzzy 是一个简单易用的模糊字符串匹配工具包.它依 ...

  8. 分享一个简单易用的软件定时器模块(MultiTimer)——基于keil+stm32f103zet+hal库(裸机实现)

    公众号上看到一个比较好的一个github项目:https://github.com/0x1abin/MultiTimer 今天看了看,简单的,就移植了- 且看文档的说明, ============== ...

  9. 开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发

    [原][开源框架]Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位... 时间 2015-01-05 10:08:18 我是程序猿,我为自己代言 原文  http: ...

随机推荐

  1. pytest+allure高端测试报告

    1.下载jdk,搭建jdk环境 下载JDK  http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.下载allure ...

  2. VisualStudio2010配置使用Halcon

    电脑系统环境变量(path): %HALCONROOT%\bin\x86sse2-win32;%HALCONROOT%\bin\x64-win64;%HALCONROOT%\bin\dotnet20; ...

  3. [LC] 215. Kth Largest Element in an Array

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  4. spring xml 注入 map 时 map 标签报错

    如图所示: 在XML配置文件中并没有问题,问题出在实体类,在类中属性 maps 用 Map定义即可,用HashMap定义就会出现如上错误 K-I-N-G-D-O-M

  5. springboot 配置热部署 及 热部署后依旧是404的坑

    springboot配置热部署的教程网上一大堆: 个人喜欢这种方式: https://www.cnblogs.com/winner-0715/p/6666579.html 本文主要强调的是,大家如果配 ...

  6. [洛谷P4782] [模板] 2-SAT 问题

    NOIp后第一篇题解. NOIp我考的很凉啊...... 题目传送门 之前讲过怎么判断2-SAT是否存在解. 至于如何构造一组解: 我们想到对tarjan缩点后的图进行拓扑排序. 那么对于代表0状态的 ...

  7. JS去重函数的扩展应用

    数据: 账单id[1,1,1,1,2,2,2,3,3,3,3,3,3,3], 相对于账单id的金额[100,120,110,150,200,180,220,115,150,120,180,220,14 ...

  8. MariaDB 命令

    1.账号登入 mysql -u root -p 上述命令,“root” 是登入账号,上述命令回车后,则进行密码的输入 登入成功后如下: 2.创建用户命令 create user 'new_user'@ ...

  9. CSAPC08台湾邀请赛_T1_skyline

    题目链接:CSAPC08台湾邀请赛_T1_skyline 题目描述 一座山的山稜线由许多片段的45度斜坡构成,每一个片段不是上坡就是下坡. / /​ * / ​/ * /  // ​/ // / 在我 ...

  10. Python 列表[::-1]翻转

    b = a[i:j:s]: i为起始索引(缺省为0), j为结束索引(不包括,缺省为len(a)), s为步进(缺省为1). 所以a[i:j:1]相当于a[i:j]. 当s<0时: i缺省时,默 ...