Skip to content

Instantly share code, notes, and snippets.

@usagi
Last active March 19, 2025 20:38
Show Gist options
  • Save usagi/10aaba329af481095923 to your computer and use it in GitHub Desktop.
Save usagi/10aaba329af481095923 to your computer and use it in GitHub Desktop.
CMake プロジェクトの C++ アプリで webp 形式の読み書きに libwebp で対応することはじめ ref: http://qiita.com/usagi/items/38589f87a7a88ad1ddcb
cmake_minimum_required( VERSION 3.2 )
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
link_directories(${CMAKE_CURRENT_BINARY_DIR}/lib)
include( ExternalProject )
ExternalProject_Add( external_libwebp
# https://github.com/webmproject/libwebp
# http://www.webmproject.org/
GIT_REPOSITORY [email protected]:webmproject/libwebp.git
# v0.5.0 タグなどには cmake が無くて少し手間が増えるのでとりあえず master
GIT_TAG master
# WEBP 系のオプションは webp リポジトリーの CMakeLists.txt 冒頭にわかりやすく整理されているよ
# おまけツールの cwebp, dwebp コマンドのビルドを on にする場合は libjpeg が必要になるのでとりあえず off にしておくよ
CMAKE_ARGS -DWEBP_BUILD_CWEBP=off
-DWEBP_BUILD_DWEBP=off
-DWEBP_EXPERIMENTAL_FEATURES=on
-DWEBP_FORCE_ALIGNED=on
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_COMPILER_IS_GNUCXX=${CMAKE_COMPILER_IS_GNUCXX}
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_C_FLAGS=${GL_BINDING_C_FLAGS}
# cmake -> ninja -> install ターゲットなどしたいところだけどカスタムプリフィックスの挙動がおかしいようなので install だけごりごり書いておく
INSTALL_COMMAND
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/external/libwebp/src/external_libwebp/src/webp ${CMAKE_CURRENT_BINARY_DIR}/include/webp
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/external/libwebp/src/external_libwebp-build/include ${CMAKE_CURRENT_BINARY_DIR}/include
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/external/libwebp/src/external_libwebp-build/libwebp.a ${CMAKE_CURRENT_BINARY_DIR}/lib/libwebp.a
# cwebp, dwebp もビルドする時は付ける
#COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/external/libwebp/src/external_libwebp-build/cwebp.exe ${CMAKE_CURRENT_BINARY_DIR}/bin/cwebp.exe
#COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/external/libwebp/src/external_libwebp-build/dwebp.exe ${CMAKE_CURRENT_BINARY_DIR}/bin/dwebp.exe
)
#include <webp/decode.h>
#include <webp/encode.h>
#include <webp/types.h>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <vector>
auto main() -> int
{
// メモリーに 256 pixels * 256 pixels * 4 elements な変換元の入力画像データを適当に作るよ
constexpr auto in_width = 256;
constexpr auto in_height = 256;
constexpr auto in_elements = 4;
std::vector< std::uint8_t > in( in_width * in_height * in_elements );
for ( int y = 0 ; y < in_height; ++y )
for ( int x = 0 ; x < in_width; ++x )
{
in[ y * in_width * in_elements + x * in_elements + 0] = x;
in[ y * in_width * in_elements + x * in_elements + 1] = 0;
in[ y * in_width * in_elements + x * in_elements + 2] = y;
in[ y * in_width * in_elements + x * in_elements + 3] = 255;
}
// webp 形式に変換した結果をこれに入れるよ
std::uint8_t* out_data = nullptr;
auto out_size = 0ull;
constexpr auto in_stride = in_width * in_elements;
const auto write_file = [&]( const auto& filename )
{
std::ofstream o( filename, std::ios::binary );
o.write( reinterpret_cast< const char* >( out_data ), out_size );
if ( o.bad() )
return EXIT_FAILURE;
};
#ifndef LOSSLESS
// ロッシーで最高品質の webp に変換してファイルを出力してみる
{
constexpr auto out_quality_factor = 100.0f;
out_size = WebPEncodeRGBA
( in.data(), in_width, in_height, in_stride
, out_quality_factor
, &out_data
);
write_file( "lossy-100.webp" );
}
#else
// ロスレスで最高品質の webp に変換してファイルを出力してみる
{
out_size = WebPEncodeLosslessRGBA
( in.data(), in_width, in_height, in_stride
, &out_data
);
write_file( "lossless.webp" );
}
#endif
}
#include <webp/decode.h>
#include <webp/encode.h>
#include <webp/types.h>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <vector>
auto main() -> int
{
std::ifstream i( "hoge.lossless.webp", std::ios::binary );
std::vector< std::uint8_t > in
( ( std::istreambuf_iterator< char >( i ) )
, ( std::istreambuf_iterator< char >( ) )
);
// 対象のバイナリーデータが webp 形式か確認(†1)
if ( WebPGetInfo( in.data(), in.size(), nullptr, nullptr ) == 0 )
return EXIT_FAILURE;
int width = 0;
int height = 0;
const auto deleter = []( auto* p ){ free( p ); };
const std::unique_ptr< std::uint8_t, decltype( deleter ) > decoded_data
( WebPDecodeRGBA( in.data(), in.size(), &width, &height )
, deleter
);
);
/* 読みだした画像でお好みの処理をどうぞ */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment