libwebpのインストールとC言語での使用方法・使用例

こちらではMacにlibwebpをインストールする手順とlibwebpを用いたプログラムの例を紹介します。

メモ

試したOSは下記の通りです。他の環境では試せていませんのでご了承ください。

macOS Mojave

バージョン10.14.1

ダウンロードされるフォルダ違う・改行コードが異なる、などの違いがありますが、LINUX環境でも手順は参考になると思います。

libwebpの入手・インストール

まずは libwebp の入手方法とインストール方法について解説していきます。

libwebpのダウンロード

まずlibwebpをダウンロードするためにhttps://developers.google.com/speed/webp/download?hl=jaにアクセスしましょう。そして、自分の使用するOSに合わせて一番下のリンクを押すとダウンロードが開始されます。Mac OS Xであれば一番右のDownload for Mac OSX からダウンロードできます。2018/12/4だと、libwebp-1.0.0-mac-10.13.tarという名のファイルがダウンロードされました。

続いてターミナルでダウンロードしたファイルがあるフォルダにアクセスします。ターミナルアプリは「アプリケーション」→「ユーティリティ」にあります。


私がダウンロードしたファイルをダウンロードフォルダに保存しましたので下記コマンドでフォルダにアクセスしました。

cd /Users/[私のユーザ名]/Downloads/

続いてダウンロードした.tarを下記コマンドにより展開します。「libwebp-1.0.0-mac-10.13.tar」の部分はダウンロードしてきたファイル名に合わせて変更してください

tar xvf libwebp-1.0.0-mac-10.13.tar

フォルダが作成され、その中に様々なファイルが展開されるはずです。私の場合は「libwebp-1.0.0-mac-10.13」というフォルダが作成されました。

フォルダの中身は下図のようになっていると思います。

libwebpインストール

フォルダの中のincludeとlib(ついでにbinも)を/usr/local以下にコピーすればインストールすることができます。例えば「libwebp-1.0.0-mac-10.13」フォルダで下記コマンドを実行すればコピーできます。

sudo cp -r include/* /usr/local/include/
sudo cp lib/* /usr/local/lib
sudo cp bin/* /usr/local/bin

インストールの確認

最後にインストールされたことを確認しておきましょう。

今まで作成したC言語のプログラムファイルをコンパイルしてやるときに、最後に「-lwebp」をつけてからコンパイルしてみてください。下記のような感じです。

-lwebpを付けるとlibwebpをリンクしてやることが可能になります。これにより自分のプログラムでwebp関連の様々な関数が使用可能になります。

gcc japanese.c -o japanese.exe -lwebp

エラーが表示されずコンパイルが完了すれば、libwebpのインストールに成功です。

インストールがうまくできていなければ下記のようなメッセージが表示されますので再度手順を確認してみてください。

ld: library not found for -lwebp

clang: error: linker command failed with exit code 1 (use -v to see invocation)

libwebpを使用したプログラム例

続いて libwebp を使用したプログラム例を紹介します。

WebPファイル読み込み・書き込み

WebP ファイルを読み込み・書き込みするためのプログラムは以下のようになります。

ヘッダーファイル

mywebp.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include "webp/decode.h"
#include "webp/encode.h"

typedef struct{
  unsigned char *data;
  unsigned int width;
  unsigned int height;
  unsigned int ch;
} RAWDATA_t;

int webpFileReadDecode(RAWDATA_t *, const char*);
int webpFileEncodeWrite(RAWDATA_t *, const char*);
int freeRawData(RAWDATA_t *);

ポイントを説明します。

・libwebpのデコード関数・エンコード関数を使用するためにヘッダファイルをインクルード

#include "webp/decode.h"
#include "webp/encode.h"

・RAW形式データの情報格納用構造体を定義

dataにはWebPをデコードしたRAW形式画像データの先頭ポインタを指すアドレス、widthには画像の横幅、heightには画像の高さ、chには画像の色数(RGBの時は3、RGBAの時は4)がそれぞれ格納されます。

typedef struct{
  unsigned char *data;
  unsigned int width;
  unsigned int height;
  unsigned int ch;
} RAWDATA_t;

RAW形式画像データについては下の記事で説明していますので是非参考にしてください。

画像データの構造・画素・RAWデータについて解説画像データの構造・画素・RAWデータについて解説

この記事でも出てきているようにdataのポインタの先は下図のように各ピクセルのRGB順にデータが並んでいます。

アルファチャネル付きのファイルの場合は各ピクセルが下図のようにRGBα順にデータが並んでいます。

ソースファイル

mywebp.c
#include "mywebp.h"

int webpFileReadDecode(RAWDATA_t *rawData, const char* filename){

  FILE *fi; /* 入力ファイルポインタ */
  VP8StatusCode ret; /* webp関数の戻り値格納 */
  WebPBitstreamFeatures features; /* 入力webpファイルの情報 */
  struct stat statinfo; /* ファイルサイズ取得用 */
  long fileSize; /* ファイルサイズ */
  uint8_t *data; /* 入力webpファイルデータ */
  uint8_t *decodedData; /* 入力webpデコードデータ */
  int width; /* webpデコードデータの幅 */
  int height; /* webpデコードデータの高さ */

  /* WebPファイルオープン */
  fi = fopen(filename, "rb");
  if(fi == NULL) {
    printf("%sは開けません\n", filename);
    return -1;
  }

  /* WebPファイルのサイズ取得 */
  if (stat(filename, &statinfo) != 0) {
    printf("%sのファイルサイズ取得に失敗しました\n", filename);
    fclose(fi);
    return -1;
  }
  fileSize = statinfo.st_size;

  /* WebPファイルのデータ格納用メモリ確保 */
  data = (uint8_t*)malloc(sizeof(uint8_t) * fileSize);
  if(data == NULL) {
    printf("malloc error\n");
    fclose(fi);
    return -1;
  }

  /* WebPファイル読み込み */
  fread(data, fileSize, 1, fi);
  fclose(fi);

  /* WebPデータの情報取得 */
  ret = WebPGetFeatures(data, fileSize, &features);
  if(ret != VP8_STATUS_OK){
    printf("WebPGetFeatures error\n");
    free(data);
    return -1;
  }

  /* アルファチャンネルでデコード方法を切り替えてデコード */
  if(features.has_alpha == 0){
    decodedData = WebPDecodeRGB(data, fileSize, &width, &height);
  } else {
    decodedData = WebPDecodeRGBA(data, fileSize, &width, &height);
  }
  free(data);

  /* RAWDATA_t構造体への情報セット */
  rawData->width = width;
  rawData->height = height;
  if(features.has_alpha == 0) {
    rawData->ch = 3;
  } else {
    rawData->ch = 4;
  }
  printf("width = %d, height = %d, ch = %d\n", rawData->width, rawData->height, rawData->ch);

  /* デコードデータ用メモリ確保 */
  rawData->data =
    (unsigned char*)malloc(sizeof(unsigned char) * rawData->width * rawData->height * rawData->ch);
  if(rawData->data == NULL){
    printf("data malloc error\n");
    WebPFree(decodedData);
    return -1;
  }

  /* RAWDATA_t構造体へデコードデータセット */
  memcpy(rawData->data, decodedData, rawData->height *rawData->width * rawData->ch);

  /* デコードデータ解放 */
  WebPFree(decodedData);

  fclose(fi);

  return 0;
}

int webpFileEncodeWrite(RAWDATA_t *rawData, const char *filename){
  FILE *fo; /* 出力ファイルポインタ */
  uint8_t *encodedData; /* WebPエンコードデータ */
  size_t encodedSize; /* エンコードサイズ */

  /* エンコード実行 */
  if(rawData->ch == 3) {
    encodedSize = WebPEncodeLosslessRGB(
      rawData->data,
      rawData->width,
      rawData->height,
      rawData->width * rawData->ch,
      &encodedData);
  } else if(rawData->ch == 4) {
    encodedSize = WebPEncodeLosslessRGBA(
      rawData->data,
      rawData->width,
      rawData->height,
      rawData->width * rawData->ch,
      &encodedData);
  }
  /* 出力ファイルオープン */
  fo = fopen(filename, "wb");
  if(fo == NULL){
    WebPFree(encodedData);
    printf("%sが開けません\n", filename);
    return -1;
  }

  /* ファイルへエンコードデータ書き出し */
  fwrite(encodedData, encodedSize, 1, fo);

  /* エンコードデータ解放 */
  WebPFree(encodedData);
  
  fclose(fo);
  return 0;
}


int freeRawData(RAWDATA_t *raw){
  if(raw->data != NULL){
    free(raw->data);
    raw->data = NULL;
  }
  return 0;
}

main関数

上記で作成した関数の使い方がイメージつくように使用例を書いてみました。

#include "mywebp.h"

int main(int argc, char *argv[]){

  RAWDATA_t raw;
  int i, j, c;
  int ave, sum;
  char outname[256];

  FILE *fo;

  if(argc != 2){
    printf("ファイル名が指定されていません\n");
    return -1;
  }

  if(webpFileReadDecode(&raw, argv[1]) == -1){
    printf("webpFileReadDecode error\n");
    return -1;
  }

  printf("raw->data = %p\n", raw.data);
  printf("raw->width = %d\n", raw.width);
  printf("raw->height = %d\n", raw.height);
  printf("raw->ch = %d\n", raw.ch);

  /* グレースケールに変換 */
  for(j = 0; j < raw.height; j++){
    for(i = 0; i < raw.width; i++){
      sum = 0;
      for(c = 0; c < 3; c++){
        sum += raw.data[raw.ch * (i + j * raw.width) + c];
      }
      ave = sum / raw.ch;
      for(c = 0; c < 3; c++){
        raw.data[raw.ch * (i + j * raw.width) + c] = ave;
      }
    }
  }

  sprintf(outname, "%s", "output.webp");

  if(webpFileEncodeWrite(&raw, outname) == -1){
    printf("webpFileEncodeWrite error\n");
    freeRawData(&raw);
    return -1;
  }

  freeRawData(&raw);

  return 0;
}

処理の流れは下記の通りです。

  1. webpFileReadDecode関数を使用してWebPファイルの読み込みデコード
  2. 画像処理
  3. webpFileEncodeWrite()関数を使用してエンコードとWebPファイルへの書き込み
  4. freeして終了

画像処理では入力された画像をグレースケールに変換するソースコードを書いています。

私はWebP読み込み用・書き込み用のソースファイルを”mywebp.c”として分けて作成し、ヘッダーファイルを”mywebp.h”としています。ですので上記のソースコードにはところどころ”mywebp.h”が出てきています。違う名前にする場合は変更必要ですのでお気をつけください。このファイル名を用いている時、下記のコマンドでコンパイルとプログラムの実行が可能です。

gcc main.c -c
gcc mywebp.c -c
gcc main.o mywebp.o -o webp.exe -lwebp
./webp.exe test.webp

コンパイル時には”-lwebp“が必要です。これはlibwebpにリンクするためのコンパイルオプションになります。

ここで載せたソースコードはあくまで一例です。WebPファイルを読み込んでデコードするあたりやWebPファイルをエンコードして書き込むあたりはカスタマイズして自分が使用しやすいように変更してください。

WebPファイルの入手

WebP読み込むプログラムを作ったけど、肝心のWebPファイルがない・・・、という方はコチラの画像を使ってみてください。Google Chromeだと画像は見れるはずです。画像が見れなくても右クリックすれば保存可能です。

スポンサーリンク

libwepbが提供する関数

libwebpが提供する関数にどんなものがあるかや、使用方法は下記の「WebP API Documentation」に記載されています。

参考 WebP API Documentationgoogle developer
注意

このページはlibwebpのインストール方法や使用例の紹介を目的としたページであり、libwebpのライセンス体系については私も詳しくないのでこのページでは言及していません。libwebpを使用する方は自己責任で使用してください。

例えば商用利用等を行う場合はライセンス体系についてご自分で調査してから使用の可否をご判断ください。

まとめ

このページでは次世代画像フォーマットの WebP を読み込み・書き込みするライブラリである libwebp のインストール方法やプログラム中での使用方法について解説しました。

今後 WebP の普及率が高まる可能性は高いと思いますので、WebP を使ってみたいという方は是非このページを参考にして libwebp をインストールしてみてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です