static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQuality) { bool success = false; const QVector<QRgb> cmap = image.colorTable(); struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device); struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) { // WARNING: // this if loop is inside a setjmp/longjmp branch // do not create C++ temporaries here because the destructor may never be called // if you allocate memory, make sure that you can free it (row_pointer[0]) jpeg_create_compress(&cinfo); cinfo.dest = iod_dest; cinfo.image_width = image.width(); cinfo.image_height = image.height(); bool gray=false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; for (int i = image.colorCount(); gray && i--;) { gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && qRed(cmap[i]) == qBlue(cmap[i])); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.)) + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.)); qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.)) + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54; if (diffInch < diffCm) { cinfo.density_unit = 1; // dots/inch cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.); cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.); } else { cinfo.density_unit = 2; // dots/cm cinfo.X_density = (image.dotsPerMeterX()+50) / 100; cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; } int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75; #if defined(Q_OS_UNIXWARE) jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, B_TRUE); #else jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, true); #endif row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { uchar *row = row_pointer[0]; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: if (gray) { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); row[i] = qRed(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); row[i] = qRed(cmap[bit]); } } } else { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } }
void GLImageDrawable::setImage(const QImage& image, bool insidePaint) { //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark1: insidePaint:"<<insidePaint; if(m_allocatedMemory > IMAGE_ALLOCATION_CAP_MB*1024*1024 && !liveStatus() && canReleaseImage()) { m_releasedImage = true; //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" NOT LOADING"; #ifdef DEBUG_MEMORY_USAGE qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Allocated memory ("<<(m_allocatedMemory/1024/1024)<<"MB ) exceedes" << IMAGE_ALLOCATION_CAP_MB << "MB cap - delaying load until go-live"; #endif return; } m_releasedImage = false; //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark2"; //image.save("whitedebug.png"); if(m_frame && m_frame->isValid() && xfadeEnabled() && !insidePaint) { if(m_hqXfadeEnabled) { m_oldImage = m_image; hqXfadeStart(); } else { m_frame2 = m_frame; //sqDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Starting crossfade with m_frame2"; //m_frame2 = VideoFramePtr(new VideoFrame(m_image,1000/30)); updateTexture(true); // true = read from m_frame2 xfadeStart(); } } // Take the memory off the list because when crossfade is done, the frame should get freed if(m_frame) { m_allocatedMemory -= m_frame->pointerLength(); #ifdef DEBUG_MEMORY_USAGE qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Allocated memory down to:"<<(m_allocatedMemory/1024/1024)<<"MB"; #endif //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark4"; } QImage localImage; if(m_shadowEnabled || m_borderWidth > 0.001) localImage = applyBorder(image); else localImage = image; // QImage bgImage(QSize(1000,750), QImage::Format_ARGB32_Premultiplied); // QBrush bgTexture(QPixmap("ColorTile2.png")); // QPainter bgPainter(&bgImage); // bgPainter.fillRect(bgImage.rect(), bgTexture); // bgPainter.end(); // //bgImage = bgImage.convertToFormat(QImage::Format_RGB32); // // localImage = bgImage; //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark5"; if(1) { //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Setting new m_frame"; m_frame = VideoFramePtr(new VideoFrame(localImage, 1000/30)); } else { m_frame = VideoFramePtr(new VideoFrame()); //m_frame->setPixelFormat(QVideoFrame::Format_RGB32); //m_frame->setCaptureTime(QTime::currentTime()); m_frame->setBufferType(VideoFrame::BUFFER_POINTER); m_frame->setHoldTime(1000/30); m_frame->setSize(localImage.size()); //m_frame->setDebugPtr(true); QImage::Format format = localImage.format(); m_frame->setPixelFormat( format == QImage::Format_ARGB32 ? QVideoFrame::Format_ARGB32 : format == QImage::Format_RGB32 ? QVideoFrame::Format_RGB32 : format == QImage::Format_RGB888 ? QVideoFrame::Format_RGB24 : format == QImage::Format_RGB16 ? QVideoFrame::Format_RGB565 : format == QImage::Format_RGB555 ? QVideoFrame::Format_RGB555 : //format == QImage::Format_ARGB32_Premultiplied ? QVideoFrame::Format_ARGB32_Premultiplied : // GLVideoDrawable doesn't support premultiplied - so the format conversion below will convert it to ARGB32 automatically QVideoFrame::Format_Invalid); if(m_frame->pixelFormat() == QVideoFrame::Format_Invalid) { qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<": image was not in an acceptable format, converting to ARGB32 automatically."; localImage = localImage.convertToFormat(QImage::Format_ARGB32); m_frame->setPixelFormat(QVideoFrame::Format_ARGB32); } memcpy(m_frame->allocPointer(localImage.byteCount()), (const uchar*)localImage.bits(), localImage.byteCount()); } m_allocatedMemory += localImage.byteCount(); m_image = image; // explicitly release the original image to see if that helps with memory... //image = QImage(); #ifdef DEBUG_MEMORY_USAGE qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Allocated memory up to:"<<(m_allocatedMemory/1024/1024)<<"MB"; #endif //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark7"; // Don't updateTexture if m_hqXfadeActive because // we'll updateTexture inside hqXfadeTick with a blended image if(!m_hqXfadeActive) updateTexture(); // QString file = QString("debug-%1-%2.png").arg(metaObject()->className()).arg(QString().sprintf("%p",((void*)this))); // m_image.save(file); // qDebug() << "QImageDrawable::setImage: "<<(QObject*)this<<": Wrote: "<<file; if(fpsLimit() <= 0.0 && !insidePaint) { //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" mark8"; updateGL(); if(!liveStatus()) m_needUpdate = true; } updateShadow(); //qDebug() << "GLImageDrawable::setImage(): "<<(QObject*)this<<" Set image size:"<<m_frame->image().size(); // TODO reimp so this code works // if(m_visiblePendingFrame) // { // //qDebug() << "GLVideoDrawable::frameReady: "<<this<<", pending visible set, calling setVisible("<<m_tempVisibleValue<<")"; // m_visiblePendingFrame = false; // GLDrawable::setVisible(m_tempVisibleValue); // } }
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; } }