写在前面的话

WebP是Google开发的一种图像格式,支持图像数据的有损和无损压缩。保留动画和alpha透明通道数据。

可以创建和JPEG、PNG和GIF图像格式在质量相同或质量更高,但是数据更小的一种图像格式。

如下简单的分析一下webp图像格式,并使用sdl显示图片。

webp项目地址:https://github.com/webmproject/libwebp

sdl项目地址:https://libsdl.org/

webp格式图片说明

webp格式图像数据由两部分组成,RIFF头和图像负载信息。

RIFF头信息由21个字节组成。

0-3 四个字节是 RIFF 四个字符,表示 资源交换格式Resource Interchange File Format的简写。

4-7 四个字节是 WEBP文件的全部长度,这个长度包含RIFF

8-11 四个字节是 资源交换格式的名称,填WEBP这四个字符

12-15 四个字节是数据块Chunk的负载信息的编码格式,取值有VP8表示无损vp8压缩,VP8L表示有损vp8压缩

16-19 四个字节是有损压缩时的VP8数据负载信息的长度

20-以后数vp8格式的图像数据帧。

VP8格式的定义如下

struct VP8Io {
// set by VP8GetHeaders()
int width, height; // picture dimensions, in pixels (invariable).
// These are the original, uncropped dimensions.
// The actual area passed to put() is stored
// in mb_w / mb_h fields. // set before calling put()
int mb_y; // position of the current rows (in pixels)
int mb_w; // number of columns in the sample
int mb_h; // number of rows in the sample
const uint8_t* y, *u, *v; // rows to copy (in yuv420 format)
int y_stride; // row stride for luma
int uv_stride; // row stride for chroma
const uint8_t* a;
};

VP8使用14位表示图像的宽和高,因此webp格式图像宽高最大是2^14 = 16384像素。

VP8的每一个像素的值是通过 左上top-left 上top 右上top-right 和左left这4个像素做预测得到。

预测的方法如下

  // L = left pixel, T = top pixel, TL = top left pixel.

  // ARGB component estimates for prediction.
int pAlpha = ALPHA(L) + ALPHA(T) - ALPHA(TL);
int pRed = RED(L) + RED(T) - RED(TL);
int pGreen = GREEN(L) + GREEN(T) - GREEN(TL);
int pBlue = BLUE(L) + BLUE(T) - BLUE(TL); // Manhattan distances to estimates for left and top pixels.
int pL = abs(pAlpha - ALPHA(L)) + abs(pRed - RED(L)) +
abs(pGreen - GREEN(L)) + abs(pBlue - BLUE(L));
int pT = abs(pAlpha - ALPHA(T)) + abs(pRed - RED(T)) +
abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T));

VP8的详细分析,后面增加一篇对应的文章分析。

环境准备

centos环境可以先安装png tiff jpeg和sdl

yum install libjpeg-devel
yum install libpng-devel
yum install libtiff-devel

osx系统可以使用brew命令按照对应的包

使用cmake编译webp项目后会生成如下小工具

cwebp 工具可以将其他格式图片转成webp图片

./cwebp -h
Usage: cwebp [options] -q quality input.png -o output.webp where quality is between 0 (poor) to 100 (very good).
Typical value is around 80.

dwebp 工具可以将webp图片转成png jpg tiff ppm等格式

./dwebp -h
Usage: dwebp in_file [options] [-o out_file] -pam ......... save the raw RGBA samples as a color PAM
-ppm ......... save the raw RGB samples as a color PPM
-bmp ......... save as uncompressed BMP format
-tiff ........ save as uncompressed TIFF format
-pgm ......... save the raw YUV samples as a grayscale PGM
file with IMC4 layout
-yuv ......... save the raw YUV samples in flat layout

vwebp_sdl 工具可以将通过sdl显示webp图片

做SDL显示的一个例子

首先找一张png的图片,将这个图片转成webp格式的图像。

./cwebp leopard2.png -o  leopard2.webp

Saving file 'leopard2.webp'
File: leopard2.png
Dimension: 842 x 1134
Output: 59610 bytes Y-U-V-All-PSNR 40.28 44.99 46.35 41.45 dB
(0.50 bpp)
block count: intra4: 2898 (77.01%)
intra16: 865 (22.99%)
skipped: 1 (0.03%)
bytes used: header: 203 (0.3%)
mode-partition: 13872 (23.3%)
Residuals bytes |segment 1|segment 2|segment 3|segment 4| total
macroblocks: | 12%| 37%| 10%| 42%| 3763
quantizer: | 36 | 32 | 27 | 16 |
filter level: | 11 | 8 | 12 | 15 |

如下是png格式图片是webp格式图片大小的3.4倍,png格式的图像大小是1.4M,webp格式图像的大小是58k

1.4M  9  8 16:29 leopard2.png
58K 9 8 16:30 leopard2.webp

显示webp图片

./vwebp_sdl leopard2.webp

SDL图像显示原理

SDL库在的图像显示表面接收RGB或者YUV格式的图像数据。

因此,若显示webp格式的图像,需要将webp格式的图像转成RGB或者YUV格式,将图像数据传递给SDL的显示表面实现显示效果。

注:其他格式的图片也是同样的做法,其他格式转成RGB或者YUV格式数据交给SDL显示表面。

显示逻辑如下:

 结合SDL显示图像的原理如下:

SDL显示webp的主要代码

int WebpToSDL(const char* data, unsigned int data_size) {
int ok = 0;
// 第一步 声明webp的配置和属性
VP8StatusCode status;
WebPDecoderConfig config;
WebPBitstreamFeatures* const input = &config.input;
WebPDecBuffer* const output = &config.output; SDL_Surface* screen = NULL;
SDL_Surface* surface = NULL;
// 第二步 初始化webp解码配置信息
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
return 0;
} if (!init_ok) {
SDL_Init(SDL_INIT_VIDEO);
init_ok = 1;
}
// 第三步 获取webp图像数据
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
if (status != VP8_STATUS_OK) goto Error; screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
if (screen == NULL) {
fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
input->width, input->height);
goto Error;
} surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
input->width, input->height, 32,
0x000000ffu, // R mask
0x0000ff00u, // G mask
0x00ff0000u, // B mask
0xff000000u); // A mask if (surface == NULL) {
fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
input->width, input->height);
goto Error;
}
if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface); #if SDL_BYTEORDER == SDL_BIG_ENDIAN
output->colorspace = MODE_BGRA;
#else
output->colorspace = MODE_RGBA;
#endif
output->width = surface->w;
output->height = surface->h;
output->u.RGBA.rgba = surface->pixels;
output->u.RGBA.stride = surface->pitch;
output->u.RGBA.size = surface->pitch * surface->h;
output->is_external_memory = 1;
// 第四步 解码webp格式成rgb格式的图像数据
status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config);
if (status != VP8_STATUS_OK) {
fprintf(stderr, "Error decoding image (%d)\n", status);
goto Error;
} if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
// 第五步 将rgb的图像数据显示到SDL的目标表面,实现显示
if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
SDL_Flip(screen)) {
goto Error;
} ok = 1; Error:
SDL_FreeSurface(surface);
SDL_FreeSurface(screen);
WebPFreeDecBuffer(output);
return ok;
}

参考材料:

https://developers.google.cn/speed/webp/docs/riff_container

done.

祝玩的开心~

【图像处理】使用SDL预览webp图片的更多相关文章

  1. 基于HTML5的可预览多图片Ajax上传

    一.关于图片上传什么什么的 在XHTML的时代,我们使用HTML file控件上传图片一次只能上传一张.要一次上传多图,做法是借助于flash.例如swfupload.js.可惜,使用复杂的点,比如f ...

  2. HTML5可预览多图片ajax上传(使用formData传递数据)

    HTML5可预览多图片ajax上传(使用formData传递数据) 在介绍上传图片之前,我们简单的来了解下FormData的基本使用:介绍完成后这些基本知识后,我们会在文章最后提供一个demo,就是a ...

  3. input type=file实现图片上传,预览以及图片删除

    背景 前两天在做一个PC网站的意见反馈,其中涉及到了图片上传功能,要求可以上传多张图片,并且支持图片上传预览及图片删除, 图片上传这一块以前没怎么搞过,而且一般也很少会碰到这样的需求,所以在做这个功能 ...

  4. 小程序 canvas实现图片预览,图片保存

    wxml 代码: <view class="result-page"> <canvas bindtap="previewImage" canv ...

  5. 一款基于jQuery可放大预览的图片滑块插件

    今天给大家分享一款基于jQuery可放大预览的图片滑块插件.这款jQuery焦点图插件的特点是可以横向左右滑动图片,并且点击图片可以进行放大预览,唯一的缺陷是这款焦点图并不能循环切换,如果你有较好的J ...

  6. 移动端 H5 拍照 从手机选择图片,移动端预览,图片压缩,图片预览,再上传服务器

    前言:最近公司的项目在做全网营销,要做非微信浏览器的wap 站 的改版,其中涉及到的一点技术就是采用H5 选择手机相册中的图片,或者拍照,再将获取的图片进行压缩之后上传. 这个功能模块主要有这5点比较 ...

  7. 小程序实现图片上传,预览以及图片base64位处理

    最近一段时间在做小程序项目,第一期功也完工了.需要好好总结一下经验,把项目中遇到的问题好好总结一下,遇到的问题,踩过的坑.今天写一个小程序实现图片上传,预览,以及删除,图片base64位处理.下面就是 ...

  8. js:s上次预览,上传图片预览,图片上传预览

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. IE7+ 浏览器兼容预览本地图片

    css #preview_fake { filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale); o ...

随机推荐

  1. []*T *[]T *[]*T 傻傻分不清楚

    前言 作为一个 Go 语言新手,看到一切"诡异"的代码都会感到好奇:比如我最近看到的几个方法:伪代码如下: func FindA() ([]*T,error) { } func F ...

  2. POJ 1190 生日蛋糕题解

    题目地址:http://poj.org/problem?id=1190 一道很有趣的搜索题--主要是剪枝-- 我弄了5个剪枝: 1.当前剩余层数>=上层半径,剪掉 2.当前剩余层数>=上层 ...

  3. 在Windows中安装PySpark环境

    在Windows中安装PySpark环境 安装Python 可以选择安装官方版本的Python,或是Anaconda,对应的地址如下. 下载地址 Python:https://www.python.o ...

  4. Socket通信-客户端

    WSADATA wsd; SOCKET sHost; SOCKADDR_IN servAddr; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) retu ...

  5. MySQL-19-分布式架构MyCat

    MyCAT基础架构图(实验环境) MyCAT实验环境准备 1 环境准备 两台虚拟机: db01(10.0.0.51) db02(10.0.0.52) 每台创建四个mysql实例:3307 3308 3 ...

  6. Python之简单的神经网络

    from sklearn import datasets from sklearn import preprocessing from sklearn.model_selection import t ...

  7. 从安装到使用——Odoo常见问题及故障处理

    小九今天分享了Odoo一键部署.高效安装的图文详解,接下来,针对Odoo使用过程中的一些问题,小九整理了详细的常见问题问答.这样的直观方式往往能快速高效地解决一些疑惑. 也欢迎提出其他问题,共同探讨, ...

  8. NOIP 模拟 $32\; \rm Walker$

    题解 \(by\;zj\varphi\) 发现当把 \(\rm scale×cos\theta,scale×sin\theta,dx,dy\) 当作变量时只有四个,两个方程就行. 当 \(\rm n\ ...

  9. 题解 Strange Housing

    传送门 首先想了黑白染色,发现不会染 其实可以考虑如何动态地维护出这个点集 发现题面里对不在点集之中的点之间的连边没有要求 所以考虑不断向图中加点,为了满足要求,每次取一个与当前新图中相连的点 若它与 ...

  10. 深层剖析鸿蒙轻内核M核的动态内存如何支持多段非连续性内存

    摘要:鸿蒙轻内核M核新增支持了多段非连续性内存区域,把多个非连续性内存逻辑上合一,用户不感知底层的不同内存块. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列九 动态内存Dynamic Mem ...