18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Holger Hans Peter Freyther
48f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
55af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ImageBuffer.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ImageData.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "MIMETypeRegistry.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "StillImageQt.h"
36f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include "TransparencyLayer.h"
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/text/CString.h>
38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/text/StringConcatenate.h>
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QBuffer>
418f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include <QColor>
428f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include <QImage>
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QImageWriter>
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QPainter>
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QPixmap>
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <math.h>
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectImageBufferData::ImageBufferData(const IntSize& size)
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_pixmap(size)
52e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    , m_painter(0)
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
54e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    if (m_pixmap.isNull())
55e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        return;
56e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pixmap.fill(QColor(Qt::transparent));
585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
59e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    QPainter* painter = new QPainter;
605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    m_painter.set(painter);
615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
62e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    if (!painter->begin(&m_pixmap))
63e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        return;
64e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block
655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Since ImageBuffer is used mainly for Canvas, explicitly initialize
665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // its painter's pen and brush with the corresponding canvas defaults
675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // NOTE: keep in sync with CanvasRenderingContext2D::State
685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    QPen pen = painter->pen();
695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    pen.setColor(Qt::black);
705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    pen.setWidth(1);
715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    pen.setCapStyle(Qt::FlatCap);
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    pen.setJoinStyle(Qt::SvgMiterJoin);
735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    pen.setMiterLimit(10);
745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    painter->setPen(pen);
755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    QBrush brush = painter->brush();
765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    brush.setColor(Qt::black);
775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    painter->setBrush(brush);
785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
79f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
80f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    m_image = StillImage::createForRendering(&m_pixmap);
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
832bde8e466a4451c7319e3a072d118917957d6554Steve BlockQImage ImageBufferData::toQImage() const
842bde8e466a4451c7319e3a072d118917957d6554Steve Block{
852bde8e466a4451c7319e3a072d118917957d6554Steve Block    QPaintEngine* paintEngine = m_pixmap.paintEngine();
862bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!paintEngine || paintEngine->type() != QPaintEngine::Raster)
872bde8e466a4451c7319e3a072d118917957d6554Steve Block        return m_pixmap.toImage();
882bde8e466a4451c7319e3a072d118917957d6554Steve Block
892bde8e466a4451c7319e3a072d118917957d6554Steve Block    // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it.
902bde8e466a4451c7319e3a072d118917957d6554Steve Block    // For performance reasons, we don't want that here, so we temporarily redirect the paint engine.
912bde8e466a4451c7319e3a072d118917957d6554Steve Block    QPaintDevice* currentPaintDevice = paintEngine->paintDevice();
922bde8e466a4451c7319e3a072d118917957d6554Steve Block    paintEngine->setPaintDevice(0);
932bde8e466a4451c7319e3a072d118917957d6554Steve Block    QImage image = m_pixmap.toImage();
942bde8e466a4451c7319e3a072d118917957d6554Steve Block    paintEngine->setPaintDevice(currentPaintDevice);
952bde8e466a4451c7319e3a072d118917957d6554Steve Block    return image;
962bde8e466a4451c7319e3a072d118917957d6554Steve Block}
972bde8e466a4451c7319e3a072d118917957d6554Steve Block
98f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_data(size)
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_size(size)
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
102e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    success = m_data.m_painter && m_data.m_painter->isActive();
103e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    if (!success)
104e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        return;
105e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_context.set(new GraphicsContext(m_data.m_painter.get()));
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectImageBuffer::~ImageBuffer()
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
113ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochsize_t ImageBuffer::dataSize() const
114ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{
115ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    return m_size.width() * m_size.height() * 4;
116ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch}
117ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectGraphicsContext* ImageBuffer::context() const
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_data.m_painter->isActive());
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_context.get();
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
125f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickbool ImageBuffer::drawsUsingCopy() const
126967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
127f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    return false;
128f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick}
129967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
130f486d19d62f1bc33246748b14b14a9dfa617b57fIain MerrickPassRefPtr<Image> ImageBuffer::copyImage() const
131f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{
132f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    return StillImage::create(m_data.m_pixmap);
133967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
134967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
135f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
136f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick                       CompositeOperator op, bool useLowQualityScale)
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
138f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (destContext == context()) {
139f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        // We're drawing into our own buffer.  In order for this to work, we need to copy the source buffer first.
140f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        RefPtr<Image> copy = copyImage();
141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale);
142f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    } else
143f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
144f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick}
145f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
146f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform,
147f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick                              const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
148f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{
149f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (destContext == context()) {
150f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        // We're drawing into our own buffer.  In order for this to work, we need to copy the source buffer first.
151f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        RefPtr<Image> copy = copyImage();
152f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
153f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    } else
154f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        m_data.m_image->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
155f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick}
156f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
157f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) const
158f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{
159f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    QPixmap* nativeImage = m_data.m_image->nativeImageForCurrentFrame();
160f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (!nativeImage)
161f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        return;
162f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    IntRect rect = enclosingIntRect(floatRect);
164f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    QPixmap alphaMask = *nativeImage;
165f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height())
166f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        alphaMask = alphaMask.scaled(rect.width(), rect.height());
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
168f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    context->pushTransparencyLayerInternal(rect, 1.0, alphaMask);
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
1720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
1730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    bool isPainting = m_data.m_painter->isActive();
1740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (isPainting)
1750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_data.m_painter->end();
1760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1772bde8e466a4451c7319e3a072d118917957d6554Steve Block    QImage image = m_data.toQImage().convertToFormat(QImage::Format_ARGB32);
1780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(!image.isNull());
1790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
180e14391e94c850b8bd03680c23b38978db68687a8John Reck    uchar* bits = image.bits();
181e14391e94c850b8bd03680c23b38978db68687a8John Reck    const int bytesPerLine = image.bytesPerLine();
182e14391e94c850b8bd03680c23b38978db68687a8John Reck
1830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for (int y = 0; y < m_size.height(); ++y) {
184e14391e94c850b8bd03680c23b38978db68687a8John Reck        quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
185e14391e94c850b8bd03680c23b38978db68687a8John Reck        for (int x = 0; x < m_size.width(); ++x) {
186e14391e94c850b8bd03680c23b38978db68687a8John Reck            QRgb& pixel = scanLine[x];
187e14391e94c850b8bd03680c23b38978db68687a8John Reck            pixel = qRgba(lookUpTable[qRed(pixel)],
188e14391e94c850b8bd03680c23b38978db68687a8John Reck                          lookUpTable[qGreen(pixel)],
189e14391e94c850b8bd03680c23b38978db68687a8John Reck                          lookUpTable[qBlue(pixel)],
190e14391e94c850b8bd03680c23b38978db68687a8John Reck                          qAlpha(pixel));
1910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
1920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
1930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_data.m_pixmap = QPixmap::fromImage(image);
1950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (isPainting)
1970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_data.m_painter->begin(&m_data.m_pixmap);
1980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
1990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
200231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <Multiply multiplied>
201cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size)
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
203cad810f21b803229eb11403f9209855525a25d57Steve Block    RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
204cad810f21b803229eb11403f9209855525a25d57Steve Block    unsigned char* data = result->data();
2058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
2062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height())
207cad810f21b803229eb11403f9209855525a25d57Steve Block        memset(data, 0, result->length());
2088f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
2098f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int originx = rect.x();
2108f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int destx = 0;
2118f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (originx < 0) {
2128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        destx = -originx;
2138f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        originx = 0;
2148f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
2152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int endx = rect.maxX();
216231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (endx > size.width())
217231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        endx = size.width();
2188f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int numColumns = endx - originx;
2198f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
2208f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int originy = rect.y();
2218f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int desty = 0;
2228f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (originy < 0) {
2238f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        desty = -originy;
2248f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        originy = 0;
2258f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
2262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int endy = rect.maxY();
227231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (endy > size.height())
228231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        endy = size.height();
2298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int numRows = endy - originy;
2308f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
2310617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    // NOTE: For unmultiplied data, we undo the premultiplication below.
2322bde8e466a4451c7319e3a072d118917957d6554Steve Block    QImage image = imageData.toQImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
233231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2348f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(!image.isNull());
2358f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
2360617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    const int bytesPerLine = image.bytesPerLine();
2370617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    const uchar* bits = image.constBits();
2380617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]);
2400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
2410617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (multiplied == Unmultiplied) {
2420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        for (int y = 0; y < numRows; ++y) {
243e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
2440617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            for (int x = 0; x < numColumns; x++) {
2450617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                QRgb pixel = scanLine[x + originx];
2460617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                int alpha = qAlpha(pixel);
2470617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                // Un-premultiply and convert RGB to BGR.
2480617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                if (alpha == 255)
2490617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                    destRows[x] = (0xFF000000
2500617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | (qBlue(pixel) << 16)
2510617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | (qGreen(pixel) << 8)
2520617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | (qRed(pixel)));
2530617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                else if (alpha > 0)
2540617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                    destRows[x] = ((alpha << 24)
2550617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | (((255 * qBlue(pixel)) / alpha)) << 16)
2560617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | (((255 * qGreen(pixel)) / alpha) << 8)
2570617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                                | ((255 * qRed(pixel)) / alpha);
2580617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                else
2590617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                    destRows[x] = 0;
2600617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            }
2610617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            destRows += rect.width();
2620617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        }
2630617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    } else {
2640617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        for (int y = 0; y < numRows; ++y) {
265e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
2660617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            for (int x = 0; x < numColumns; x++) {
2670617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                QRgb pixel = scanLine[x + originx];
2680617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                // Convert RGB to BGR.
2690617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                destRows[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
2700617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
2710617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            }
2720617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            destRows += rect.width();
2738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
2748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
2758f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
276cad810f21b803229eb11403f9209855525a25d57Steve Block    return result.release();
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
279cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
280231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
281231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return getImageData<Unmultiplied>(rect, m_data, m_size);
282231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
283231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
284cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
285231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
286231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return getImageData<Premultiplied>(rect, m_data, m_size);
287231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
288231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2890617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenstatic inline unsigned int premultiplyABGRtoARGB(unsigned int x)
2900617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{
2910617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    unsigned int a = x >> 24;
2920617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (a == 255)
2930617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return (x << 16) | ((x >> 16) & 0xff) | (x & 0xff00ff00);
2940617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    unsigned int t = (x & 0xff00ff) * a;
2950617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
2960617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    t = ((t << 16) | (t >> 16)) & 0xff00ff;
2970617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
2980617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    x = ((x >> 8) & 0xff) * a;
2990617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    x = (x + ((x >> 8) & 0xff) + 0x80);
3000617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    x &= 0xff00;
3010617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    x |= t | (a << 24);
3020617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    return x;
3030617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen}
3040617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <Multiply multiplied>
306cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3088f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(sourceRect.width() > 0);
3098f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(sourceRect.height() > 0);
3108f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3118f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int originx = sourceRect.x();
3128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int destx = destPoint.x() + sourceRect.x();
3138f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(destx >= 0);
314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(destx < size.width());
3158f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(originx >= 0);
3162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(originx <= sourceRect.maxX());
3178f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int endx = destPoint.x() + sourceRect.maxX();
319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(endx <= size.width());
3208f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3218f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int numColumns = endx - destx;
3228f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3238f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int originy = sourceRect.y();
3248f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int desty = destPoint.y() + sourceRect.y();
3258f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(desty >= 0);
326231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(desty < size.height());
3278f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(originy >= 0);
3282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(originy <= sourceRect.maxY());
3298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int endy = destPoint.y() + sourceRect.maxY();
331231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(endy <= size.height());
3328f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    int numRows = endy - desty;
3338f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
334cad810f21b803229eb11403f9209855525a25d57Steve Block    unsigned srcBytesPerRow = 4 * sourceSize.width();
3358f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3360617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    // NOTE: For unmultiplied input data, we do the premultiplication below.
3370617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    QImage image(numColumns, numRows, QImage::Format_ARGB32_Premultiplied);
3380617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    uchar* bits = image.bits();
3390617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    const int bytesPerLine = image.bytesPerLine();
3400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
341cad810f21b803229eb11403f9209855525a25d57Steve Block    const quint32* srcScanLine = reinterpret_cast_ptr<const quint32*>(source->data() + originy * srcBytesPerRow + originx * 4);
3420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3430617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (multiplied == Unmultiplied) {
3440617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        for (int y = 0; y < numRows; ++y) {
345e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
3460617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            for (int x = 0; x < numColumns; x++) {
3470617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                // Premultiply and convert BGR to RGB.
3480617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                quint32 pixel = srcScanLine[x];
3490617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                destScanLine[x] = premultiplyABGRtoARGB(pixel);
3500617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            }
351cad810f21b803229eb11403f9209855525a25d57Steve Block            srcScanLine += sourceSize.width();
3520617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        }
3530617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    } else {
3540617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        for (int y = 0; y < numRows; ++y) {
355e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
3560617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            for (int x = 0; x < numColumns; x++) {
3570617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                // Convert BGR to RGB.
3580617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                quint32 pixel = srcScanLine[x];
3590617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen                destScanLine[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
3600617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen            }
361cad810f21b803229eb11403f9209855525a25d57Steve Block            srcScanLine += sourceSize.width();
3628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
3638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
3648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
365e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    bool isPainting = data.m_painter->isActive();
366e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    if (!isPainting)
367231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        data.m_painter->begin(&data.m_pixmap);
368e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    else {
369e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->save();
370e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
371e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        // putImageData() should be unaffected by painter state
372e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->resetTransform();
373e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->setOpacity(1.0);
374e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->setClipping(false);
375e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    }
376e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
377e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    data.m_painter->setCompositionMode(QPainter::CompositionMode_Source);
3780617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    data.m_painter->drawImage(destx, desty, image);
379e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
380e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    if (!isPainting)
381e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->end();
382e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    else
383e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        data.m_painter->restore();
384231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
385231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
386cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
387231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
388cad810f21b803229eb11403f9209855525a25d57Steve Block    putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
389231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
390231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
391cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
392231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
393cad810f21b803229eb11403f9209855525a25d57Steve Block    putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// We get a mimeType here but QImageWriter does not support mimetypes but
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// only formats (png, gif, jpeg..., xpm). So assume we get image/ as image
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// mimetypes and then remove the image/ to get the Qt format.
399545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochString ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!mimeType.startsWith("image/"))
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return "data:,";
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // prepare our target
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    QByteArray data;
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    QBuffer buffer(&data);
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.open(QBuffer::WriteOnly);
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
411545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (quality && *quality >= 0.0 && *quality <= 1.0) {
412545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), *quality * 100 + 0.5)) {
413545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            buffer.close();
414545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            return "data:,";
415545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        }
416545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    } else {
417545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), 100)) {
418545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            buffer.close();
419545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            return "data:,";
420545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        }
4215af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    }
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.close();
424a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
425a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return makeString("data:", mimeType, ";base64,", data.toBase64().data());
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
429