/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qpixmap.h" #include #include "qpixmap_raster_p.h" #include "qimage_p.h" #include "qpaintengine.h" #include "qbitmap.h" #include "qimage.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE QPixmap qt_toRasterPixmap(const QImage &image) { QPlatformPixmap *data = new QRasterPlatformPixmap(image.depth() == 1 ? QPlatformPixmap::BitmapType : QPlatformPixmap::PixmapType); data->fromImage(image, Qt::AutoColor); return QPixmap(data); } QPixmap qt_toRasterPixmap(const QPixmap &pixmap) { if (pixmap.isNull()) return QPixmap(); if (QPixmap(pixmap).data_ptr()->classId() == QPlatformPixmap::RasterClass) return pixmap; return qt_toRasterPixmap(pixmap.toImage()); } QRasterPlatformPixmap::QRasterPlatformPixmap(PixelType type) : QPlatformPixmap(type, RasterClass) { } QRasterPlatformPixmap::~QRasterPlatformPixmap() { } QImage::Format QRasterPlatformPixmap::systemNativeFormat() { if (!QGuiApplication::primaryScreen()) return QImage::Format_RGB32; return QGuiApplication::primaryScreen()->handle()->format(); } QPlatformPixmap *QRasterPlatformPixmap::createCompatiblePlatformPixmap() const { return new QRasterPlatformPixmap(pixelType()); } void QRasterPlatformPixmap::resize(int width, int height) { QImage::Format format; if (pixelType() == BitmapType) format = QImage::Format_MonoLSB; else format = systemNativeFormat(); image = QImage(width, height, format); w = width; h = height; d = image.depth(); is_null = (w <= 0 || h <= 0); if (pixelType() == BitmapType && !image.isNull()) { image.setColorCount(2); image.setColor(0, QColor(Qt::color0).rgba()); image.setColor(1, QColor(Qt::color1).rgba()); } setSerialNumber(image.cacheKey() >> 32); } bool QRasterPlatformPixmap::fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags) { QByteArray a = QByteArray::fromRawData(reinterpret_cast(buffer), len); QBuffer b(&a); b.open(QIODevice::ReadOnly); QImage image = QImageReader(&b, format).read(); if (image.isNull()) return false; createPixmapForImage(std::move(image), flags); return !isNull(); } void QRasterPlatformPixmap::fromImage(const QImage &sourceImage, Qt::ImageConversionFlags flags) { QImage image = sourceImage; createPixmapForImage(std::move(image), flags); } void QRasterPlatformPixmap::fromImageInPlace(QImage &sourceImage, Qt::ImageConversionFlags flags) { createPixmapForImage(std::move(sourceImage), flags); } void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) { Q_UNUSED(flags); QImage image = imageReader->read(); if (image.isNull()) return; createPixmapForImage(std::move(image), flags); } // from qbackingstore.cpp extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); void QRasterPlatformPixmap::copy(const QPlatformPixmap *data, const QRect &rect) { fromImage(data->toImage(rect).copy(), Qt::NoOpaqueDetection); } bool QRasterPlatformPixmap::scroll(int dx, int dy, const QRect &rect) { if (!image.isNull()) qt_scrollRectInImage(image, rect, QPoint(dx, dy)); return true; } void QRasterPlatformPixmap::fill(const QColor &color) { uint pixel; if (image.depth() == 1) { int gray = qGray(color.rgba()); // Pick the best approximate color in the image's colortable. if (qAbs(qGray(image.color(0)) - gray) < qAbs(qGray(image.color(1)) - gray)) pixel = 0; else pixel = 1; } else if (image.depth() >= 15) { int alpha = color.alpha(); if (alpha != 255) { if (!image.hasAlphaChannel()) { QImage::Format toFormat = qt_alphaVersionForPainting(image.format()); if (!image.reinterpretAsFormat(toFormat)) image = QImage(image.width(), image.height(), toFormat); } } image.fill(color); return; } else if (image.format() == QImage::Format_Alpha8) { pixel = qAlpha(color.rgba()); } else if (image.format() == QImage::Format_Grayscale8) { pixel = qGray(color.rgba()); } else if (image.format() == QImage::Format_Grayscale16) { QRgba64 c = color.rgba64(); pixel = qGray(c.red(), c.green(), c.blue()); } else { pixel = 0; // ### what about 8 bit indexed? } image.fill(pixel); } bool QRasterPlatformPixmap::hasAlphaChannel() const { return image.hasAlphaChannel(); } QImage QRasterPlatformPixmap::toImage() const { if (!image.isNull()) { QImageData *data = const_cast(image).data_ptr(); if (data->paintEngine && data->paintEngine->isActive() && data->paintEngine->paintDevice() == &image) { return image.copy(); } } return image; } QImage QRasterPlatformPixmap::toImage(const QRect &rect) const { if (rect.isNull()) return image; QRect clipped = rect.intersected(QRect(0, 0, w, h)); const uint du = uint(d); if ((du % 8 == 0) && (((uint(clipped.x()) * du)) % 32 == 0)) { QImage newImage(image.scanLine(clipped.y()) + clipped.x() * (du / 8), clipped.width(), clipped.height(), image.bytesPerLine(), image.format()); newImage.setDevicePixelRatio(image.devicePixelRatio()); return newImage; } else { return image.copy(clipped); } } QPaintEngine* QRasterPlatformPixmap::paintEngine() const { return image.paintEngine(); } int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const { QImageData *d = image.d; if (!d) return 0; // override the image dpi with the screen dpi when rendering to a pixmap switch (metric) { case QPaintDevice::PdmWidth: return w; case QPaintDevice::PdmHeight: return h; case QPaintDevice::PdmWidthMM: return qRound(d->width * 25.4 / qt_defaultDpiX()); case QPaintDevice::PdmHeightMM: return qRound(d->height * 25.4 / qt_defaultDpiY()); case QPaintDevice::PdmNumColors: return d->colortable.size(); case QPaintDevice::PdmDepth: return this->d; case QPaintDevice::PdmDpiX: return qt_defaultDpiX(); case QPaintDevice::PdmPhysicalDpiX: return qt_defaultDpiX(); case QPaintDevice::PdmDpiY: return qt_defaultDpiY(); case QPaintDevice::PdmPhysicalDpiY: return qt_defaultDpiY(); case QPaintDevice::PdmDevicePixelRatio: return image.devicePixelRatio(); case QPaintDevice::PdmDevicePixelRatioScaled: return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale(); default: qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); break; } return 0; } void QRasterPlatformPixmap::createPixmapForImage(QImage sourceImage, Qt::ImageConversionFlags flags) { QImage::Format format; if (flags & Qt::NoFormatConversion) format = sourceImage.format(); else if (pixelType() == BitmapType) { format = QImage::Format_MonoLSB; } else { if (sourceImage.depth() == 1) { format = sourceImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; } else { QImage::Format nativeFormat = systemNativeFormat(); QImage::Format opaqueFormat = qt_opaqueVersionForPainting(nativeFormat); QImage::Format alphaFormat = qt_alphaVersionForPainting(nativeFormat); if (!sourceImage.hasAlphaChannel()) { format = opaqueFormat; } else if ((flags & Qt::NoOpaqueDetection) == 0 && !sourceImage.data_ptr()->checkForAlphaPixels()) { format = opaqueFormat; } else { format = alphaFormat; } } } // image has alpha format but is really opaque, so try to do a // more efficient conversion if (format == QImage::Format_RGB32 && (sourceImage.format() == QImage::Format_ARGB32 || sourceImage.format() == QImage::Format_ARGB32_Premultiplied)) { image = std::move(sourceImage); image.reinterpretAsFormat(QImage::Format_RGB32); } else { image = std::move(sourceImage).convertToFormat(format, flags); } if (image.d) { w = image.d->width; h = image.d->height; d = image.d->depth; } else { w = h = d = 0; } is_null = (w <= 0 || h <= 0); //ensure the pixmap and the image resulting from toImage() have the same cacheKey(); setSerialNumber(image.cacheKey() >> 32); if (image.d) setDetachNumber(image.d->detach_no); } QImage* QRasterPlatformPixmap::buffer() { return ℑ } qreal QRasterPlatformPixmap::devicePixelRatio() const { return image.devicePixelRatio(); } void QRasterPlatformPixmap::setDevicePixelRatio(qreal scaleFactor) { image.setDevicePixelRatio(scaleFactor); } QT_END_NAMESPACE