void QGLPixmapData::fill(const QColor &color) { if (!isValid()) return; bool hasAlpha = color.alpha() != 255; if (hasAlpha && !m_hasAlpha) { if (m_texture.id) { destroyTexture(); m_dirty = true; } m_hasAlpha = color.alpha() != 255; } if (useFramebufferObjects()) { m_source = QVolatileImage(); m_hasFillColor = true; m_fillColor = color; } else { forceToImage(); if (m_source.depth() == 32) { m_source.fill(PREMUL(color.rgba())); } else if (m_source.depth() == 1) { if (color == Qt::color1) m_source.fill(1); else m_source.fill(0); } } }
Color atoc(const char *str) { Color col = 0; if (*str == '#') { str++; sscanf(str, "%x", &col); if (strlen(str) == 3 || strlen(str) == 4) { col = (((col & 0x000f) )|((col & 0x000f) << 4))| (((col & 0x00f0) << 4)|((col & 0x00f0) << 8))| (((col & 0x0f00) << 8)|((col & 0x0f00) << 12))| (((col & 0xf000) << 12)|((col & 0xf000) << 16)); } if (strlen(str) % 4) col |= 0xff000000; else col = PREMUL(col); } else { int i; for (i = 0; def_colors[i].str != 0; i++) { if (strcasecmp(def_colors[i].str, str) == 0) { col = def_colors[i].col; break; } } col |= 0xff000000; } return col; }
// If copyBack is true, bind will copy the contents of the render // FBO to the texture (which is not bound to the texture, as it's // a multisample FBO). GLuint QGLPixmapData::bind(bool copyBack) const { if (m_renderFbo && copyBack) { copyBackFromRenderFbo(true); } else { ensureCreated(); } GLuint id = m_texture.id; glBindTexture(GL_TEXTURE_2D, id); if (m_hasFillColor) { if (!useFramebufferObjects()) { m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); } m_hasFillColor = false; GLenum format = qt_gl_preferredTextureFormat(); QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits()); } return id; }
void QBlittablePlatformPixmap::fill(const QColor &color) { if (blittable()->capabilities() & QBlittable::AlphaFillRectCapability) { blittable()->unlock(); blittable()->alphaFillRect(QRectF(0,0,w,h),color,QPainter::CompositionMode_Source); } else if (color.alpha() == 255 && blittable()->capabilities() & QBlittable::SolidRectCapability) { blittable()->unlock(); blittable()->fillRect(QRectF(0,0,w,h),color); } else { // Need to be backed with an alpha channel now. It would be nice // if we could just change the format, e.g. when going from // RGB32 -> ARGB8888. if (color.alpha() != 255 && !hasAlphaChannel()) { m_blittable.reset(0); m_engine.reset(0); m_alpha = true; } uint pixel = PREMUL(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[blittable()->lock()->format()]; Q_ASSERT(layout->convertFromARGB32PM); layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); //so premultiplied formats are supported and ARGB32 and RGB32 blittable()->lock()->fill(pixel); } }
QT_BEGIN_NAMESPACE bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags) { Q_ASSERT(data->format == QImage::Format_ARGB32); // extra pixels on each line const int spare = data->width & 3; // width in pixels of the pad at the end of each line const int pad = (data->bytes_per_line >> 2) - data->width; const int iter = data->width >> 2; int height = data->height; const __m128i alphaMask = _mm_set1_epi32(0xff000000); const __m128i nullVector = _mm_setzero_si128(); const __m128i half = _mm_set1_epi16(0x80); const __m128i colorMask = _mm_set1_epi32(0x00ff00ff); __m128i *d = reinterpret_cast<__m128i*>(data->data); while (height--) { const __m128i *end = d + iter; for (; d != end; ++d) { const __m128i srcVector = _mm_loadu_si128(d); const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { // opaque, data is unchanged } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) == 0xffff) { // fully transparent _mm_storeu_si128(d, nullVector); } else { __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); __m128i result; BYTE_MUL_SSE2(result, srcVector, alphaChannel, colorMask, half); result = _mm_or_si128(_mm_andnot_si128(alphaMask, result), srcVectorAlpha); _mm_storeu_si128(d, result); } } QRgb *p = reinterpret_cast<QRgb*>(d); QRgb *pe = p+spare; for (; p != pe; ++p) { if (*p < 0x00ffffff) *p = 0; else if (*p < 0xff000000) *p = PREMUL(*p); } d = reinterpret_cast<__m128i*>(p+pad); } data->format = QImage::Format_ARGB32_Premultiplied; return true; }
void saveGradientStops(QTextStream &str, const QGradient *g) { QGradientStops stops = g->stops(); if (g->interpolationMode() == QGradient::ColorInterpolation) { bool constantAlpha = true; int alpha = stops.at(0).second.alpha(); for (int i = 1; i < stops.size(); ++i) constantAlpha &= (stops.at(i).second.alpha() == alpha); if (!constantAlpha) { const qreal spacing = qreal(0.02); QGradientStops newStops; QRgb fromColor = PREMUL(stops.at(0).second.rgba()); QRgb toColor; for (int i = 0; i + 1 < stops.size(); ++i) { int parts = qCeil((stops.at(i + 1).first - stops.at(i).first) / spacing); newStops.append(stops.at(i)); toColor = PREMUL(stops.at(i + 1).second.rgba()); if (parts > 1) { qreal step = (stops.at(i + 1).first - stops.at(i).first) / parts; for (int j = 1; j < parts; ++j) { QRgb color = INV_PREMUL(INTERPOLATE_PIXEL_256(fromColor, 256 - 256 * j / parts, toColor, 256 * j / parts)); newStops.append(QGradientStop(stops.at(i).first + j * step, QColor::fromRgba(color))); } } fromColor = toColor; } newStops.append(stops.back()); stops = newStops; } } foreach(QGradientStop stop, stops) { QString color = QString::fromLatin1("#%1%2%3") .arg(stop.second.red(), 2, 16, QLatin1Char('0')) .arg(stop.second.green(), 2, 16, QLatin1Char('0')) .arg(stop.second.blue(), 2, 16, QLatin1Char('0')); str << QLatin1String(" <stop offset=\"")<< stop.first << QLatin1String("\" ") << QLatin1String("stop-color=\"") << color << QLatin1String("\" ") << QLatin1String("stop-opacity=\"") << stop.second.alphaF() <<QLatin1String("\" />\n"); }
QPaintEngine* QGLPixmapData::paintEngine() const { if (!isValid()) return 0; // If the application wants to paint into the QPixmap, we first // force it to QImage format and then paint into that. // This is simpler than juggling multiple GL contexts. const_cast<QGLPixmapData *>(this)->forceToImage(); if (m_hasFillColor) { m_source.fill(PREMUL(m_fillColor.rgba())); m_hasFillColor = false; } return m_source.paintEngine(); }
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; #if !(defined(QT_COMPILER_SUPPORTS_NEON) || defined(__SSE2__)) if (image.format() == QImage::Format_RGB16) toFormat = QImage::Format_ARGB8565_Premultiplied; else if (image.format() == QImage::Format_RGB666) toFormat = QImage::Format_ARGB6666_Premultiplied; else if (image.format() == QImage::Format_RGB555) toFormat = QImage::Format_ARGB8555_Premultiplied; else if (image.format() == QImage::Format_RGB444) toFormat = QImage::Format_ARGB4444_Premultiplied; else #endif toFormat = QImage::Format_ARGB32_Premultiplied; if (!image.isNull() && qt_depthForFormat(image.format()) == qt_depthForFormat(toFormat)) { image.detach(); image.d->format = toFormat; } else { image = QImage(image.width(), image.height(), toFormat); } } } pixel = PREMUL(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); } else { pixel = 0; // ### what about 8 bits } image.fill(pixel); }
void QVGPixmapData::fill(const QColor &color) { if (!isValid()) return; forceToImage(); if (source.depth() == 1) { // Pick the best approximate color in the image's colortable. int gray = qGray(color.rgba()); if (qAbs(qGray(source.imageRef().color(0)) - gray) < qAbs(qGray(source.imageRef().color(1)) - gray)) source.fill(0); else source.fill(1); } else { source.fill(PREMUL(color.rgba())); } }
void QBlittablePixmapData::fill(const QColor &color) { if (blittable()->capabilities() & QBlittable::AlphaFillRectCapability) { blittable()->unlock(); blittable()->alphaFillRect(QRectF(0,0,w,h),color,QPainter::CompositionMode_Source); } else if (color.alpha() == 255 && blittable()->capabilities() & QBlittable::SolidRectCapability) { blittable()->unlock(); blittable()->fillRect(QRectF(0,0,w,h),color); } else { // Need to be backed with an alpha channel now. It would be nice // if we could just change the format, e.g. when going from // RGB32 -> ARGB8888. if (color.alpha() != 255 && !hasAlphaChannel()) { m_blittable.reset(0); m_engine.reset(0); m_alpha = true; } uint pixel; switch (blittable()->lock()->format()) { case QImage::Format_ARGB32_Premultiplied: pixel = PREMUL(color.rgba()); break; case QImage::Format_ARGB8565_Premultiplied: pixel = qargb8565(color.rgba()).rawValue(); break; case QImage::Format_ARGB8555_Premultiplied: pixel = qargb8555(color.rgba()).rawValue(); break; case QImage::Format_ARGB6666_Premultiplied: pixel = qargb6666(color.rgba()).rawValue(); break; case QImage::Format_ARGB4444_Premultiplied: pixel = qargb4444(color.rgba()).rawValue(); break; default: pixel = color.rgba(); break; } //so premultiplied formats are supported and ARGB32 and RGB32 blittable()->lock()->fill(pixel); } }
QPaintEngine* QGLPixmapData::paintEngine() const { if (!isValid()) return 0; if (m_renderFbo) return m_engine; if (useFramebufferObjects()) { extern QGLWidget* qt_gl_share_widget(); if (!QGLContext::currentContext()) qt_gl_share_widget()->makeCurrent(); QGLShareContextScope ctx(qt_gl_share_widget()->context()); QGLFramebufferObjectFormat format; format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); format.setSamples(4); format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); m_renderFbo = qgl_fbo_pool()->acquire(size(), format); if (m_renderFbo) { if (!m_engine) m_engine = new QGL2PaintEngineEx; return m_engine; } qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; } // If the application wants to paint into the QPixmap, we first // force it to QImage format and then paint into that. // This is simpler than juggling multiple GL contexts. const_cast<QGLPixmapData *>(this)->forceToImage(); if (m_hasFillColor) { m_source.fill(PREMUL(m_fillColor.rgba())); m_hasFillColor = false; } return m_source.paintEngine(); }
GLuint QGLPixmapData::bind(bool copyBack) const { ensureCreated(); GLuint id = m_texture.id; glBindTexture(GL_TEXTURE_2D, id); if (m_hasFillColor) { m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); m_hasFillColor = false; GLenum format = qt_gl_preferredTextureFormat(); QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.constBits()); } return id; }
QPaintEngine* QGLPixmapData::paintEngine() const { if (!isValid()) return 0; if (m_renderFbo) return m_engine; if (useFramebufferObjects()) { extern QGLWidget* qt_gl_share_widget(); if (!QGLContext::currentContext()) const_cast<QGLContext *>(qt_gl_share_context())->makeCurrent(); QGLShareContextScope ctx(qt_gl_share_context()); QGLFramebufferObjectFormat format; format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); format.setSamples(4); format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); m_renderFbo = qgl_fbo_pool()->acquire(size(), format); if (m_renderFbo) { if (!m_engine) m_engine = new QGL2PaintEngineEx; return m_engine; } qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; } m_dirty = true; if (m_source.size() != size()) m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied); if (m_hasFillColor) { m_source.fill(PREMUL(m_fillColor.rgba())); m_hasFillColor = false; } return m_source.paintEngine(); }
void QVGPixmapData::fill(const QColor &color) { if (!isValid()) return; if (source.isNull()) source = QImage(w, h, sourceFormat()); if (source.depth() == 1) { // Pick the best approximate color in the image's colortable. int gray = qGray(color.rgba()); if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray)) source.fill(0); else source.fill(1); } else { source.fill(PREMUL(color.rgba())); } // Re-upload the image to VG the next time toVGImage() is called. recreate = true; }
QImage QGLPixmapData::fillImage(const QColor &color) const { QImage img; if (pixelType() == BitmapType) { img = QImage(w, h, QImage::Format_MonoLSB); img.setColorCount(2); img.setColor(0, QColor(Qt::color0).rgba()); img.setColor(1, QColor(Qt::color1).rgba()); if (color == Qt::color1) img.fill(1); else img.fill(0); } else { img = QImage(w, h, m_hasAlpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); img.fill(PREMUL(color.rgba())); } return img; }
void QMacPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { setSerialNumber(++qt_pixmap_serial); // the conversion code only handles format >= // Format_ARGB32_Premultiplied at the moment.. if (img.format() > QImage::Format_ARGB32_Premultiplied) { QImage image; if (img.hasAlphaChannel()) image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); else image = img.convertToFormat(QImage::Format_RGB32); fromImage(image, flags); return; } w = img.width(); h = img.height(); is_null = (w <= 0 || h <= 0); d = (pixelType() == BitmapType ? 1 : img.depth()); QImage image = img; int dd = QPixmap::defaultDepth(); bool force_mono = (dd == 1 || (flags & Qt::ColorMode_Mask)==Qt::MonoOnly); if (force_mono) { // must be monochrome if (d != 1) { image = image.convertToFormat(QImage::Format_MonoLSB, flags); // dither d = 1; } } else { // can be both bool conv8 = false; if(d > 8 && dd <= 8) { // convert to 8 bit if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither) flags = (flags & ~Qt::DitherMode_Mask) | Qt::PreferDither; conv8 = true; } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) { conv8 = d == 1; // native depth wanted } else if (d == 1) { if (image.colorCount() == 2) { QRgb c0 = image.color(0); // Auto: convert to best QRgb c1 = image.color(1); conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255); } else { // eg. 1-color monochrome images (they do exist). conv8 = true; } } if (conv8) { image = image.convertToFormat(QImage::Format_Indexed8, flags); d = 8; } } if (image.depth()==1) { image.setColor(0, QColor(Qt::color0).rgba()); image.setColor(1, QColor(Qt::color1).rgba()); } if (d == 16 || d == 24) { image = image.convertToFormat(QImage::Format_RGB32, flags); fromImage(image, flags); return; } // different size or depth, make a new pixmap resize(w, h); quint32 *dptr = pixels, *drow; const uint dbpr = bytesPerRow; const QImage::Format sfmt = image.format(); const unsigned short sbpr = image.bytesPerLine(); // use const_cast to prevent a detach const uchar *sptr = const_cast<const QImage &>(image).bits(), *srow; for (int y = 0; y < h; ++y) { drow = dptr + (y * (dbpr / 4)); srow = sptr + (y * sbpr); switch(sfmt) { case QImage::Format_MonoLSB: case QImage::Format_Mono:{ for (int x = 0; x < w; ++x) { char one_bit = *(srow + (x / 8)); if (sfmt == QImage::Format_Mono) one_bit = one_bit >> (7 - (x % 8)); else one_bit = one_bit >> (x % 8); if ((one_bit & 0x01)) *(drow+x) = 0xFF000000; else *(drow+x) = 0xFFFFFFFF; } break; } case QImage::Format_Indexed8: { int numColors = image.numColors(); if (numColors > 0) { for (int x = 0; x < w; ++x) { int index = *(srow + x); *(drow+x) = PREMUL(image.color(qMin(index, numColors))); } } } break; case QImage::Format_RGB32: for (int x = 0; x < w; ++x) *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000; break; case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: for (int x = 0; x < w; ++x) { if(sfmt == QImage::Format_RGB32) *(drow+x) = 0xFF000000 | (*(((quint32*)srow) + x) & 0x00FFFFFF); else if(sfmt == QImage::Format_ARGB32_Premultiplied) *(drow+x) = *(((quint32*)srow) + x); else *(drow+x) = PREMUL(*(((quint32*)srow) + x)); } break; default: qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt, __FILE__, __LINE__); break; } }
QPixmap QPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { QPixmap pixmap; if(img.isNull()) { qWarning("QPixmap::convertFromImage: Cannot convert a null image"); return pixmap; } QImage image = img; int d = image.depth(); int dd = defaultDepth(); bool force_mono = (dd == 1 || (flags & Qt::ColorMode_Mask)==Qt::MonoOnly); if(force_mono) { // must be monochrome if(d != 1) { image = image.convertToFormat(QImage::Format_MonoLSB, flags); // dither d = 1; } } else { // can be both bool conv8 = false; if(d > 8 && dd <= 8) { // convert to 8 bit if((flags & Qt::DitherMode_Mask) == Qt::AutoDither) flags = (flags & ~Qt::DitherMode_Mask) | Qt::PreferDither; conv8 = true; } else if((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) { conv8 = d == 1; // native depth wanted } else if(d == 1) { if(image.numColors() == 2) { QRgb c0 = image.color(0); // Auto: convert to best QRgb c1 = image.color(1); conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255); } else { // eg. 1-color monochrome images (they do exist). conv8 = true; } } if(conv8) { image = image.convertToFormat(QImage::Format_Indexed8, flags); d = 8; } } if(image.depth()==1) { image.setColor(0, QColor(Qt::color0).rgba()); image.setColor(1, QColor(Qt::color1).rgba()); } if (d == 16) { QImage im = image.convertToFormat(QImage::Format_RGB32, flags); return fromImage(im); } int w = image.width(); int h = image.height(); // different size or depth, make a new pixmap if (d == 1) pixmap = QBitmap(w, h); else pixmap = QPixmap(w, h); quint32 *dptr = pixmap.data->pixels, *drow; const uint dbpr = pixmap.data->nbytes / h; const QImage::Format sfmt = image.format(); const unsigned short sbpr = image.bytesPerLine(); uchar *sptr = image.bits(), *srow; for(int y=0;y<h;y++) { drow = dptr + (y * (dbpr / 4)); srow = sptr + (y * sbpr); switch(sfmt) { case QImage::Format_MonoLSB: case QImage::Format_Mono:{ for(int x=0;x<w;++x) { char one_bit = *(srow + (x / 8)); if(sfmt == QImage::Format_Mono) one_bit = one_bit >> (7 - (x % 8)); else one_bit = one_bit >> (x % 8); if((one_bit & 0x01)) *(drow+x) = 0x00000000; else *(drow+x) = 0xFFFFFFFF; } break; } case QImage::Format_Indexed8: for(int x=0;x<w;++x) { *(drow+x) = PREMUL(image.color(*(srow + x))); } break; case QImage::Format_RGB32: for(int x=0;x<w;++x) *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000; break; case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: for(int x=0;x<w;++x) { if(sfmt == QImage::Format_RGB32) *(drow+x) = 0xFF000000 | (*(((quint32*)srow) + x) & 0x00FFFFFF); else if(sfmt == QImage::Format_ARGB32_Premultiplied) *(drow+x) = *(((quint32*)srow) + x); else *(drow+x) = PREMUL(*(((quint32*)srow) + x)); } break; default: qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt, __FILE__, __LINE__); break; } }