Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion PIL/WebPImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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)")
Expand Down
126 changes: 111 additions & 15 deletions _webp.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,146 @@
#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;
uint8_t *output;
char *mode;
Py_ssize_t size;
Py_ssize_t icc_size;
Py_ssize_t exif_size;
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;
Expand Down