1/* 2 * Copyright (C) 2010 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "ImageBuffer.h" 21 22#include "CairoUtilities.h" 23#include "GdkCairoUtilities.h" 24#include "GRefPtrGtk.h" 25#include "MIMETypeRegistry.h" 26#include <cairo.h> 27#include <gtk/gtk.h> 28#include <wtf/gobject/GUniquePtr.h> 29#include <wtf/text/Base64.h> 30#include <wtf/text/CString.h> 31#include <wtf/text/WTFString.h> 32 33namespace WebCore { 34 35static bool encodeImage(cairo_surface_t* surface, const String& mimeType, const double* quality, GUniqueOutPtr<gchar>& buffer, gsize& bufferSize) 36{ 37 // List of supported image encoding types comes from the GdkPixbuf documentation. 38 // http://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-File-saving.html#gdk-pixbuf-save-to-bufferv 39 40 String type = mimeType.substring(sizeof "image"); 41 if (type != "jpeg" && type != "png" && type != "tiff" && type != "ico" && type != "bmp") 42 return false; 43 44 GRefPtr<GdkPixbuf> pixbuf; 45 if (type == "jpeg") { 46 // JPEG doesn't support alpha channel. The <canvas> spec states that toDataURL() must encode a Porter-Duff 47 // composite source-over black for image types that do not support alpha. 48 RefPtr<cairo_surface_t> newSurface; 49 if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE) { 50 newSurface = adoptRef(cairo_image_surface_create_for_data(cairo_image_surface_get_data(surface), 51 CAIRO_FORMAT_RGB24, 52 cairo_image_surface_get_width(surface), 53 cairo_image_surface_get_height(surface), 54 cairo_image_surface_get_stride(surface))); 55 } else { 56 IntSize size = cairoSurfaceSize(surface); 57 newSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24, size.width(), size.height())); 58 RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get())); 59 cairo_set_source_surface(cr.get(), surface, 0, 0); 60 cairo_paint(cr.get()); 61 } 62 pixbuf = adoptGRef(cairoSurfaceToGdkPixbuf(newSurface.get())); 63 } else 64 pixbuf = adoptGRef(cairoSurfaceToGdkPixbuf(surface)); 65 if (!pixbuf) 66 return false; 67 68 GUniqueOutPtr<GError> error; 69 if (type == "jpeg" && quality && *quality >= 0.0 && *quality <= 1.0) { 70 String qualityString = String::format("%d", static_cast<int>(*quality * 100.0 + 0.5)); 71 gdk_pixbuf_save_to_buffer(pixbuf.get(), &buffer.outPtr(), &bufferSize, type.utf8().data(), &error.outPtr(), "quality", qualityString.utf8().data(), NULL); 72 } else 73 gdk_pixbuf_save_to_buffer(pixbuf.get(), &buffer.outPtr(), &bufferSize, type.utf8().data(), &error.outPtr(), NULL); 74 75 return !error; 76} 77 78String ImageBuffer::toDataURL(const String& mimeType, const double* quality, CoordinateSystem) const 79{ 80 ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); 81 82 GUniqueOutPtr<gchar> buffer; 83 gsize bufferSize; 84 if (!encodeImage(m_data.m_surface.get(), mimeType, quality, buffer, bufferSize)) 85 return "data:,"; 86 87 Vector<char> base64Data; 88 base64Encode(buffer.get(), bufferSize, base64Data); 89 90 return "data:" + mimeType + ";base64," + base64Data; 91} 92 93} 94