mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 14:54:46 +03:00
Added WebP advanced options.
This commit is contained in:
parent
9f79e4a320
commit
26f58424cc
|
@ -56,6 +56,26 @@ def _save(im, fp, filename):
|
||||||
quality = im.encoderinfo.get("quality", 80)
|
quality = im.encoderinfo.get("quality", 80)
|
||||||
icc_profile = im.encoderinfo.get("icc_profile", "")
|
icc_profile = im.encoderinfo.get("icc_profile", "")
|
||||||
exif = im.encoderinfo.get("exif", "")
|
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(
|
data = _webp.WebPEncode(
|
||||||
im.tobytes(),
|
im.tobytes(),
|
||||||
|
@ -65,7 +85,27 @@ def _save(im, fp, filename):
|
||||||
float(quality),
|
float(quality),
|
||||||
im.mode,
|
im.mode,
|
||||||
icc_profile,
|
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:
|
if data is None:
|
||||||
raise IOError("cannot write file as WEBP (encoder returned None)")
|
raise IOError("cannot write file as WEBP (encoder returned None)")
|
||||||
|
|
126
_webp.c
126
_webp.c
|
@ -9,12 +9,85 @@
|
||||||
#include <webp/mux.h>
|
#include <webp/mux.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
|
|
||||||
{
|
struct option {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int lossless;
|
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 *rgb;
|
||||||
uint8_t *icc_bytes;
|
uint8_t *icc_bytes;
|
||||||
uint8_t *exif_bytes;
|
uint8_t *exif_bytes;
|
||||||
|
@ -22,37 +95,60 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
|
||||||
char *mode;
|
char *mode;
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
Py_ssize_t icc_size;
|
Py_ssize_t icc_size;
|
||||||
Py_ssize_t exif_size;
|
Py_ssize_t exif_size;
|
||||||
size_t ret_size;
|
size_t ret_size;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#iiifss#s#",
|
if (!PyArg_ParseTuple(args, "s#iiifss#s#iiifiiiiiiiiiiiiiiii",
|
||||||
(char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode,
|
(char**)&rgb, &size,
|
||||||
&icc_bytes, &icc_size, &exif_bytes, &exif_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;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
if (strcmp(mode, "RGBA")==0){
|
if (strcmp(mode, "RGBA")==0){
|
||||||
if (size < width * height * 4){
|
if (size < opt.width * opt.height * 4){
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
|
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
|
||||||
if (lossless) {
|
if (opt.lossless) {
|
||||||
ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4* width, &output);
|
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 1);
|
||||||
|
if (!ret_size) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#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){
|
} else if (strcmp(mode, "RGB")==0){
|
||||||
if (size < width * height * 3){
|
if (size < opt.width * opt.height * 3){
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
|
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
|
||||||
if (lossless) {
|
if (opt.lossless) {
|
||||||
ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3* width, &output);
|
ret_size = getSizeAfterEncode(&opt, &rgb, &output, 0);
|
||||||
|
if (!ret_size) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#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 {
|
} else {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user