zoukankan      html  css  js  c++  java
  • 【图像处理】使用SDL预览webp图片

    写在前面的话

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

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

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

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

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

    webp格式图片说明

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

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |      'R'      |      'I'      |      'F'      |      'F'      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           File Size                           |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |      'W'      |      'E'      |      'B'      |      'P'      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    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!
    ");
        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)!
    ",
                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!
    ",
                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)
    ", 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.

    祝玩的开心~

  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/voipman/p/15244037.html
Copyright © 2011-2022 走看看