#include <cairo-gl.h>
#endif
+#if ENABLE(TIZEN_CANVAS_TODATAURL_USING_IMAGE_ENCODER)
+#include "ImageData.h"
+#include "png.h"
+#include "jpeglib.h"
+#include <setjmp.h>
+#endif
+
namespace WebCore {
void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
cairo_surface_destroy(surface);
}
#endif
+
+#if ENABLE(TIZEN_CANVAS_TODATAURL_USING_IMAGE_ENCODER)
+/* Unpremultiplies data and converts native endian ARGB => RGBA bytes (from cairo unpremultiply_data) */
+static void preMultipliedARGBtoRGBACallback(png_structp png, png_row_infop row_info, png_bytep data)
+{
+ for (unsigned i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t* b = &data[i];
+ uint32_t pixel;
+
+ memcpy(&pixel, b, sizeof(uint32_t));
+ uint8_t alpha = (pixel & 0xff000000) >> 24;
+ if (!alpha)
+ b[0] = b[1] = b[2] = b[3] = 0;
+ else {
+ b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ b[3] = alpha;
+ }
+ }
+}
+
+static void writePNGCallback(png_structp png, png_bytep data, png_size_t size)
+{
+ static_cast<Vector<unsigned char>*>(png_get_io_ptr(png))->append(data, size);
+}
+
+bool encodeImageDataToPNG(const ImageData& image, Vector<char>* output)
+{
+ IntSize imageSize = image.size();
+ unsigned char* inputPixels = image.data()->data();
+
+ png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ png_info* info = png_create_info_struct(png);
+ if (!png || !info || setjmp(png_jmpbuf(png))) {
+ png_destroy_write_struct(png ? &png : 0, info ? &info : 0);
+ return false;
+ }
+
+ png_set_compression_level(png, 3);
+ png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
+
+ png_set_write_fn(png, output, writePNGCallback, 0);
+ png_set_IHDR(png, info, imageSize.width(), imageSize.height(), 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0, 0);
+ png_write_info(png, info);
+ png_set_write_user_transform_fn(png, preMultipliedARGBtoRGBACallback);
+
+ const size_t pixelRowStride = imageSize.width() * 4;
+ for (int y = 0; y < imageSize.height(); ++y) {
+ png_write_row(png, inputPixels);
+ inputPixels += pixelRowStride;
+ }
+
+ png_write_end(png, info);
+ png_destroy_write_struct(&png, &info);
+
+ return true;
+}
+
+struct JPEGOutputBuffer : public jpeg_destination_mgr {
+ Vector<unsigned char>* output;
+ Vector<unsigned char> buffer;
+};
+
+static void jpegInitCallback(j_compress_ptr cinfo)
+{
+ JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest);
+ out->buffer.resize(8192);
+ out->next_output_byte = out->buffer.data();
+ out->free_in_buffer = out->buffer.size();
+}
+
+static boolean jpegWriteCallback(j_compress_ptr cinfo)
+{
+ JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest);
+ out->output->append(out->buffer.data(), out->buffer.size());
+ out->next_output_byte = out->buffer.data();
+ out->free_in_buffer = out->buffer.size();
+
+ return true;
+}
+
+static void jpegTerminateCallback(j_compress_ptr cinfo)
+{
+ JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest);
+ const size_t size = out->buffer.size() - out->free_in_buffer;
+ out->output->append(out->buffer.data(), size);
+}
+
+static void jpegErrorCallback(j_common_ptr common)
+{
+ jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data);
+ longjmp(*jumpBufferPtr, -1);
+}
+
+bool encodeImageDataToJPEG(const ImageData& image, 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 = jpegErrorCallback;
+ 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 = jpegInitCallback;
+ cinfo.dest->empty_output_buffer = jpegWriteCallback;
+ cinfo.dest->term_destination = jpegTerminateCallback;
+
+ IntSize imageSize = image.size();
+ imageSize.clampNegativeToZero();
+ cinfo.image_height = imageSize.height();
+ cinfo.image_width = imageSize.width();
+
+ cinfo.in_color_space = JCS_RGB;
+ cinfo.input_components = 3;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, quality, true);
+ jpeg_start_compress(&cinfo, true);
+
+ unsigned char* pixels = image.data()->data();;
+ row.resize(cinfo.image_width * cinfo.input_components);
+ const unsigned char* pixelEnd = pixels + cinfo.image_width * cinfo.image_height * 4;
+ while (pixels < pixelEnd) {
+ JSAMPLE* rowdata = row.data();
+ for (const unsigned char* rowEnd = pixels + cinfo.image_width * 4; pixels < rowEnd;) {
+ *rowdata++ = static_cast<JSAMPLE>(*pixels++ & 0xFF);
+ *rowdata++ = static_cast<JSAMPLE>(*pixels++ & 0xFF);
+ *rowdata++ = static_cast<JSAMPLE>(*pixels++ & 0xFF);
+ ++pixels;
+ }
+ rowdata = row.data();
+ jpeg_write_scanlines(&cinfo, &rowdata, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ return true;
+}
+#endif
+
} // namespace WebCore
#endif
}
-#if !PLATFORM(GTK)
+#if !PLATFORM(GTK) && !ENABLE(TIZEN_CANVAS_TODATAURL_USING_IMAGE_ENCODER)
static cairo_status_t writeFunction(void* output, const unsigned char* data, unsigned int length)
{
if (!reinterpret_cast<Vector<unsigned char>*>(output)->tryAppend(data, length))
}
#endif
+#if ENABLE(TIZEN_CANVAS_TODATAURL_USING_IMAGE_ENCODER)
+static bool encodeImage(const ImageData& image, const String& mimeType, const double* quality, Vector<char>* output)
+{
+ if (mimeType == "image/jpeg") {
+ Vector<unsigned char>* encodedImage = reinterpret_cast<Vector<unsigned char>*>(output);
+ int compressionQuality = 65;
+ if (quality && *quality >= 0.0 && *quality <= 1.0)
+ compressionQuality = static_cast<int>(*quality * 100);
+ return encodeImageDataToJPEG(image, compressionQuality, encodedImage);
+ }
+
+ return encodeImageDataToPNG(image, output);
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality, CoordinateSystem) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ IntRect rect(0, 0, m_size.width(), m_size.height());
+ RefPtr<ImageData> imageData = ImageData::create(rect.size(), getPremultipliedImageData(rect));
+
+ Vector<char> encodedImage;
+ if (!imageData || !encodeImage(*imageData, mimeType, quality, &encodedImage))
+ return "data:,";
+
+ Vector<char> base64Data;
+ base64Encode(encodedImage, base64Data);
+
+ return "data:" + mimeType + ";base64," + base64Data;
+}
+#endif
+
} // namespace WebCore