24
26

More than 5 years have passed since last update.

libwebp を使って iOS で WebP を表示する

Last updated at Posted at 2016-06-01

ファイルサイズを削減できる WebP。iOS で WebP を使用する OSS を見かけますが、使用用途にイマイチマッチしなかったので、libwebp を直接使用して描画することにしました。やってみると以外と簡単。

iOS framework のダウンロードとインストール

webp を iOS で使用するために framework 形式で Google が公開しているのでこちらをダウンロードします。

  • downloads repository
    • この記事を書いた時点での最新は libwebp-0.5.0-ios-framework.tar.gz

tar.gz を解凍するとそのまま framework のフォルダ構成になっているので、WebP.framework という名前のフォルダに解凍。
xcode の 「Link Binary With Libraries」 に WebP.framework を追加します。

webp 画像の描画

webp から UIImage を作るのは次の順序です。

  1. ファイルのロード
  2. WebPDecodeARGB を呼び出してデコード
  3. デコードしたバッファから CGDataProvider を作成
  4. CGDataProvider から CGImage を作成
  5. CGImage から UIImage を作成

libwebp で使用するのは WebPDecodeARGB だけです。この関数は WebP をデコードするもので、この戻り値は次のフォーマットになっています。

[a0, r0, g0, b0, a1, r1, g1, b1, ...]

参照:WebP API Documentation

これはそのまま CGImageRef のバッファーとして使用できるので、CGDataProvider でラップして CGImageCreate に渡します。

- (UIImage*)loadImageAtPath:(NSString*)path
{
  // ファイルのロード
  NSData* data = [[NSData alloc] initWithContentsOfFile:path];
  size_t length = data.length;
  uint8_t* image = (uint8_t*)data.bytes;

  // デコード
  int width, height;
  uint8_t* decoded = WebPDecodeARGB(image, length, &width, &height);
  if (decoded == NULL) {
    return nil;
  }

  // デコードしたバッファから CGDataProvider を作成
  self.size = CGSizeMake(width, height);
  CGDataProviderRef provider =
    CGDataProviderCreateWithData(NULL, decoded, width * 4 * height, releaseBuffer);

  // CGDataProvider から CGImage を作成
  CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
  CGImageRef cgImage = CGImageCreate(width,
    height,
    8,         // ビット深度、デコードバッファは uint8 なので 8bit
    32,        // ピクセルあたりのビット数、8x4(ARGB) なので 32bit
    width * 4, // 1ラインあたりのバイト数、4byte(32bit) かける幅
    space,
    kCGImageAlphaNoneSkipFirst, // 1byte目のアルファ値を無視する
    provider,
    NULL,
    NO,
    kCGRenderingIntentDefault);

  // CGImage から UIImage を作成
  UIImage* uiImage = [UIImage imageWithCGImage:cgImage];

  CGImageRelease(cgImage);
  CGColorSpaceRelease(space);
  CGDataProviderRelease(provider);

  return uiImage;
}

static void releaseBuffer(void *info, const void *data, size_t size)
{
  // WebPDecodeARGB で取得したバッファは free で開放します。
  free((void*)data);
}

 描画速度

測定したところ JPEG が 1~10ms ぐらいに対して 10 ~ 100ms なので10倍程度かかってます。一方でファイルサイズは半減しているのでネットワークからファイルを取得する場合は向いているかもしれません。

24
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
26