145 lines
8.0 KiB
C++
145 lines
8.0 KiB
C++
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <emscripten.h>
|
|
#include <emscripten/bind.h>
|
|
#include "libwebp/src/webp/encode.h"
|
|
#include "libwebp/src/webp/decode.h"
|
|
|
|
using namespace emscripten;
|
|
|
|
class WebPEnc {
|
|
public:
|
|
WebPEnc() { this->ready = false; this->picAlloc = false; }
|
|
~WebPEnc() { this->reset(); }
|
|
bool init() {
|
|
if (this->ready) { return false; }
|
|
WebPPictureInit(&(this->pic));
|
|
WebPMemoryWriterInit(&(this->writer));
|
|
this->pic.writer = WebPMemoryWrite;
|
|
this->pic.custom_ptr = &(this->writer);
|
|
WebPConfigInit(&(this->config));
|
|
this->ready = true;
|
|
return true;
|
|
}
|
|
void reset() {
|
|
if (!this->ready) { return; }
|
|
if (this->picAlloc) { WebPPictureFree(&(this->pic)); }
|
|
WebPMemoryWriterClear(&(this->writer));
|
|
this->ready = false;
|
|
this->picAlloc = false;
|
|
}
|
|
// Clunky workaround for Embind not supporting pointers to primitives (first argument should be a const uint8_t *)
|
|
bool loadRGBA(const int input, int width, int height) {
|
|
if (!this->ready) { return false; }
|
|
this->pic.width = width;
|
|
this->pic.height = height;
|
|
WebPPictureImportRGBA(&(this->pic), reinterpret_cast<const uint8_t *>(input), width * 4);
|
|
this->picAlloc = true;
|
|
return true;
|
|
}
|
|
bool setPreset(int en) {
|
|
if (!this->ready) { return false; }
|
|
if (en > 0) { WebPConfigPreset(&(this->config), (WebPPreset)en, 100.0f); }
|
|
else { WebPConfigInit(&(this->config)); }
|
|
return true;
|
|
}
|
|
bool setLosslessPreset(int en) {
|
|
if (!this->ready) { return false; }
|
|
if (en > 0) { WebPConfigLosslessPreset(&(this->config), en); this->pic.use_argb = 1; }
|
|
else { WebPConfigInit(&(this->config)); this->pic.use_argb = 0; }
|
|
return true;
|
|
}
|
|
bool setQuality(float q) { if (!this->ready) { return false; } this->config.quality = q; return true; }
|
|
bool setMethod(int m) { if (!this->ready) { return false; } this->config.method = m; return true; }
|
|
bool setExact(bool ex) { if (!this->ready) { return false; } this->config.exact = ex ? 1 : 0; return true; }
|
|
int encode() {
|
|
if (!this->ready) { return -1; }
|
|
if (!WebPValidateConfig(&(this->config))) { return -2; }
|
|
if (!WebPEncode(&(this->config), &(this->pic))) { return this->pic.error_code; }
|
|
return 0;
|
|
}
|
|
// Clunky workaround for Embind not supporting pointers to primitives (this should return uint8_t*)
|
|
int getResult() { return (int)this->writer.mem; }
|
|
size_t getResultSize() { return this->writer.size; }
|
|
bool advImageHint(int en) { if (!this->ready) { return false; } this->config.image_hint = (WebPImageHint)en; return true; }
|
|
bool advTargetSize(int s) { if (!this->ready) { return false; } this->config.target_size = s; return true; }
|
|
bool advTargetPSNR(float psnr) { if (!this->ready) { return false; } this->config.target_PSNR = psnr; return true; }
|
|
bool advSegments(int seg) { if (!this->ready) { return false; } this->config.segments = seg; return true; }
|
|
bool advSnsStrength(int str) { if (!this->ready) { return false; } this->config.sns_strength = str; return true; }
|
|
bool advFilterStrength(int str) { if (!this->ready) { return false; } this->config.filter_strength = str; return true; }
|
|
bool advFilterSharpness(int shr) { if (!this->ready) { return false; } this->config.filter_sharpness = shr ? 1 : 0; return true; }
|
|
bool advFilterType(int type) { if (!this->ready) { return false; } this->config.filter_type = type ? 1 : 0; return true; }
|
|
bool advAutoFilter(int filter) { if (!this->ready) { return false; } this->config.autofilter = filter ? 1 : 0; return true; }
|
|
bool advAlphaCompression(int comp) { if (!this->ready) { return false; } this->config.alpha_compression = comp; return true; }
|
|
bool advAlphaFiltering(int filter) { if (!this->ready) { return false; } this->config.alpha_filtering = filter; return true; }
|
|
bool advAlphaQuality(int qual) { if (!this->ready) { return false; } this->config.alpha_quality = qual; return true; }
|
|
bool advPass(int pass) { if (!this->ready) { return false; } this->config.pass = pass; return true; }
|
|
bool advShowCompressed(int comp) { if (!this->ready) { return false; } this->config.show_compressed = comp ? 1 : 0; return true; }
|
|
bool advPreprocessing(int prepro) { if (!this->ready) { return false; } this->config.preprocessing = prepro; return true; }
|
|
bool advPartitions(int parts) { if (!this->ready) { return false; } this->config.partitions = parts; return true; }
|
|
bool advPartitionLimit(int limit) { if (!this->ready) { return false; } this->config.partition_limit = limit; return true; }
|
|
bool advEmulateJpegSize(int emulate) { if (!this->ready) { return false; } this->config.emulate_jpeg_size = emulate ? 1 : 0; return true; }
|
|
bool advThreadLevel(int threads) { if (!this->ready) { return false; } this->config.thread_level = threads; return true; }
|
|
bool advLowMemory(int low) { if (!this->ready) { return false; } this->config.low_memory = low ? 1 : 0; return true; }
|
|
bool advNearLossless(int near) { if (!this->ready) { return false; } this->config.near_lossless = near; return true; }
|
|
bool advUseDeltaPalette(int delta) { if (!this->ready) { return false; } this->config.use_delta_palette = 0 /*delta*/; return true; }
|
|
bool advUseSharpYUV(int sharp) { if (!this->ready) { return false; } this->config.use_sharp_yuv = sharp ? 1 : 0; return true; }
|
|
bool advQMin(int min) { if (!this->ready) { return false; } this->config.qmin = min; return true; }
|
|
bool advQMax(int max) { if (!this->ready) { return false; } this->config.qmax = max; return true; }
|
|
private:
|
|
bool ready;
|
|
bool picAlloc;
|
|
WebPConfig config;
|
|
WebPPicture pic;
|
|
WebPMemoryWriter writer;
|
|
};
|
|
// Encoder hooks
|
|
EMSCRIPTEN_BINDINGS(WebPBinding) {
|
|
class_<WebPEnc>("WebPEnc")
|
|
.constructor<>()
|
|
.function("init", &WebPEnc::init)
|
|
.function("reset", &WebPEnc::reset)
|
|
.function("loadRGBA", &WebPEnc::loadRGBA)
|
|
.function("setPreset", &WebPEnc::setPreset)
|
|
.function("setLosslessPreset", &WebPEnc::setLosslessPreset)
|
|
.function("setQuality", &WebPEnc::setQuality)
|
|
.function("setMethod", &WebPEnc::setMethod)
|
|
.function("setExact", &WebPEnc::setExact)
|
|
.function("encode", &WebPEnc::encode)
|
|
.function("getResult", &WebPEnc::getResult)
|
|
.function("getResultSize", &WebPEnc::getResultSize)
|
|
.function("advImageHint", &WebPEnc::advImageHint)
|
|
.function("advTargetSize", &WebPEnc::advTargetSize)
|
|
.function("advTargetPSNR", &WebPEnc::advTargetPSNR)
|
|
.function("advSegments", &WebPEnc::advSegments)
|
|
.function("advSnsStrength", &WebPEnc::advSnsStrength)
|
|
.function("advFilterStrength", &WebPEnc::advFilterStrength)
|
|
.function("advFilterSharpness", &WebPEnc::advFilterSharpness)
|
|
.function("advFilterType", &WebPEnc::advFilterType)
|
|
.function("advAutoFilter", &WebPEnc::advAutoFilter)
|
|
.function("advAlphaCompression", &WebPEnc::advAlphaCompression)
|
|
.function("advAlphaFiltering", &WebPEnc::advAlphaFiltering)
|
|
.function("advAlphaQuality", &WebPEnc::advAlphaQuality)
|
|
.function("advPass", &WebPEnc::advPass)
|
|
.function("advShowCompressed", &WebPEnc::advShowCompressed)
|
|
.function("advPreprocessing", &WebPEnc::advPreprocessing)
|
|
.function("advPartitions", &WebPEnc::advPartitions)
|
|
.function("advPartitionLimit", &WebPEnc::advPartitionLimit)
|
|
.function("advEmulateJpegSize", &WebPEnc::advEmulateJpegSize)
|
|
.function("advThreadLevel", &WebPEnc::advThreadLevel)
|
|
.function("advLowMemory", &WebPEnc::advLowMemory)
|
|
.function("advNearLossless", &WebPEnc::advNearLossless)
|
|
.function("advUseDeltaPalette", &WebPEnc::advUseDeltaPalette)
|
|
.function("advUseSharpYUV", &WebPEnc::advUseSharpYUV)
|
|
.function("advQMin", &WebPEnc::advQMin)
|
|
.function("advQMax", &WebPEnc::advQMax);
|
|
}
|
|
extern "C" {
|
|
// Decoder
|
|
EMSCRIPTEN_KEEPALIVE uint8_t *decodeRGBA(const uint8_t *data, size_t dataSize) { return WebPDecodeRGBA(data, dataSize, 0, 0); }
|
|
EMSCRIPTEN_KEEPALIVE void decodeFree(uint8_t *data) { WebPFree(data); }
|
|
// Utility
|
|
EMSCRIPTEN_KEEPALIVE uint8_t *allocBuffer(size_t size) { return (uint8_t*)malloc(size * sizeof(uint8_t)); }
|
|
EMSCRIPTEN_KEEPALIVE void destroyBuffer(uint8_t *p) { free(p); }
|
|
}
|