Commits

Fredrik Lundh committed 18f2d5d

Fixed WebP write support, including quality setting.

  • Participants
  • Parent commits c2ca2b6

Comments (0)

Files changed (5)

PIL/WebPImagePlugin.py

 def _save(im, fp, filename):
     if im.mode != "RGB":
         raise IOError("cannot write mode %s as WEBP" % im.mode)
+    im.encoderconfig = (
+        im.encoderinfo.get("quality", 0),
+        )
     ImageFile._save(im, fp, [("webp", (0, 0) + im.size, 0, (im.mode,))])
 
 #
 
     char* mode;
     char* rawmode;
-    if (!PyArg_ParseTuple(args, ARG("ss", "ss"), &mode, &rawmode))
+    int quality = 0;
+    if (!PyArg_ParseTuple(args, ARG("ss|i", "ss|i"), &mode, &rawmode,
+			  &quality))
 	return NULL;
 
-    encoder = PyImaging_EncoderNew(sizeof(WEBPSTATE));
+    encoder = PyImaging_EncoderNew(sizeof(WEBPCONTEXT));
     if (encoder == NULL)
 	return NULL;
 
 
     encoder->encode = ImagingWebPEncode;
 
+    ((WEBPCONTEXT*)encoder->state.context)->quality = quality;
+
     return (PyObject*) encoder;
 }
 #endif

libImaging/WebP.h

 
     /* CONFIGURATION */
 
+    /* Quality (1-100, 0 means default) */
+    int quality;
+
     /* INTERNAL */
+    uint8_t* output_data; /* pointer to next data chunk */
+    size_t output_size; /* bytes left to copy */
 
-} WEBPSTATE;
+    uint8_t* output_buffer; /* pointer to output data buffer*/
+
+} WEBPCONTEXT;

libImaging/WebPDecode.c

 int
 ImagingWebPDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
 {
-    /* WEBPSTATE* webpstate = state->context; */
     UINT32 image_size;
     UINT8* image_data;
     int y, xsize, ysize;

libImaging/WebPEncode.c

 int
 ImagingWebPEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
 {
+    WEBPCONTEXT* context = (WEBPCONTEXT*) state->context;
+
     UINT8* buffer;
     UINT8* ptr;
-    uint8_t* output_data;
+    uint8_t* output_ptr;
     size_t output_size;
     int y, stride;
+    float quality = 75.0F;
 
-    /* do this in state 0 */
+    if (!state->state) {
+	/* copy image contents to packed buffer and compress it */
 
-    stride = state->xsize * 3;
+	stride = state->xsize * 3;
 
-    buffer = malloc(im->ysize * stride);
-    if (!buffer) {
-	state->errcode = IMAGING_CODEC_MEMORY;
-        return -1;
+	buffer = malloc(im->ysize * stride);
+
+	if (!buffer) {
+	    state->errcode = IMAGING_CODEC_MEMORY;
+	    return -1;
+	}
+	for (ptr = buffer, y = 0; y < state->ysize; ptr += stride, y++) {
+	    state->shuffle(ptr, (UINT8*) im->image[y + state->yoff] +
+			   state->xoff * im->pixelsize, state->xsize);
+	}
+
+	if (context->quality > 0)
+	    quality = (float) context->quality;
+
+	context->output_size = WebPEncodeRGB(buffer,
+					     state->xsize, state->ysize,
+					     stride, quality,
+					     &context->output_data);
+
+	if (!context->output_size) {
+	    state->errcode = IMAGING_CODEC_BROKEN;
+	    return -1;
+	}
+
+	state->state++;
+
+	/* keep a pointer to the full buffer */
+	context->output_buffer = context->output_data;
+
     }
 
-    for (ptr = buffer, y = 0; y < state->ysize; ptr += stride, y++) {
-        state->shuffle(ptr, (UINT8*) im->image[y + state->yoff] +
-		       state->xoff * im->pixelsize, state->xsize);
+    if (context->output_size < bytes) {
+	/* copy remaining part to output buffer */
+        memcpy(buf, context->output_data, context->output_size);
+	state->errcode = IMAGING_CODEC_END;
+	free(context->output_buffer);
+	return context->output_size;
+    } else {
+	/* fill the buffer */
+	memcpy(buf, context->output_data, bytes);
+	context->output_data += bytes;
+	context->output_size -= bytes;
+	return bytes;
     }
-
-    output_size = WebPEncodeRGB(buffer, state->xsize, state->ysize, stride,
-				75.f, &output_data);
-
-    if (!output_size) {
-	state->errcode = IMAGING_CODEC_BROKEN;
-	return -1;
-    }
-
-    /* return data piecewise in state 1 */
-
-    state->errcode = IMAGING_CODEC_END;
-
-    ptr = buf;
-
-    if (output_size < bytes) {
-        memcpy(buf, output_data, output_size);
-	ptr += output_size;
-    }
-
-    return ptr - buf;
 }
 
 #endif