• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2008 Holger Hans Peter Freyther
4  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 #include "ImageBuffer.h"
30 
31 #include "CString.h"
32 #include "GraphicsContext.h"
33 #include "ImageData.h"
34 #include "MIMETypeRegistry.h"
35 #include "StillImageQt.h"
36 
37 #include <QBuffer>
38 #include <QColor>
39 #include <QImage>
40 #include <QImageWriter>
41 #include <QPainter>
42 #include <QPixmap>
43 #include <math.h>
44 
45 namespace WebCore {
46 
ImageBufferData(const IntSize & size)47 ImageBufferData::ImageBufferData(const IntSize& size)
48     : m_pixmap(size)
49 {
50     m_pixmap.fill(QColor(Qt::transparent));
51 
52     QPainter* painter = new QPainter(&m_pixmap);
53     m_painter.set(painter);
54 
55     // Since ImageBuffer is used mainly for Canvas, explicitly initialize
56     // its painter's pen and brush with the corresponding canvas defaults
57     // NOTE: keep in sync with CanvasRenderingContext2D::State
58     QPen pen = painter->pen();
59     pen.setColor(Qt::black);
60     pen.setWidth(1);
61     pen.setCapStyle(Qt::FlatCap);
62     pen.setJoinStyle(Qt::MiterJoin);
63     pen.setMiterLimit(10);
64     painter->setPen(pen);
65     QBrush brush = painter->brush();
66     brush.setColor(Qt::black);
67     painter->setBrush(brush);
68     painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
69 }
70 
ImageBuffer(const IntSize & size,ImageColorSpace imageColorSpace,bool & success)71 ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
72     : m_data(size)
73     , m_size(size)
74 {
75     m_context.set(new GraphicsContext(m_data.m_painter.get()));
76     success = true;
77 }
78 
~ImageBuffer()79 ImageBuffer::~ImageBuffer()
80 {
81 }
82 
context() const83 GraphicsContext* ImageBuffer::context() const
84 {
85     ASSERT(m_data.m_painter->isActive());
86 
87     return m_context.get();
88 }
89 
image() const90 Image* ImageBuffer::image() const
91 {
92     if (!m_image) {
93         // It's assumed that if image() is called, the actual rendering to the
94         // GraphicsContext must be done.
95         ASSERT(context());
96         m_image = StillImage::create(m_data.m_pixmap);
97     }
98 
99     return m_image.get();
100 }
101 
platformTransformColorSpace(const Vector<int> & lookUpTable)102 void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
103 {
104     bool isPainting = m_data.m_painter->isActive();
105     if (isPainting)
106         m_data.m_painter->end();
107 
108     QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
109     ASSERT(!image.isNull());
110 
111     for (int y = 0; y < m_size.height(); ++y) {
112         for (int x = 0; x < m_size.width(); x++) {
113             QRgb value = image.pixel(x, y);
114             value = qRgba(lookUpTable[qRed(value)],
115                           lookUpTable[qGreen(value)],
116                           lookUpTable[qBlue(value)],
117                           lookUpTable[qAlpha(value)]);
118             image.setPixel(x, y, value);
119         }
120     }
121 
122     m_data.m_pixmap = QPixmap::fromImage(image);
123 
124     if (isPainting)
125         m_data.m_painter->begin(&m_data.m_pixmap);
126 }
127 
getImageData(const IntRect & rect) const128 PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
129 {
130     PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
131     unsigned char* data = result->data()->data()->data();
132 
133     if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
134         memset(data, 0, result->data()->length());
135 
136     int originx = rect.x();
137     int destx = 0;
138     if (originx < 0) {
139         destx = -originx;
140         originx = 0;
141     }
142     int endx = rect.x() + rect.width();
143     if (endx > m_size.width())
144         endx = m_size.width();
145     int numColumns = endx - originx;
146 
147     int originy = rect.y();
148     int desty = 0;
149     if (originy < 0) {
150         desty = -originy;
151         originy = 0;
152     }
153     int endy = rect.y() + rect.height();
154     if (endy > m_size.height())
155         endy = m_size.height();
156     int numRows = endy - originy;
157 
158     QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
159     ASSERT(!image.isNull());
160 
161     unsigned destBytesPerRow = 4 * rect.width();
162     unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
163     for (int y = 0; y < numRows; ++y) {
164         for (int x = 0; x < numColumns; x++) {
165             QRgb value = image.pixel(x + originx, y + originy);
166             int basex = x * 4;
167 
168             destRows[basex] = qRed(value);
169             destRows[basex + 1] = qGreen(value);
170             destRows[basex + 2] = qBlue(value);
171             destRows[basex + 3] = qAlpha(value);
172         }
173         destRows += destBytesPerRow;
174     }
175 
176     return result;
177 }
178 
putImageData(ImageData * source,const IntRect & sourceRect,const IntPoint & destPoint)179 void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
180 {
181     ASSERT(sourceRect.width() > 0);
182     ASSERT(sourceRect.height() > 0);
183 
184     int originx = sourceRect.x();
185     int destx = destPoint.x() + sourceRect.x();
186     ASSERT(destx >= 0);
187     ASSERT(destx < m_size.width());
188     ASSERT(originx >= 0);
189     ASSERT(originx <= sourceRect.right());
190 
191     int endx = destPoint.x() + sourceRect.right();
192     ASSERT(endx <= m_size.width());
193 
194     int numColumns = endx - destx;
195 
196     int originy = sourceRect.y();
197     int desty = destPoint.y() + sourceRect.y();
198     ASSERT(desty >= 0);
199     ASSERT(desty < m_size.height());
200     ASSERT(originy >= 0);
201     ASSERT(originy <= sourceRect.bottom());
202 
203     int endy = destPoint.y() + sourceRect.bottom();
204     ASSERT(endy <= m_size.height());
205     int numRows = endy - desty;
206 
207     unsigned srcBytesPerRow = 4 * source->width();
208 
209     bool isPainting = m_data.m_painter->isActive();
210     if (isPainting)
211         m_data.m_painter->end();
212 
213     QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
214 
215     unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
216     for (int y = 0; y < numRows; ++y) {
217         quint32* scanLine = reinterpret_cast<quint32*>(image.scanLine(y + desty));
218         for (int x = 0; x < numColumns; x++) {
219             int basex = x * 4;
220             scanLine[x + destx] = reinterpret_cast<quint32*>(srcRows + basex)[0];
221         }
222 
223         srcRows += srcBytesPerRow;
224     }
225 
226     m_data.m_pixmap = QPixmap::fromImage(image);
227 
228     if (isPainting)
229         m_data.m_painter->begin(&m_data.m_pixmap);
230 }
231 
232 // We get a mimeType here but QImageWriter does not support mimetypes but
233 // only formats (png, gif, jpeg..., xpm). So assume we get image/ as image
234 // mimetypes and then remove the image/ to get the Qt format.
toDataURL(const String & mimeType) const235 String ImageBuffer::toDataURL(const String& mimeType) const
236 {
237     ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
238 
239     if (!mimeType.startsWith("image/"))
240         return "data:,";
241 
242     // prepare our target
243     QByteArray data;
244     QBuffer buffer(&data);
245     buffer.open(QBuffer::WriteOnly);
246 
247     if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data()))
248         return "data:,";
249 
250     buffer.close();
251     return String::format("data:%s;base64,%s", mimeType.utf8().data(), data.toBase64().data());
252 }
253 
254 }
255