#include "slideshow.h" #include "imageutils.h" #include "menuid.h" #include #include #include #include #include #include #include #include #include // takes two images and makes them the same size, resizing and centering on // the bg color if needed void centerImages(QImage &img1, QImage &img2, unsigned int bgColor) { int sx, sy, dx, dy, w, h, xoff, yoff; QImage tmpImage; unsigned int *srcData, *destData; if(img1.width() == img2.width() && img1.height() == img2.height()) return; if(img1.width() > img2.width()) w = img1.width(); else w = img2.width(); if(img1.height() > img2.height()) h = img1.height(); else h = img2.height(); if(img1.width() != w || img1.height() != h){ tmpImage.create(w, h, 32); tmpImage.fill(bgColor); xoff = (w-img1.width())/2; yoff = (h-img1.height())/2; for(sy=0, dy=yoff; sy < img1.height(); ++sy, ++dy){ srcData = (unsigned int *)img1.scanLine(sy); destData = (unsigned int *)tmpImage.scanLine(dy); for(sx=0, dx=xoff; sx < img1.width(); ++sx, ++dx){ destData[dx] = srcData[sx]; } } img1 = tmpImage; img1.detach(); tmpImage.reset(); } if(img2.width() != w || img2.height() != h){ tmpImage.create(w, h, 32); tmpImage.fill(bgColor); xoff = (w-img2.width())/2; yoff = (h-img2.height())/2; for(sy=0, dy=yoff; sy < img2.height(); ++sy, ++dy){ srcData = (unsigned int *)img2.scanLine(sy); destData = (unsigned int *)tmpImage.scanLine(dy); for(sx=0, dx=xoff; sx < img2.width(); ++sx, ++dx){ destData[dx] = srcData[sx]; } } img2 = tmpImage; img2.detach(); tmpImage.reset(); } } void removeAlpha(QImage &img, unsigned int bgColor) { int x, y; unsigned int *data; unsigned int pixel; float srcPercent, destPercent; unsigned char r = qRed(bgColor); unsigned char g = qGreen(bgColor); unsigned char b = qBlue(bgColor); unsigned char alpha; for(y=0; y < img.height(); ++y){ data = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ alpha = qAlpha(data[x]); if(alpha == 0) data[x] = qRgba(r, g, b, 255); else if(alpha != 255){ pixel = data[x]; srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; data[x] = qRgba((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*r)), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*g)), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*b)), 255); } } } } // blends two images by percent into dest void blendImages(QImage &img1, QImage &img2, QImage &dest, float percent) { int x, y; unsigned int *srcData1, *srcData2, *destData; float destPercent = 1.0-percent; for(y=0; y < dest.height(); ++y){ srcData1 = (unsigned int *)img1.scanLine(y); srcData2 = (unsigned int *)img2.scanLine(y); destData = (unsigned int *)dest.scanLine(y); for(x=0; x < dest.width(); ++x){ destData[x] = qRgba((int)((percent*qRed(srcData1[x])) + (destPercent*qRed(srcData2[x]))), (int)((percent*qGreen(srcData1[x])) + (destPercent*qGreen(srcData2[x]))), (int)((percent*qBlue(srcData1[x])) + (destPercent*qBlue(srcData2[x]))), 255); } } } KIFSlideShow::KIFSlideShow(const QStringList &fileList, int delay, bool maxpect, bool loop, int effectType, int effectDelay, QWidget *parent, const char *name) : QWidget(parent, name, WStyle_StaysOnTop | WType_Popup | WDestructiveClose | WX11BypassWM) { //connect(&t, SIGNAL(timeout()), this, SLOT(slotTimer())); setBackgroundMode(NoBackground); gc = XCreateGC(x11Display(), RootWindow(x11Display(), x11Screen()), 0, 0 ); KConfig *config = KGlobal::config(); config->setGroup("UISettings"); c = config->readColorEntry("FullScreenColor", &Qt::white); XSetForeground(x11Display(), gc, c.pixel()); for(int i=0; i < 4; ++i) effectFrame[i] = NULL; pix = new QPixmap(); nextPix = NULL; img = new QImage(); nextImg = new QImage(); max = maxpect; effect = effectType; effectTime = effectDelay; looping = loop; time = delay; list = fileList; move(0, 0); resize(QApplication::desktop()->size()); it = list.begin(); show(); slotTimer(); } KIFSlideShow::~KIFSlideShow() { t.stop(); XFreeGC(x11Display(), gc); for(int i=0; i < 4; ++i){ if(effectFrame[i]) delete effectFrame[i]; } if(pix) delete pix; if(nextPix) delete nextPix; delete img; delete nextImg; } void KIFSlideShow::scaleImage(QImage &img) { if(img.width() > width() || img.height() > height()){ int w = img.width(); int h = img.height(); if(w > width()){ float percent = ((float)width())/w; w = (int)(w*percent); h = (int)(h*percent); } if(h > height()){ float percent = ((float)height())/h; w = (int)(w*percent); h = (int)(h*percent); } img = img.smoothScale(w, h); } else if(max && img.width() < width() && img.height() < height()){ int w = img.width(); int h = img.height(); float percentW, percentH; // decide if to scale horizontally or vertically percentW = percentH = 0.0; if(img.width() < width()) percentW = ((float)width())/w; if(img.height() < height()) percentH = ((float)height())/h; // can we scale width to screensize w/out making height offscreen if(percentW && ((int)(h * percentW)) <= height()){ w = (int)(w*percentW); h = (int)(h*percentW); } // if not try to scale horizontally w/out making width offscreen else if(percentH && ((int)(w * percentH)) <= width()){ w = (int)(w*percentH); h = (int)(h*percentH); } img = img.smoothScale(w, h); } } void KIFSlideShow::slotTimer() { t.stop(); int timeout; QTime processTime; processTime.start(); if(it == list.end()){ if(looping) it = list.begin(); else{ close(); return; } } if(effect == NoSlideEffectID){ // no effect, just load image into pixmap loadImage(*img, (*it)); if(!img->isNull()){ scaleImage(*img); pix->convertFromImage(*img); } else pix->resize(0, 0); repaint(false); ++it; } else{ // Okay, there is an effect. Display this image, load up the next, // and calculate the next animation while displaying the current one if(nextPix){ QPixmap *tmp = pix; for(int i=0; i < 4; ++i){ if(effectFrame[i]){ pix = effectFrame[i]; paint(rect()); usleep(effectTime*1000); } } pix = tmp; *pix = *nextPix; } else{ nextPix = new QPixmap(); loadImage(*img, (*it)); if(!img->isNull()){ scaleImage(*img); convertImageToPixmap(*img, *pix); } else{ pix->resize(0, 0); img->create(100, 100, 32); img->fill(c.rgb()); } } repaint(false); ++it; if(it == list.end()){ if(looping) it = list.begin(); else{ qWarning("Doing early timeout"); timeout = time*1000-processTime.elapsed(); if(timeout < 300) // always keep a little delay timeout = 300; t.singleShot(timeout, this, SLOT(slotTimer())); return; } } loadImage(*nextImg, (*it)); if(!nextImg->isNull()){ scaleImage(*nextImg); convertImageToPixmap(*nextImg, *nextPix); } else{ nextPix->resize(0, 0); nextImg->create(100, 100, 32); nextImg->fill(c.rgb()); } for(int i=0; i < 4; ++i){ if(!effectFrame[i]) effectFrame[i] = new QPixmap(); } if(img->depth() < 32) *img = img->convertDepth(32); if(nextImg->depth() < 32) *nextImg = nextImg->convertDepth(32); if(img->hasAlphaBuffer()) removeAlpha(*img, c.rgb()); if(nextImg->hasAlphaBuffer()) removeAlpha(*nextImg, c.rgb()); if(effect == BlendSlideEffectID){ centerImages(*img, *nextImg, c.rgb()); QImage destImg(img->width(), img->height(), 32); blendImages(*img, *nextImg, destImg, 0.90); convertImageToPixmap(destImg, *effectFrame[0]); blendImages(*img, *nextImg, destImg, 0.75); convertImageToPixmap(destImg, *effectFrame[1]); blendImages(*img, *nextImg, destImg, 0.50); convertImageToPixmap(destImg, *effectFrame[2]); blendImages(*img, *nextImg, destImg, 0.25); convertImageToPixmap(destImg, *effectFrame[3]); } else if(effect == FadeSlideEffectID){ QImage destImg(KImageEffect::blend(c, *nextImg, 0.20)); convertImageToPixmap(destImg, *effectFrame[0]); destImg = KImageEffect::blend(c, *nextImg, 0.40); convertImageToPixmap(destImg, *effectFrame[1]); destImg = KImageEffect::blend(c, *nextImg, 0.60); convertImageToPixmap(destImg, *effectFrame[2]); destImg = KImageEffect::blend(c, *nextImg, 0.80); convertImageToPixmap(destImg, *effectFrame[3]); } *img = *nextImg; img->detach(); nextImg->reset(); } timeout = time*1000-processTime.elapsed(); if(timeout < 300) // always keep a little delay timeout = 300; t.singleShot(timeout, this, SLOT(slotTimer())); } void KIFSlideShow::paint(const QRect &rect) { if(pix->isNull()){ XFillRectangle(x11Display(), winId(), gc, 0, 0, width(), height()); return; } QRect pixRect(0, 0, pix->width(), pix->height()); QRect drawRect(rect); if(pix->width() < width()){ pixRect.setLeft(((width()-pix->width())/2)-1); pixRect.setWidth(pix->width()); // need to reset } if(pix->height() < height()){ pixRect.setTop(((height()-pix->height())/2)-1); pixRect.setHeight(pix->height()); } pixRect = pixRect.intersect(drawRect); if(pix->mask()) XFillRectangle(x11Display(), winId(), gc, pixRect.x(), pixRect.y(), drawRect.width(), drawRect.height()); bitBlt(this, pixRect.topLeft(), pix, drawRect, Qt::CopyROP); // fill in the edges int rects = 0; XRectangle rectangles[4]; if(drawRect.top() < pixRect.top()){ rectangles[rects].x = drawRect.x(); rectangles[rects].y = drawRect.x(); rectangles[rects].width = drawRect.width(); rectangles[rects].height = pixRect.top()-drawRect.top(); ++rects; } if(drawRect.left() < pixRect.left()){ rectangles[rects].x = drawRect.x(); rectangles[rects].y = pixRect.top()-drawRect.top(); rectangles[rects].width = pixRect.left()-drawRect.left(); rectangles[rects].height = drawRect.height()-pixRect.top(); ++rects; } if(drawRect.right() > pixRect.right()){ rectangles[rects].x = pixRect.right()+1; rectangles[rects].y = pixRect.top()-drawRect.top(); rectangles[rects].width = drawRect.right()-pixRect.right(); rectangles[rects].height = drawRect.height()-pixRect.top(); ++rects; } if(drawRect.bottom() > pixRect.bottom()){ rectangles[rects].x = pixRect.left(); rectangles[rects].y = pixRect.bottom()+1; rectangles[rects].width = pixRect.width(); rectangles[rects].height = drawRect.bottom()-pixRect.bottom(); ++rects; } if(rects) XFillRectangles(x11Display(), winId(), gc, rectangles, rects); } void KIFSlideShow::paintEvent(QPaintEvent *ev) { paint(ev->rect()); } void KIFSlideShow::closeEvent(QCloseEvent *ev) { t.stop(); pix->resize(0, 0); ev->accept(); } void KIFSlideShow::mousePressEvent(QMouseEvent *ev) { if(ev->button() == LeftButton){ close(); } }