PassOwnPtr<JPEGImageEncoderState> JPEGImageEncoderState::create(const IntSize& imageSize, const double& quality, Vector<unsigned char>* output)
{
    if (imageSize.width() <= 0 || imageSize.height() <= 0)
        return nullptr;

    OwnPtr<JPEGImageEncoderStateImpl> encoderState = adoptPtr(new JPEGImageEncoderStateImpl());

    jpeg_compress_struct* cinfo = encoderState->cinfo();
    jpeg_error_mgr* error = encoderState->error();
    cinfo->err = jpeg_std_error(error);
    error->error_exit = handleError;

    jmp_buf jumpBuffer;
    cinfo->client_data = &jumpBuffer;

    if (setjmp(jumpBuffer)) {
        return nullptr;
    }

    JPEGOutputBuffer* destination = encoderState->outputBuffer();
    destination->output = output;

    jpeg_create_compress(cinfo);
    cinfo->dest = destination;
    cinfo->dest->init_destination = prepareOutput;
    cinfo->dest->empty_output_buffer = writeOutput;
    cinfo->dest->term_destination = finishOutput;

    cinfo->image_height = imageSize.height();
    cinfo->image_width = imageSize.width();
    cinfo->in_color_space = JCS_RGB;
    cinfo->input_components = 3;

    jpeg_set_defaults(cinfo);
    int compressionQuality = JPEGImageEncoder::computeCompressionQuality(quality);
    jpeg_set_quality(cinfo, compressionQuality, TRUE);
    disableSubsamplingForHighQuality(cinfo, compressionQuality);
    jpeg_start_compress(cinfo, TRUE);

    cinfo->client_data = 0;
    return encoderState.release();
}
Example #2
0
static bool encodePixels(IntSize imageSize, unsigned char* inputPixels, bool premultiplied, int quality, Vector<unsigned char>* output)
{
    JPEGOutputBuffer destination;
    destination.output = output;
    Vector<JSAMPLE> row;

    jpeg_compress_struct cinfo;
    jpeg_error_mgr error;
    cinfo.err = jpeg_std_error(&error);
    error.error_exit = handleError;
    jmp_buf jumpBuffer;
    cinfo.client_data = &jumpBuffer;

    if (setjmp(jumpBuffer)) {
        jpeg_destroy_compress(&cinfo);
        return false;
    }

    jpeg_create_compress(&cinfo);
    cinfo.dest = &destination;
    cinfo.dest->init_destination = prepareOutput;
    cinfo.dest->empty_output_buffer = writeOutput;
    cinfo.dest->term_destination = finishOutput;

    imageSize.clampNegativeToZero();
    cinfo.image_height = imageSize.height();
    cinfo.image_width = imageSize.width();

#if defined(JCS_EXTENSIONS)
    if (premultiplied) {
        cinfo.in_color_space = SK_B32_SHIFT ? JCS_EXT_RGBX : JCS_EXT_BGRX;

        cinfo.input_components = 4;

        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, quality, TRUE);
        disableSubsamplingForHighQuality(&cinfo, quality);
        jpeg_start_compress(&cinfo, TRUE);

        unsigned char* pixels = inputPixels;
        const size_t pixelRowStride = cinfo.image_width * 4;
        while (cinfo.next_scanline < cinfo.image_height) {
            jpeg_write_scanlines(&cinfo, &pixels, 1);
            pixels += pixelRowStride;
        }

        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        return true;
    }
#endif

    cinfo.in_color_space = JCS_RGB;
    cinfo.input_components = 3;

    void (*extractRowRGB)(const unsigned char*, unsigned int, unsigned char* output);
    extractRowRGB = &RGBAtoRGB;
    if (premultiplied)
        extractRowRGB = &preMultipliedBGRAtoRGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    disableSubsamplingForHighQuality(&cinfo, quality);
    jpeg_start_compress(&cinfo, TRUE);

    unsigned char* pixels = inputPixels;
    row.resize(cinfo.image_width * cinfo.input_components);
    const size_t pixelRowStride = cinfo.image_width * 4;
    while (cinfo.next_scanline < cinfo.image_height) {
        JSAMPLE* rowData = row.data();
        extractRowRGB(pixels, cinfo.image_width, rowData);
        jpeg_write_scanlines(&cinfo, &rowData, 1);
        pixels += pixelRowStride;
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    return true;
}