Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

histogramEditor.cpp

Go to the documentation of this file.
00001 //==============================================
00002 //  copyright            : (C) 2003-2005 by Will Stokes
00003 //==============================================
00004 //  This program is free software; you can redistribute it
00005 //  and/or modify it under the terms of the GNU General
00006 //  Public License as published by the Free Software
00007 //  Foundation; either version 2 of the License, or
00008 //  (at your option) any later version.
00009 //==============================================
00010 
00011 //Systemwide includes
00012 #include <qlayout.h>
00013 #include <qlabel.h>
00014 #include <qcombobox.h>
00015 #include <qpushbutton.h>
00016 #include <qframe.h>
00017 #include <qslider.h>
00018 #include <qtooltip.h>
00019 #include <qsizegrip.h>
00020 
00021 //Projectwide includes
00022 #include "histogramEditor.h"
00023 #include "scaledPreviewInterface.h"
00024 #include "histogramInterface.h"
00025 #include "../clickableLabel.h"
00026 #include "../dynamicSlider.h"
00027 #include "../../config.h"
00028 #include "../../backend/tools/imageTools.h"
00029 
00030 #define SLIDER_RADIUS 40
00031 
00032 //==============================================
00033 HistogramEditor::HistogramEditor( QString fileName, QWidget *parent, const char* name ) : QDialog(parent,name,true)
00034 {
00035   //set pointer to null to make sure no 
00036   //random data is ever accessed by the preview interface
00037   histogramInterface = NULL;
00038 
00039   //record filename
00040   this->fileName = fileName;
00041   
00042   //-----
00043   //find mean color values
00044   meanR = 0;
00045   meanG = 0;
00046   meanB = 0;
00047   int x, y;
00048   QRgb* rgb;
00049   uchar* scanLine;
00050   QImage image = QImage( fileName );
00051   for( y=0; y<image.height(); y++)
00052   {   
00053     scanLine = image.scanLine(y);
00054     for( x=0; x<image.width(); x++)
00055     {
00056       rgb = ((QRgb*)scanLine+x);
00057       double r = ((double)qRed(*rgb)   )/255.0;
00058       double g = ((double)qGreen(*rgb) )/255.0;
00059       double b = ((double)qBlue(*rgb)  )/255.0;
00060       
00061       meanR+=r;
00062       meanG+=g;
00063       meanB+=b;
00064     } //x
00065   } //y
00066   meanR = meanR / ( image.width() * image.height() );
00067   meanG = meanG / ( image.width() * image.height() );
00068   meanB = meanB / ( image.width() * image.height() );
00069   
00070   QFrame* visibleFrame = new QFrame( this, "visible widgets" );
00071   //--------------  
00072   //Preview frame: 
00073   previewInterface = new ScaledPreviewInterface( fileName, visibleFrame, 
00074                                                  "previewInterface" );
00075   connect( previewInterface, SIGNAL(resized()), 
00076            this, SLOT(generateAdjustedPreviewImage()) );  
00077 
00078   previewSelection = new QComboBox( visibleFrame, "previewSelction" );
00079   previewSelection->insertItem( tr("Split View") );
00080   previewSelection->insertItem( tr("Original Image") );
00081   previewSelection->insertItem( tr("Adjusted Image") );
00082   connect( previewSelection, SIGNAL(activated(int)), this, SLOT(selectPreviewImageType(int)) );  
00083   //--------------
00084   //Adjust frame:   
00085   histogramInterface = new HistogramInterface( fileName, visibleFrame, 
00086                                                "histogramInterface" );  
00087 
00088   //connect adjustments in histogram to generateAdjustedPreviewImage
00089   connect( histogramInterface, SIGNAL( selectedRangeChanged() ),
00090            SLOT( generateAdjustedPreviewImage() ) );
00091   
00092   QToolTip::add( histogramInterface, tr("Click and drag to select tonal range") );  
00093 
00094   histogramType = new QComboBox( visibleFrame, "histogramType" );
00095   histogramType->insertItem( tr("Luminosity") );
00096   histogramType->insertItem( tr("Red") );
00097   histogramType->insertItem( tr("Green") );
00098   histogramType->insertItem( tr("Blue") );  
00099   connect( histogramType, SIGNAL(activated(int)), this, SLOT(selectHistogramType(int)) );  
00100   QToolTip::add( histogramType, tr("Histogram channel displayed") );  
00101   //--------------
00102   //Slider frame:
00103   QString noChange = QString( tr("No change") );
00104   
00105   brightness = new DynamicSlider( Qt::Vertical, visibleFrame );
00106   brightness->setZeroString( noChange );
00107   brightness->setPrefixes("", "+");
00108   brightness->setMinValue( -SLIDER_RADIUS );
00109   brightness->setMaxValue( SLIDER_RADIUS );
00110   connect( brightness, SIGNAL(valueChanged(int)),
00111            this, SLOT(generateAdjustedPreviewImage()) );;
00112   QToolTip::add( brightness, tr("Drag to adjust image brightness") );  
00113            
00114   brightnessIcon = new ClickableLabel( visibleFrame, "brightnessIcon" );
00115   brightnessIcon->setPixmap( QPixmap(QString(IMAGE_PATH)+"miscImages/brightness.png") );
00116   connect( brightnessIcon, SIGNAL(clicked()), SLOT(resetBrightness()) );    
00117   QToolTip::add( brightnessIcon, tr("Reset brightness") );
00118 
00119   contrast = new DynamicSlider( Qt::Vertical, visibleFrame );
00120   contrast->setZeroString( noChange );
00121   contrast->setPrefixes("", "+");
00122   contrast->setMinValue( -SLIDER_RADIUS );
00123   contrast->setMaxValue( SLIDER_RADIUS );
00124   connect( contrast, SIGNAL(valueChanged(int)),
00125            this, SLOT(generateAdjustedPreviewImage()) );
00126   QToolTip::add( contrast, tr("Drag to adjust image contrast") );  
00127 
00128   contrastIcon = new ClickableLabel( visibleFrame, "contrastIcon" );
00129   contrastIcon->setPixmap( QPixmap(QString(IMAGE_PATH)+"miscImages/contrast.png") );
00130   connect( contrastIcon, SIGNAL(clicked()), SLOT(resetContrast()) );    
00131   QToolTip::add( contrastIcon, tr("Reset contrast") );
00132   //--------------
00133   //Dialog buttons:  
00134   buttonsFrame =   new QFrame( visibleFrame, "dialogButtons" );
00135 
00136   QPushButton* applyButton = new QPushButton( tr("Apply"), buttonsFrame );
00137   applyButton->setDefault(true);
00138   applyButton->setFocus();
00139   connect( applyButton, SIGNAL(clicked()), SLOT(applyAction()) );
00140                                 
00141   QPushButton* cancelButton = new QPushButton( tr("Cancel"), buttonsFrame );
00142   connect( cancelButton, SIGNAL(clicked()), SLOT(reject()) );
00143 
00144   QPushButton* resetButton = new QPushButton( tr("Reset"), buttonsFrame );
00145   connect( resetButton, SIGNAL(clicked()), SLOT(resetAction()) );
00146 
00147   QGridLayout* buttonsGrid = new QGridLayout( buttonsFrame, 1, 5, 0 );
00148   buttonsGrid->setColStretch( 0, 1 );
00149   buttonsGrid->addWidget( applyButton,  0, 1 );
00150   buttonsGrid->addWidget( cancelButton, 0, 2 );
00151   buttonsGrid->addWidget( resetButton, 0, 3 );
00152   buttonsGrid->setColStretch( 4, 1 );  
00153   buttonsGrid->setSpacing( WIDGET_SPACING );
00154   //--------------
00155   QGridLayout* mainGrid = new QGridLayout( visibleFrame, 5, 3, 0 );
00156   
00157   mainGrid->addMultiCellWidget( previewInterface,     0,0, 0,2 );
00158   mainGrid->addMultiCellWidget( previewSelection, 1,1, 0,2, Qt::AlignHCenter );  
00159    
00160   mainGrid->addWidget( histogramInterface,    2, 0 ); 
00161   mainGrid->addWidget( brightness,            2, 1 );
00162   mainGrid->addWidget( contrast,              2, 2 );
00163   
00164   //make sure sliders have enough space so all slider units are settable
00165   mainGrid->setRowSpacing( 2, 2*SLIDER_RADIUS + 5) ;
00166     
00167   mainGrid->addWidget( histogramType,    3, 0, Qt::AlignHCenter );
00168   mainGrid->addWidget( brightnessIcon,   3, 1 );  
00169   mainGrid->addWidget( contrastIcon,     3, 2 );  
00170   
00171   mainGrid->addMultiCellWidget( buttonsFrame, 4,4, 0,2 );
00172 
00173   mainGrid->setRowStretch( 0, 1 );
00174   mainGrid->setColStretch( 0, 1 );
00175   
00176   mainGrid->setSpacing( WIDGET_SPACING );
00177   mainGrid->setMargin( WIDGET_SPACING );
00178   
00179   QGridLayout* invisibleGrid = new QGridLayout( this, 2, 1, 0 );
00180   invisibleGrid->addWidget( visibleFrame, 0, 0 );
00181   invisibleGrid->setRowStretch( 0, 1 );
00182   
00183   //PLATFORM_SPECIFIC_CODE
00184   //windows users expect a grip, but qt doesn't put one in by default. we'll add
00185   //it for them too. :-)
00186 #if defined(Q_OS_WIN)
00187   QSizeGrip* sizeGrip = new QSizeGrip( this );
00188   invisibleGrid->addWidget( sizeGrip, 1, 0, Qt::AlignRight | Qt::AlignBottom );
00189 #endif
00190   
00191   
00192   
00193   
00194   //Window caption
00195   setCaption( tr("Album Shaper: Histogram Editor") );
00196   //-------------------------------
00197 }
00198 //==============================================
00199 HistogramEditor::~HistogramEditor() { }
00200 //==============================================
00201 void HistogramEditor::applyAction()
00202 {
00203   //check if user has adjusted brightness, contrast, or histogram ranges.
00204   //if any changes have taken place call "accept", else "reject" so image is not
00205   //updated and appear modified
00206   int lumLeft, lumRight, redLeft, redRight, greenLeft, greenRight, blueLeft, blueRight;
00207   histogramInterface->getHistBoundaries( lumLeft, lumRight,
00208                                          redLeft, redRight,
00209                                          greenLeft, greenRight,
00210                                          blueLeft, blueRight );  
00211   if( brightness->value() != 0 || contrast->value()   != 0 ||
00212       lumLeft != 0 || lumRight != 255 ||
00213       redLeft !=0 || redRight != 255 ||
00214       greenLeft != 0 || greenRight != 255 ||
00215       blueLeft != 0 || blueRight != 255 )
00216   { accept(); }
00217   else
00218   { reject(); }  
00219 }
00220 //==============================================
00221 void HistogramEditor::resetAction()
00222 {
00223   histogramInterface->resetBoundaries();
00224   resetBrightness();
00225   resetContrast();
00226 }
00227 //==============================================
00228 QImage* HistogramEditor::getModifiedImage()
00229 { 
00230   QImage* adjustedImage = new QImage(fileName);
00231   adjustImage( *adjustedImage );
00232   return adjustedImage;  
00233 }
00234 //==============================================
00235 void HistogramEditor::selectPreviewImageType( int selection )
00236 {
00237   previewInterface->setPreviewMode( (PREVIEW_MODE)selection );
00238 }
00239 //==============================================
00240 void HistogramEditor::selectHistogramType( int selection )
00241 {
00242   histogramInterface->setDisplayChannel( (DISPLAYED_CHANNEL) selection );
00243 }
00244 //==============================================
00245 void HistogramEditor::resetBrightness()
00246 { brightness->setValue( 0 ); }
00247 //==============================================
00248 void HistogramEditor::resetContrast()
00249 { contrast->setValue( 0 ); }
00250 //==============================================
00251 void HistogramEditor::getHistBoundaries(int &lumLeft, int &lumRight,
00252                                         int &redLeft, int &redRight,
00253                                         int &greenLeft, int &greenRight,
00254                                         int &blueLeft, int &blueRight)
00255 {
00256   //sanity check
00257   if( histogramInterface )
00258   {
00259     histogramInterface->getHistBoundaries( lumLeft, lumRight,
00260                                            redLeft, redRight,
00261                                            greenLeft, greenRight,
00262                                            blueLeft, blueRight );
00263   }
00264   else
00265   {
00266     lumLeft = 0; lumRight = 255;
00267     redLeft = 0; redRight = 255;
00268     greenLeft = 0; greenRight = 255;
00269     blueLeft = 0; blueRight = 255;
00270   }
00271 }
00272 //==============================================
00273 void HistogramEditor::generateAdjustedPreviewImage()
00274 {
00275   //get original image
00276   QImage origImage = previewInterface->getOrigImage();
00277 
00278   //construct adjusted image
00279   QImage adjustedImage = origImage.copy();
00280   adjustImage( adjustedImage );
00281   
00282   //set adjusted image
00283   previewInterface->setAdjustedImage( adjustedImage );
00284 }
00285 //==============================================
00286 void HistogramEditor::adjustImage( QImage &image )
00287 {
00288   //obtain histogram left and right boundaries
00289   //sanity check
00290   int lumLeft, lumRight, redLeft, redRight, greenLeft, greenRight, blueLeft, blueRight;
00291   if( histogramInterface )
00292   {
00293     histogramInterface->getHistBoundaries( lumLeft, lumRight,
00294                                            redLeft, redRight,
00295                                            greenLeft, greenRight,
00296                                            blueLeft, blueRight );
00297   }
00298   else
00299   {
00300     lumLeft = 0; lumRight = 255;
00301     redLeft = 0; redRight = 255;
00302     greenLeft = 0; greenRight = 255;
00303     blueLeft = 0; blueRight = 255;
00304   }
00305   
00306   //modify image
00307   double displayToOneScalar = 1.0/255.0;
00308   double scaledMeanR = displayToOneScalar*scaleColor( 255.0*meanR, redLeft, redRight );
00309   double scaledMeanG = displayToOneScalar*scaleColor( 255.0*meanG, greenLeft, greenRight );
00310   double scaledMeanB = displayToOneScalar*scaleColor( 255.0*meanB, blueLeft, blueRight );
00311   
00312   double brightnessScalar, addedBrightnessColor;
00313   if(brightness->value() < 0)
00314   {
00315     brightnessScalar = ((double)(SLIDER_RADIUS + brightness->value()))/SLIDER_RADIUS;
00316     addedBrightnessColor = 1.0 - brightnessScalar;
00317   }
00318   else
00319   {
00320     brightnessScalar = ((double)(SLIDER_RADIUS - brightness->value()))/SLIDER_RADIUS;
00321     addedBrightnessColor = 0.0;
00322   }
00323   
00324   int x, y;  
00325   QRgb* rgb;
00326   double r,g,b;
00327   double h,s,v;
00328   int rPrime, gPrime, bPrime;
00329   uchar* scanLine;
00330   
00331   for( y=0; y<image.height(); y++)
00332   {   
00333     scanLine = image.scanLine(y);
00334     for( x=0; x<image.width(); x++)
00335     {
00336       //get rgb value
00337       rgb = ((QRgb*)scanLine+x);
00338       r = qRed(*rgb);
00339       g = qGreen(*rgb);
00340       b = qBlue(*rgb);
00341       
00342       //apply histogram boundaries
00343       RGBtoHSV(r,g,b,&h,&s,&v);
00344       v = scaleColor( v, lumLeft, lumRight );
00345       HSVtoRGB( &r,&g,&b, h,s,v);         
00346       
00347       r = scaleColor( r, redLeft, redRight );
00348       g = scaleColor( g, greenLeft, greenRight );
00349       b = scaleColor( b, blueLeft, blueRight );
00350       
00351       //convert to 0-1 scale
00352       r = r*displayToOneScalar;
00353       g = g*displayToOneScalar;
00354       b = b*displayToOneScalar;
00355       
00356       //adjust contrast
00357       r = ( (r-scaledMeanR) * (SLIDER_RADIUS-contrast->value()) )/SLIDER_RADIUS + scaledMeanR;
00358       g = ( (g-scaledMeanG) * (SLIDER_RADIUS-contrast->value()) )/SLIDER_RADIUS + scaledMeanG;
00359       b = ( (b-scaledMeanB) * (SLIDER_RADIUS-contrast->value()) )/SLIDER_RADIUS + scaledMeanB;
00360       
00361       //apply brightness adjustment
00362       //http://www.sgi.com/misc/grafica/interp/
00363       r = brightnessScalar*r + addedBrightnessColor;
00364       g = brightnessScalar*g + addedBrightnessColor;
00365       b = brightnessScalar*b + addedBrightnessColor;
00366       
00367       //scale and clamp to 0-255 range
00368       rPrime = (int) QMIN( QMAX((r*255), 0), 255 );
00369       gPrime = (int) QMIN( QMAX((g*255), 0), 255 );
00370       bPrime = (int) QMIN( QMAX((b*255), 0), 255 );
00371       
00372       //set adjusted color value
00373       *rgb = qRgb(rPrime, gPrime, bPrime);          
00374     } //x
00375   } //y  
00376 }
00377 //==============================================
00378 double HistogramEditor::scaleColor( double color, int left, int right )
00379 {
00380   return QMAX( QMIN( (255.0*(color-left)) / (right-left), 255), 0 );  
00381 }
00382 //==============================================
00383 void HistogramEditor::keyPressEvent(QKeyEvent *e)
00384 {
00385   if(e->key() == Qt::Key_Control )
00386   {
00387     PREVIEW_MODE curMode = (PREVIEW_MODE) previewSelection->currentItem();
00388     if(curMode == ORIGINAL_IMAGE)
00389       previewInterface->setPreviewMode( ADJUSTED_IMAGE, true );
00390     else if(curMode == ADJUSTED_IMAGE)
00391       previewInterface->setPreviewMode( ORIGINAL_IMAGE, true );
00392     else
00393       previewInterface->setPreviewMode( INV_SPLIT_VIEW );
00394   }
00395   else { QDialog::keyPressEvent(e); }
00396 }
00397 //==============================================
00398 void HistogramEditor::keyReleaseEvent(QKeyEvent *e)
00399 {
00400   if(e->key() == Qt::Key_Control )
00401   {
00402     previewInterface->setPreviewMode( (PREVIEW_MODE) previewSelection->currentItem(), 
00403                                       false );
00404   }
00405   else { QDialog::keyReleaseEvent(e); }
00406 }
00407 //==============================================
00408 
00409 

Generated on Sat Apr 2 05:44:04 2005 for AlbumShaper by  doxygen 1.3.9.1