00001 #include "oimagescrollview.h"
00002
00003 #include <opie2/oimagezoomer.h>
00004 #include <opie2/odebug.h>
00005 #include <opie2/oapplication.h>
00006 #include <opie2/owait.h>
00007 #include <opie2/opieexif.h>
00008
00009 #include <qimage.h>
00010 #include <qlayout.h>
00011
00012
00013 #define AUTO_SCALE 0
00014 #define AUTO_ROTATE 1
00015 #define SHOW_ZOOMER 2
00016 #define FIRST_RESIZE_DONE 3
00017 #define IMAGE_IS_JPEG 4
00018 #define IMAGE_SCALED_LOADED 5
00019
00020 #define SCROLLVIEW_BITSET_SIZE 6
00021
00022 namespace Opie {
00023 namespace MM {
00024 OImageScrollView::OImageScrollView( QWidget* parent, const char* name, WFlags f )
00025 :QScrollView(parent,name,f|Qt::WRepaintNoErase ),_image_data(),_original_data(),
00026 m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("")
00027 {
00028 _zoomer = 0;
00029 m_states[AUTO_SCALE]=true;
00030 m_states[AUTO_ROTATE]=true;
00031 m_states[FIRST_RESIZE_DONE]=false;
00032 m_states[IMAGE_IS_JPEG]=false;
00033 m_states[IMAGE_SCALED_LOADED]=false;
00034 m_states[SHOW_ZOOMER]=true;
00035 _newImage = true;
00036 init();
00037 }
00038
00039 OImageScrollView::OImageScrollView (const QImage&img, QWidget * parent, const char * name, WFlags f,bool always_scale,bool rfit)
00040 :QScrollView(parent,name,f|Qt::WRepaintNoErase),_image_data(),_original_data(img),
00041 m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("")
00042 {
00043 _zoomer = 0;
00044 m_states[AUTO_SCALE]=always_scale;
00045 m_states[AUTO_ROTATE]=rfit;
00046 m_states[FIRST_RESIZE_DONE]=false;
00047 m_states[IMAGE_IS_JPEG]=false;
00048 m_states[IMAGE_SCALED_LOADED]=false;
00049 m_states[SHOW_ZOOMER]=true;
00050 _original_data.convertDepth(QPixmap::defaultDepth());
00051 _original_data.setAlphaBuffer(false);
00052 _newImage = true;
00053 init();
00054 }
00055
00056 OImageScrollView::OImageScrollView (const QString&img, QWidget * parent, const char * name, WFlags f,bool always_scale,bool rfit)
00057 :QScrollView(parent,name,f|Qt::WRepaintNoErase),_image_data(),_original_data(),m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("")
00058 {
00059 _zoomer = 0;
00060 m_states.resize(SCROLLVIEW_BITSET_SIZE);
00061 m_states[AUTO_SCALE]=always_scale;
00062 m_states[AUTO_ROTATE]=rfit;
00063 m_states[FIRST_RESIZE_DONE]=false;
00064 m_states[IMAGE_IS_JPEG]=false;
00065 m_states[IMAGE_SCALED_LOADED]=false;
00066 m_states[SHOW_ZOOMER]=true;
00067 _newImage = true;
00068 init();
00069 setImage(img);
00070 }
00071
00072 void OImageScrollView::setImage(const QImage&img)
00073 {
00074 _image_data = QImage();
00075 _original_data=img;
00076 _original_data.convertDepth(QPixmap::defaultDepth());
00077 _original_data.setAlphaBuffer(false);
00078 m_lastName = "";
00079 setImageIsJpeg(false);
00080 setImageScaledLoaded(false);
00081 _newImage = true;
00082 if (FirstResizeDone()) {
00083 generateImage();
00084 }
00085 }
00086
00087 void OImageScrollView::loadJpeg(bool interncall)
00088 {
00089 if (m_lastName.isEmpty()) return;
00090 QImageIO iio( m_lastName, 0l );
00091 QString param;
00092 bool real_load = false;
00093 _newImage = true;
00094 if (AutoScale()) {
00095 if (!interncall) {
00096 ExifData xf;
00097 bool scanned = xf.scan(m_lastName);
00098 int wid, hei;
00099 wid = QApplication::desktop()->width();
00100 hei = QApplication::desktop()->height();
00101 if (hei>wid) {
00102 wid = hei;
00103 } else {
00104 hei = wid;
00105 }
00106 if ( (scanned && (wid<xf.getWidth()||hei<xf.getHeight()))||!scanned ) {
00107 param = QString( "Fast Shrink( 3 ) Scale( %1, %2, ScaleMin)" ).arg( wid ).arg( hei );
00108 iio.setParameters(param.latin1());
00109 setImageScaledLoaded(true);
00110 }
00111
00112 real_load = true;
00113 }
00114 } else {
00115 if (ImageScaledLoaded()||!interncall) {
00116 real_load = true;
00117 }
00118 setImageScaledLoaded(false);
00119 }
00120 if (real_load) {
00121 _original_data = iio.read() ? iio.image() : QImage();
00122 }
00123 }
00124
00125 void OImageScrollView::setImage( const QString& path ) {
00126 if (m_lastName == path) return;
00127 m_lastName = path;
00128 _newImage = true;
00129 _original_data = QImage();
00130 QString itype = QImage::imageFormat(m_lastName);
00131 if (itype == "JPEG") {
00132 setImageIsJpeg(true);
00133 loadJpeg();
00134 } else {
00135 setImageIsJpeg(false);
00136 _original_data.load(path);
00137 _original_data.convertDepth(QPixmap::defaultDepth());
00138 _original_data.setAlphaBuffer(false);
00139 }
00140 _image_data = QImage();
00141 if (FirstResizeDone()) {
00142 generateImage();
00143 if (isVisible()) viewport()->repaint(true);
00144 }
00145 }
00146
00147
00148 void OImageScrollView::init()
00149 {
00150
00151
00152
00153
00154 _zoomer = new Opie::MM::OImageZoomer( this, "The Zoomer" );
00155 connect(_zoomer, SIGNAL( zoomAreaRel(int,int)),
00156 this, SLOT(scrollBy(int,int)) );
00157 connect(_zoomer, SIGNAL( zoomArea(int,int)),
00158 this, SLOT(center(int,int)) );
00159 connect(this,SIGNAL(contentsMoving(int,int)),
00160 _zoomer, (SLOT(setVisiblePoint(int,int))) );
00161 connect(this,SIGNAL(imageSizeChanged(const QSize&)),
00162 _zoomer, SLOT(setImageSize(const QSize&)) );
00163 connect(this,SIGNAL(viewportSizeChanged(const QSize&)),
00164 _zoomer, SLOT(setViewPortSize(const QSize&)) );
00165
00166 setBackgroundColor(white);
00167 setFocusPolicy(QWidget::StrongFocus);
00168 setImageScaledLoaded(false);
00169 setImageIsJpeg(false);
00170 if (FirstResizeDone()) {
00171 m_last_rot = Rotate0;
00172 generateImage();
00173 } else if (_original_data.size().isValid()) {
00174 if (image_fit_into(_original_data.size()) || !ShowZoomer()) _zoomer->hide();
00175 resizeContents(_original_data.width(),_original_data.height());
00176 }
00177 _intensity = 0;
00178 }
00179
00180 void OImageScrollView::setAutoRotate(bool how)
00181 {
00182
00183 if (AutoRotate() != how) {
00184 m_states.setBit(AUTO_ROTATE,how);
00185 _image_data = QImage();
00186 generateImage();
00187 }
00188 }
00189
00190 bool OImageScrollView::AutoRotate()const
00191 {
00192 return m_states.testBit(AUTO_ROTATE);
00193 }
00194
00195 void OImageScrollView::setAutoScaleRotate(bool scale, bool rotate)
00196 {
00197 m_states.setBit(AUTO_ROTATE,rotate);
00198 setAutoScale(scale);
00199 }
00200
00201 void OImageScrollView::setAutoScale(bool how)
00202 {
00203 m_states.setBit(AUTO_SCALE,how);
00204 _image_data = QImage();
00205 if (ImageIsJpeg() && how == false && ImageScaledLoaded()==true) {
00206 loadJpeg(true);
00207 }
00208 _newImage = true;
00209 generateImage();
00210 }
00211
00212 bool OImageScrollView::AutoScale()const
00213 {
00214 return m_states.testBit(AUTO_SCALE);
00215 }
00216
00217 OImageScrollView::~OImageScrollView()
00218 {
00219 }
00220
00221 void OImageScrollView::rescaleImage(int w, int h)
00222 {
00223 if (_image_data.width()==w && _image_data.height()==h) {
00224 return;
00225 }
00226 double hs = (double)h / (double)_image_data.height() ;
00227 double ws = (double)w / (double)_image_data.width() ;
00228 double scaleFactor = (hs > ws) ? ws : hs;
00229 int smoothW = (int)(scaleFactor * _image_data.width());
00230 int smoothH = (int)(scaleFactor * _image_data.height());
00231 _image_data = _image_data.smoothScale(smoothW,smoothH);
00232 }
00233
00234 void OImageScrollView::rotate_into_data(Rotation r)
00235 {
00236
00237
00238 QImage dest;
00239 int x, y;
00240 if ( _original_data.depth() > 8 )
00241 {
00242 unsigned int *srcData, *destData;
00243 switch ( r )
00244 {
00245 case Rotate90:
00246 dest.create(_original_data.height(), _original_data.width(), _original_data.depth());
00247 for ( y=0; y < _original_data.height(); ++y )
00248 {
00249 srcData = (unsigned int *)_original_data.scanLine(y);
00250 for ( x=0; x < _original_data.width(); ++x )
00251 {
00252 destData = (unsigned int *)dest.scanLine(x);
00253 destData[_original_data.height()-y-1] = srcData[x];
00254 }
00255 }
00256 break;
00257 case Rotate180:
00258 dest.create(_original_data.width(), _original_data.height(), _original_data.depth());
00259 for ( y=0; y < _original_data.height(); ++y )
00260 {
00261 srcData = (unsigned int *)_original_data.scanLine(y);
00262 destData = (unsigned int *)dest.scanLine(_original_data.height()-y-1);
00263 for ( x=0; x < _original_data.width(); ++x )
00264 destData[_original_data.width()-x-1] = srcData[x];
00265 }
00266 break;
00267 case Rotate270:
00268 dest.create(_original_data.height(), _original_data.width(), _original_data.depth());
00269 for ( y=0; y < _original_data.height(); ++y )
00270 {
00271 srcData = (unsigned int *)_original_data.scanLine(y);
00272 for ( x=0; x < _original_data.width(); ++x )
00273 {
00274 destData = (unsigned int *)dest.scanLine(_original_data.width()-x-1);
00275 destData[y] = srcData[x];
00276 }
00277 }
00278 break;
00279 default:
00280 dest = _original_data;
00281 break;
00282 }
00283 }
00284 else
00285 {
00286 unsigned char *srcData, *destData;
00287 unsigned int *srcTable, *destTable;
00288 switch ( r )
00289 {
00290 case Rotate90:
00291 dest.create(_original_data.height(), _original_data.width(), _original_data.depth());
00292 dest.setNumColors(_original_data.numColors());
00293 srcTable = (unsigned int *)_original_data.colorTable();
00294 destTable = (unsigned int *)dest.colorTable();
00295 for ( x=0; x < _original_data.numColors(); ++x )
00296 destTable[x] = srcTable[x];
00297 for ( y=0; y < _original_data.height(); ++y )
00298 {
00299 srcData = (unsigned char *)_original_data.scanLine(y);
00300 for ( x=0; x < _original_data.width(); ++x )
00301 {
00302 destData = (unsigned char *)dest.scanLine(x);
00303 destData[_original_data.height()-y-1] = srcData[x];
00304 }
00305 }
00306 break;
00307 case Rotate180:
00308 dest.create(_original_data.width(), _original_data.height(), _original_data.depth());
00309 dest.setNumColors(_original_data.numColors());
00310 srcTable = (unsigned int *)_original_data.colorTable();
00311 destTable = (unsigned int *)dest.colorTable();
00312 for ( x=0; x < _original_data.numColors(); ++x )
00313 destTable[x] = srcTable[x];
00314 for ( y=0; y < _original_data.height(); ++y )
00315 {
00316 srcData = (unsigned char *)_original_data.scanLine(y);
00317 destData = (unsigned char *)dest.scanLine(_original_data.height()-y-1);
00318 for ( x=0; x < _original_data.width(); ++x )
00319 destData[_original_data.width()-x-1] = srcData[x];
00320 }
00321 break;
00322 case Rotate270:
00323 dest.create(_original_data.height(), _original_data.width(), _original_data.depth());
00324 dest.setNumColors(_original_data.numColors());
00325 srcTable = (unsigned int *)_original_data.colorTable();
00326 destTable = (unsigned int *)dest.colorTable();
00327 for ( x=0; x < _original_data.numColors(); ++x )
00328 destTable[x] = srcTable[x];
00329 for ( y=0; y < _original_data.height(); ++y )
00330 {
00331 srcData = (unsigned char *)_original_data.scanLine(y);
00332 for ( x=0; x < _original_data.width(); ++x )
00333 {
00334 destData = (unsigned char *)dest.scanLine(_original_data.width()-x-1);
00335 destData[y] = srcData[x];
00336 }
00337 }
00338 break;
00339 default:
00340 dest = _original_data;
00341 break;
00342 }
00343
00344 }
00345 _newImage = true;
00346 _image_data = dest;
00347 }
00348
00349
00350 void OImageScrollView::apply_gamma(int aValue)
00351 {
00352 if (aValue==0 || !_image_data.size().isValid()) return;
00353 float percent = ((float)aValue/100.0);
00354
00355 _image_data.detach();
00356
00357 int segColors = _image_data.depth() > 8 ? 256 : _image_data.numColors();
00358
00359 if (segColors<256) segColors=256;
00360
00361 unsigned char *segTbl = new unsigned char[segColors];
00362 int pixels = _image_data.depth()>8?_image_data.width()*_image_data.height() : _image_data.numColors();
00363
00364
00365 bool brighten = (percent >= 0);
00366 if ( percent < 0 ) {
00367 percent = -percent;
00368 }
00369
00370 unsigned int *data = _image_data.depth() > 8 ? (unsigned int *)_image_data.bits() :
00371 (unsigned int *)_image_data.colorTable();
00372
00373 int tmp = 0;
00374
00375 if (brighten) {
00376 for ( int i=0; i < segColors; ++i )
00377 {
00378 tmp = (int)(i*percent);
00379 if ( tmp > 255 )
00380 tmp = 255;
00381 segTbl[i] = tmp;
00382 }
00383 } else {
00384 for ( int i=0; i < segColors; ++i )
00385 {
00386 tmp = (int)(i*percent);
00387 if ( tmp < 0 )
00388 tmp = 0;
00389 segTbl[i] = tmp;
00390 }
00391 }
00392 if (brighten) {
00393 for ( int i=0; i < pixels; ++i )
00394 {
00395 int r = qRed(data[i]);
00396 int g = qGreen(data[i]);
00397 int b = qBlue(data[i]);
00398 int a = qAlpha(data[i]);
00399 r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
00400 g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
00401 b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
00402 data[i] = qRgba(r, g, b,a);
00403 }
00404 } else {
00405 for ( int i=0; i < pixels; ++i )
00406 {
00407 int r = qRed(data[i]);
00408 int g = qGreen(data[i]);
00409 int b = qBlue(data[i]);
00410 int a = qAlpha(data[i]);
00411 r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
00412 g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
00413 b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
00414 data[i] = qRgba(r, g, b, a);
00415 }
00416 }
00417 delete [] segTbl;
00418 }
00419
00420 const int OImageScrollView::Intensity()const
00421 {
00422 return _intensity;
00423 }
00424
00425 int OImageScrollView::setIntensity(int value,bool reload)
00426 {
00427 int oldi = _intensity;
00428 _intensity = value;
00429 if (!_pdata.size().isValid()) {
00430 return _intensity;
00431 }
00432
00433 if (!reload) {
00434 _image_data = _pdata.convertToImage();
00435 apply_gamma(_intensity-oldi);
00436 _pdata.convertFromImage(_image_data);
00437
00438
00439
00440 _image_data=QImage();
00441 if (isVisible()) {
00442 updateContents(contentsX(),contentsY(),width(),height());
00443 }
00444 } else {
00445 _newImage = true;
00446 generateImage();
00447 }
00448 return _intensity;
00449 }
00450
00451 void OImageScrollView::generateImage()
00452 {
00453 Rotation r = Rotate0;
00454 _pdata = QPixmap();
00455 if (_original_data.isNull()) {
00456 emit imageSizeChanged( _image_data.size() );
00457 if (_zoomer) _zoomer->setImage( _image_data );
00458 return;
00459 }
00460 if (width()>height()&&_original_data.width()<_original_data.height() ||
00461 width()<height()&&_original_data.width()>_original_data.height()) {
00462 if (AutoRotate()) r = Rotate90;
00463 }
00464
00465 int twidth,theight;
00466 if (AutoScale() && (_original_data.width()>width() || _original_data.height() > height()) ) {
00467 if (!_image_data.size().isValid()||width()>_image_data.width()||height()>_image_data.height()) {
00468 if (r==Rotate0) {
00469 _image_data = _original_data;
00470 } else {
00471 rotate_into_data(r);
00472 }
00473 _newImage = true;
00474 }
00475 rescaleImage(width(),height());
00476 } else if (!FirstResizeDone()||r!=m_last_rot||_image_data.width()==0) {
00477 if (r==Rotate0) {
00478 _image_data = _original_data;
00479 } else {
00480 rotate_into_data(r);
00481 }
00482 m_last_rot = r;
00483 }
00484
00485 if (_newImage) {
00486 apply_gamma(_intensity);
00487 _newImage = false;
00488 }
00489
00490 _pdata.convertFromImage(_image_data);
00491 twidth = _image_data.width();
00492 theight = _image_data.height();
00493
00494
00495
00496
00497 check_zoomer();
00498 emit imageSizeChanged( _image_data.size() );
00499 rescaleImage( 128, 128 );
00500 resizeContents(twidth,theight);
00501
00502
00503
00504 if (_zoomer) {
00505 _zoomer->setGeometry( viewport()->width()-_image_data.width()/2, viewport()->height()-_image_data.height()/2,
00506 _image_data.width()/2, _image_data.height()/2 );
00507 _zoomer->setImage( _image_data );
00508 }
00509
00510
00511
00512 _image_data=QImage();
00513 if (isVisible()) {
00514 updateContents(contentsX(),contentsY(),width(),height());
00515 }
00516 }
00517
00518 void OImageScrollView::resizeEvent(QResizeEvent * e)
00519 {
00520 QScrollView::resizeEvent(e);
00521 if (e->oldSize()==e->size()||!isUpdatesEnabled ()) return;
00522 generateImage();
00523 setFirstResizeDone(true);
00524 emit viewportSizeChanged( viewport()->size() );
00525
00526 }
00527
00528 void OImageScrollView::keyPressEvent(QKeyEvent * e)
00529 {
00530 if (!e) return;
00531 int dx = horizontalScrollBar()->lineStep();
00532 int dy = verticalScrollBar()->lineStep();
00533 if (e->key()==Qt::Key_Right) {
00534 scrollBy(dx,0);
00535 e->accept();
00536 } else if (e->key()==Qt::Key_Left) {
00537 scrollBy(0-dx,0);
00538 e->accept();
00539 } else if (e->key()==Qt::Key_Up) {
00540 scrollBy(0,0-dy);
00541 e->accept();
00542 } else if (e->key()==Qt::Key_Down) {
00543 scrollBy(0,dy);
00544 e->accept();
00545 } else {
00546 e->ignore();
00547 }
00548 QScrollView::keyPressEvent(e);
00549 }
00550
00551 void OImageScrollView::drawContents(QPainter * p, int clipx, int clipy, int clipw, int cliph)
00552 {
00553 if (!_pdata.size().isValid()) {
00554 p->fillRect(clipx,clipy,clipw,cliph, backgroundColor());
00555 return;
00556 }
00557
00558 int w = clipw;
00559 int h = cliph;
00560 int x = clipx;
00561 int y = clipy;
00562 bool erase = false;
00563
00564 if (w>_pdata.width()) {
00565 w = _pdata.width()-x;
00566 erase=true;
00567 }
00568 if (h>_pdata.height()) {
00569 h = _pdata.height()-y;
00570 erase=true;
00571 }
00572 if (!erase && (clipy+cliph>_pdata.height()||clipx+clipw>_pdata.width())) {
00573 erase = true;
00574 }
00575 if (erase||_original_data.hasAlphaBuffer()) {
00576 p->fillRect(clipx,clipy,clipw,cliph, backgroundColor());
00577 }
00578 if (w>0 && h>0&&x<_pdata.width()&&y<_pdata.height()) {
00579 p->drawPixmap(clipx,clipy,_pdata,x,y,w,h);
00580 }
00581 }
00582
00583
00584 void OImageScrollView::viewportMouseMoveEvent(QMouseEvent* e)
00585 {
00586 int mx, my;
00587 mx = e->x();
00588 my = e->y();
00589 if (_mouseStartPosX!=-1 && _mouseStartPosY!=-1) {
00590 int diffx = _mouseStartPosX-mx;
00591 int diffy = _mouseStartPosY-my;
00592 scrollBy(diffx,diffy);
00593 }
00594 _mouseStartPosX=mx;
00595 _mouseStartPosY=my;
00596 }
00597
00598 void OImageScrollView::contentsMousePressEvent ( QMouseEvent * e)
00599 {
00600
00601
00602
00603
00604
00605 _mouseStartPosX = -1;
00606 _mouseStartPosY = -1;
00607 }
00608
00609 void OImageScrollView::setDestructiveClose() {
00610 WFlags fl = getWFlags();
00611
00612 fl &= ~WDestructiveClose;
00613 fl |= WDestructiveClose;
00614 setWFlags( fl );
00615 }
00616
00617 bool OImageScrollView::image_fit_into(const QSize&s )
00618 {
00619 if (s.width()>width()||s.height()>height()) {
00620 return false;
00621 }
00622 return true;
00623 }
00624
00625 void OImageScrollView::setShowZoomer(bool how)
00626 {
00627 m_states.setBit(SHOW_ZOOMER,how);
00628 check_zoomer();
00629 }
00630
00631 bool OImageScrollView::ShowZoomer()const
00632 {
00633 return m_states.testBit(SHOW_ZOOMER);
00634 }
00635
00636 void OImageScrollView::check_zoomer()
00637 {
00638 if (!_zoomer) return;
00639 if ( (!ShowZoomer()||image_fit_into(_pdata.size()) ) && _zoomer->isVisible()) {
00640 _zoomer->hide();
00641 } else if ( ShowZoomer() && !image_fit_into(_pdata.size()) && _zoomer->isHidden()){
00642 _zoomer->show();
00643 }
00644 }
00645
00646 bool OImageScrollView::FirstResizeDone()const
00647 {
00648 return m_states.testBit(FIRST_RESIZE_DONE);
00649 }
00650
00651 void OImageScrollView::setFirstResizeDone(bool how)
00652 {
00653 m_states.setBit(FIRST_RESIZE_DONE,how);
00654 }
00655
00656 bool OImageScrollView::ImageIsJpeg()const
00657 {
00658 return m_states.testBit(IMAGE_IS_JPEG);
00659 }
00660
00661 void OImageScrollView::setImageIsJpeg(bool how)
00662 {
00663 m_states.setBit(IMAGE_IS_JPEG,how);
00664 }
00665
00666 bool OImageScrollView::ImageScaledLoaded()const
00667 {
00668 return m_states.testBit(IMAGE_SCALED_LOADED);
00669 }
00670
00671 void OImageScrollView::setImageScaledLoaded(bool how)
00672 {
00673 m_states.setBit(IMAGE_SCALED_LOADED,how);
00674 }
00675
00676 }
00677 }