예제 #1
0
파일: _webp.c 프로젝트: dvska/Pillow
PyObject* _anim_encoder_add(PyObject* self, PyObject* args)
{
    uint8_t* rgb;
    Py_ssize_t size;
    int timestamp;
    int width;
    int height;
    char* mode;
    int lossless;
    float quality_factor;
    int method;
    WebPConfig config;
    WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
    WebPAnimEncoder* enc = encp->enc;
    WebPPicture* frame = &(encp->frame);

    if (!PyArg_ParseTuple(args, "z#iiisifi",
        (char**)&rgb, &size, &timestamp, &width, &height, &mode,
        &lossless, &quality_factor, &method)) {
        return NULL;
    }

    // Check for NULL frame, which sets duration of final frame
    if (!rgb) {
        WebPAnimEncoderAdd(enc, NULL, timestamp, NULL);
        Py_RETURN_NONE;
    }

    // Setup config for this frame
    if (!WebPConfigInit(&config)) {
        PyErr_SetString(PyExc_RuntimeError, "failed to initialize config!");
        return NULL;
    }
    config.lossless = lossless;
    config.quality = quality_factor;
    config.method = method;

    // Validate the config
    if (!WebPValidateConfig(&config)) {
        PyErr_SetString(PyExc_ValueError, "invalid configuration");
        return NULL;
    }

    // Populate the frame with raw bytes passed to us
    frame->width = width;
    frame->height = height;
    frame->use_argb = 1; // Don't convert RGB pixels to YUV
    if (strcmp(mode, "RGBA")==0) {
        WebPPictureImportRGBA(frame, rgb, 4 * width);
    } else if (strcmp(mode, "RGBX")==0) {
        WebPPictureImportRGBX(frame, rgb, 4 * width);
    }

    // Add the frame to the encoder
    if (!WebPAnimEncoderAdd(enc, frame, timestamp, &config)) {
        PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc));
        return NULL;
    }

    Py_RETURN_NONE;
}
예제 #2
0
파일: _webp.c 프로젝트: dvska/Pillow
PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args)
{
    uint8_t* icc_bytes;
    uint8_t* exif_bytes;
    uint8_t* xmp_bytes;
    Py_ssize_t icc_size;
    Py_ssize_t exif_size;
    Py_ssize_t xmp_size;
    WebPData webp_data;
    WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
    WebPAnimEncoder* enc = encp->enc;
    WebPMux* mux = NULL;
    PyObject* ret = NULL;

    if (!PyArg_ParseTuple(args, "s#s#s#",
    &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) {
        return NULL;
    }

    // Init the output buffer
    WebPDataInit(&webp_data);

    // Assemble everything into the output buffer
    if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
        PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc));
        return NULL;
    }

    // Re-mux to add metadata as needed
    if (icc_size > 0 || exif_size > 0 || xmp_size > 0) {
        WebPMuxError err = WEBP_MUX_OK;
        int i_icc_size = (int)icc_size;
        int i_exif_size = (int)exif_size;
        int i_xmp_size = (int)xmp_size;
        WebPData icc_profile = { icc_bytes, i_icc_size };
        WebPData exif = { exif_bytes, i_exif_size };
        WebPData xmp = { xmp_bytes, i_xmp_size };

        mux = WebPMuxCreate(&webp_data, 1);
        if (mux == NULL) {
            PyErr_SetString(PyExc_RuntimeError, "could not re-mux to add metadata");
            return NULL;
        }
        WebPDataClear(&webp_data);

        // Add ICCP chunk
        if (i_icc_size > 0) {
            err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, 1);
            if (err != WEBP_MUX_OK) {
                return HandleMuxError(err, "ICCP");
            }
        }

        // Add EXIF chunk
        if (i_exif_size > 0) {
            err = WebPMuxSetChunk(mux, "EXIF", &exif, 1);
            if (err != WEBP_MUX_OK) {
                return HandleMuxError(err, "EXIF");
            }
        }

        // Add XMP chunk
        if (i_xmp_size > 0) {
            err = WebPMuxSetChunk(mux, "XMP ", &xmp, 1);
            if (err != WEBP_MUX_OK) {
                return HandleMuxError(err, "XMP");
            }
        }

        err = WebPMuxAssemble(mux, &webp_data);
        if (err != WEBP_MUX_OK) {
            return HandleMuxError(err, NULL);
        }
    }

    // Convert to Python bytes
    ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size);
    WebPDataClear(&webp_data);

    // If we had to re-mux, we should free it now that we're done with it
    if (mux != NULL) {
        WebPMuxDelete(mux);
    }

    return ret;
}
예제 #3
0
/* Save an animation to disk */
gboolean save_animation(gint32          nLayers,
                        gint32         *allLayers,
                        FILE           *outfile,
                        WebPSaveParams *params,
                        GError        **error)
{
    gboolean               status          = FALSE;
    gboolean               innerStatus     = TRUE;
    WebPAnimEncoderOptions enc_options;
    WebPAnimEncoder       *enc             = NULL;
    int                    frame_timestamp = 0;
    WebPData               webp_data       = {0};
    WebPMux               *mux;
    WebPMuxAnimParams      anim_params     = {0};

    /* Prepare for encoding an animation */
    WebPAnimEncoderOptionsInit(&enc_options);

    do {
        int i;
        gint32 drawable_ID = allLayers[0];

        /* Create the encoder */
        enc = WebPAnimEncoderNew(gimp_drawable_width(drawable_ID),
                                 gimp_drawable_height(drawable_ID),
                                 &enc_options);

        /* Encode each layer */
        for (i = 0; i < nLayers; i++) {
            if ((innerStatus = save_layer(allLayers[i],
                                          NULL,
                                          NULL,
                                          TRUE,
                                          enc,
                                          frame_timestamp,
                                          params,
                                          error)) == FALSE) {
                break;
            }
        }

        /* Check to make sure each layer was encoded correctly */
        if (innerStatus == FALSE) {
            break;
        }

        /* Add NULL frame */
        WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL);

        /* Initialize the WebP image structure */
        WebPDataInit(&webp_data);

        /* Write the animation to the image */
        if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
            g_set_error(error,
                        G_FILE_ERROR,
                        0,
                        "Encoding error: '%s'",
                        WebPAnimEncoderGetError(enc));
            break;
        }

        /* Create a Mux */
        mux = WebPMuxCreate(&webp_data, 1);

        /* Set animation parameters */
        anim_params.loop_count = params->loop == TRUE ? 0 : 1;
        WebPMuxSetAnimationParams(mux, &anim_params);

        /* Assemble the image */
        WebPMuxAssemble(mux, &webp_data);

        /* Write to disk */
        if (fwrite(webp_data.bytes, webp_data.size, 1, outfile) != 1) {
            break;
        }

        /* Everything succeeded */
        status = TRUE;

    } while(0);

    /* Free image data */
    WebPDataClear(&webp_data);

    /* Free the animation encoder */
    if (enc) {
        WebPAnimEncoderDelete(enc);
    }

    return status;
}