Added WebP advanced options.

This commit is contained in:
Taishi Ikai 2015-06-05 14:28:53 +09:00
parent 9f79e4a320
commit 26f58424cc
2 changed files with 152 additions and 16 deletions

View File

@ -56,6 +56,26 @@ def _save(im, fp, filename):
quality = im.encoderinfo.get("quality", 80)
icc_profile = im.encoderinfo.get("icc_profile", "")
exif = im.encoderinfo.get("exif", "")
preset = im.encoderinfo.get("preset", 0) # 0:default 1:pict 2:photo 3:draw 4:icon 5:text
method = im.encoderinfo.get("method", 4)
target_size = im.encoderinfo.get("target_size", 0)
target_PSNR = im.encoderinfo.get("target_PSNR", 0.0)
segments = im.encoderinfo.get("segments", 4)
sns_strength = im.encoderinfo.get("sns_strength", 50)
filter_strength = im.encoderinfo.get("filter_strength", 60)
filter_sharpness = im.encoderinfo.get("filter_sharpness", 0)
filter_type = im.encoderinfo.get("filter_type", 1) # 0:simple 1:strong
autofilter = im.encoderinfo.get("autofilter", False)
alpha_compression = im.encoderinfo.get("alpha_compression", True)
alpha_filtering = im.encoderinfo.get("alpha_filtering", 1) # 0:none 1:fast 2:best
alpha_quality = im.encoderinfo.get("alpha_quality", 100)
pass_count = im.encoderinfo.get("pass", 1) # 1-10
preprocessing = im.encoderinfo.get("preprocessing", 0) # 0:none 1:segment-smooth 2:pseudo-random dithering
partitions = im.encoderinfo.get("partitions", 0) # 0-3
partition_limit = im.encoderinfo.get("partition_limit", 0) # 0-100
emulate_jpeg_size = im.encoderinfo.get("emulate_jpeg_size", False)
thread_level = im.encoderinfo.get("thread_level", 0)
low_memory = im.encoderinfo.get("low_memory", False)
data = _webp.WebPEncode(
im.tobytes(),
@ -65,7 +85,27 @@ def _save(im, fp, filename):
float(quality),
im.mode,
icc_profile,
exif
exif,
preset,
method,
target_size,
float(target_PSNR),
segments,
sns_strength,
filter_strength,
filter_sharpness,
filter_type,
autofilter,
alpha_compression,
alpha_filtering,
alpha_quality,
pass_count,
preprocessing,
partitions,
partition_limit,
emulate_jpeg_size,
thread_level,
low_memory
)
if data is None:
raise IOError("cannot write file as WEBP (encoder returned None)")

124
_webp.c
View File

@ -9,12 +9,85 @@
#include <webp/mux.h>
#endif
PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
{
struct option {
int width;
int height;
int lossless;
float quality_factor;
float quality;
int preset;
int method;
int target_size;
float target_PSNR;
int segments;
int sns_strength;
int filter_strength;
int filter_sharpness;
int filter_type;
int autofilter;
int alpha_compression;
int alpha_filtering;
int alpha_quality;
int pass;
int preprocessing;
int partitions;
int partition_limit;
int emulate_jpeg_size;
int thread_level;
int low_memory;
} opt;
int getSizeAfterEncode(struct option *opt, uint8_t** rgb, uint8_t** output, int is_rgba) {
WebPConfig config;
if (!WebPConfigPreset(&config, opt->preset, opt->quality)) return 0;
config.lossless = opt->lossless;
if (opt->preset == 0) {
config.method = opt->method;
config.target_size = opt->target_size;
config.target_PSNR = opt->target_PSNR;
config.segments = opt->segments;
config.sns_strength = opt->sns_strength;
config.filter_strength = opt->filter_strength;
config.filter_sharpness = opt->filter_sharpness;
config.filter_type = opt->filter_type;
config.autofilter = opt->autofilter;
config.alpha_compression = opt->alpha_compression;
config.alpha_filtering = opt->alpha_filtering;
config.alpha_quality = opt->alpha_quality;
config.pass = opt->pass;
config.preprocessing = opt->preprocessing;
config.partitions = opt->partitions;
config.partition_limit = opt->partition_limit;
config.emulate_jpeg_size = opt->emulate_jpeg_size;
config.thread_level = opt->thread_level;
config.low_memory = opt->low_memory;
}
WebPPicture pic;
WebPPictureInit(&pic);
WebPMemoryWriter wrt;
WebPMemoryWriterInit(&wrt);
pic.use_argb = !!opt->lossless;
pic.writer = WebPMemoryWrite;
pic.custom_ptr = &wrt;
pic.width = opt->width;
pic.height = opt->height;
if (is_rgba) {
if (!WebPPictureImportRGBA(&pic, *rgb, 4* opt->width)) return 0;
} else {
if (!WebPPictureImportRGB(&pic, *rgb, 3* opt->width)) return 0;
}
WebPEncode(&config, &pic);
WebPPictureFree(&pic);
(*output) = wrt.mem;
return wrt.size;
}
PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
{
uint8_t *rgb;
uint8_t *icc_bytes;
uint8_t *exif_bytes;
@ -25,34 +98,57 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
Py_ssize_t exif_size;
size_t ret_size;
if (!PyArg_ParseTuple(args, "s#iiifss#s#",
(char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode,
&icc_bytes, &icc_size, &exif_bytes, &exif_size)) {
if (!PyArg_ParseTuple(args, "s#iiifss#s#iiifiiiiiiiiiiiiiiii",
(char**)&rgb, &size,
&opt.width, &opt.height, &opt.lossless,
&opt.quality,
&mode,
&icc_bytes, &icc_size, &exif_bytes, &exif_size,
&opt.preset, &opt.method, &opt.target_size, &opt.target_PSNR,
&opt.segments, &opt.sns_strength,
&opt.filter_strength, &opt.filter_sharpness, &opt.filter_type,
&opt.autofilter,
&opt.alpha_compression, &opt.alpha_filtering, &opt.alpha_quality,
&opt.pass, &opt.preprocessing, &opt.partitions, &opt.partition_limit,
&opt.emulate_jpeg_size, &opt.thread_level, &opt.low_memory
)) {
Py_RETURN_NONE;
}
if (strcmp(mode, "RGBA")==0){
if (size < width * height * 4){
if (size < opt.width * opt.height * 4){
Py_RETURN_NONE;
}
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
if (lossless) {
ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4* width, &output);
if (opt.lossless) {
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 1);
if (!ret_size) {
Py_RETURN_NONE;
}
} else
#endif
{
ret_size = WebPEncodeRGBA(rgb, width, height, 4* width, quality_factor, &output);
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 1);
if (!ret_size) {
Py_RETURN_NONE;
}
}
} else if (strcmp(mode, "RGB")==0){
if (size < width * height * 3){
if (size < opt.width * opt.height * 3){
Py_RETURN_NONE;
}
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
if (lossless) {
ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3* width, &output);
if (opt.lossless) {
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 0);
if (!ret_size) {
Py_RETURN_NONE;
}
} else
#endif
{
ret_size = WebPEncodeRGB(rgb, width, height, 3* width, quality_factor, &output);
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 0);
if (!ret_size) {
Py_RETURN_NONE;
}
}
} else {
Py_RETURN_NONE;