37     void imageColors( QHash<QRgb, int> &colors, 
const QImage &image )
    40       int width = image.width();
    41       int height = image.height();
    43       const QRgb *currentScanLine = 
nullptr;
    44       QHash<QRgb, int>::iterator colorIt;
    45       for ( 
int i = 0; i < height; ++i )
    47         currentScanLine = ( 
const QRgb * )( image.scanLine( i ) );
    48         for ( 
int j = 0; j < width; ++j )
    50           colorIt = colors.find( currentScanLine[j] );
    51           if ( colorIt == colors.end() )
    53             colors.insert( currentScanLine[j], 1 );
    63     bool minMaxRange( 
const QgsColorBox &colorBox, 
int &redRange, 
int &greenRange, 
int &blueRange, 
int &alphaRange )
    65       if ( colorBox.size() < 1 )
    70       int rMin = std::numeric_limits<int>::max();
    71       int gMin = std::numeric_limits<int>::max();
    72       int bMin = std::numeric_limits<int>::max();
    73       int aMin = std::numeric_limits<int>::max();
    74       int rMax = std::numeric_limits<int>::min();
    75       int gMax = std::numeric_limits<int>::min();
    76       int bMax = std::numeric_limits<int>::min();
    77       int aMax = std::numeric_limits<int>::min();
    84       for ( 
auto colorBoxIt = colorBox.constBegin() ; colorBoxIt != colorBox.constEnd(); ++colorBoxIt )
    86         currentRed = qRed( colorBoxIt->first );
    87         if ( currentRed > rMax )
    91         if ( currentRed < rMin )
    96         currentGreen = qGreen( colorBoxIt->first );
    97         if ( currentGreen > gMax )
   101         if ( currentGreen < gMin )
   106         currentBlue = qBlue( colorBoxIt->first );
   107         if ( currentBlue > bMax )
   111         if ( currentBlue < bMin )
   116         currentAlpha = qAlpha( colorBoxIt->first );
   117         if ( currentAlpha > aMax )
   121         if ( currentAlpha < aMin )
   127       redRange = rMax - rMin;
   128       greenRange = gMax - gMin;
   129       blueRange = bMax - bMin;
   130       alphaRange = aMax - aMin;
   134     bool redCompare( QPair<QRgb, int> c1, QPair<QRgb, int> c2 )
   136       return qRed( c1.first ) < qRed( c2.first );
   139     bool greenCompare( QPair<QRgb, int> c1, QPair<QRgb, int> c2 )
   141       return qGreen( c1.first ) < qGreen( c2.first );
   144     bool blueCompare( QPair<QRgb, int> c1, QPair<QRgb, int> c2 )
   146       return qBlue( c1.first ) < qBlue( c2.first );
   149     bool alphaCompare( QPair<QRgb, int> c1, QPair<QRgb, int> c2 )
   151       return qAlpha( c1.first ) < qAlpha( c2.first );
   154     QRgb boxColor( 
const QgsColorBox &box, 
int boxPixels )
   165       for ( 
auto colorBoxIt = box.constBegin(); colorBoxIt != box.constEnd(); ++colorBoxIt )
   167         currentColor = colorBoxIt->first;
   168         currentPixel = colorBoxIt->second;
   169         weight = 
static_cast<double>( currentPixel ) / boxPixels;
   170         avRed   += ( qRed( currentColor ) * weight );
   171         avGreen += ( qGreen( currentColor ) * weight );
   172         avBlue  += ( qBlue( currentColor ) * weight );
   173         avAlpha += ( qAlpha( currentColor ) * weight );
   176       return qRgba( avRed, avGreen, avBlue, avAlpha );
   180     void splitColorBox( QgsColorBox &colorBox, QgsColorBoxMap &colorBoxMap,
   181                         QMap<int, QgsColorBox>::iterator colorBoxMapIt )
   184       if ( colorBox.size() < 2 )
   195       if ( !minMaxRange( colorBox, redRange, greenRange, blueRange, alphaRange ) )
   201       if ( redRange >= greenRange && redRange >= blueRange && redRange >= alphaRange )
   203         std::sort( colorBox.begin(), colorBox.end(), redCompare );
   205       else if ( greenRange >= redRange && greenRange >= blueRange && greenRange >= alphaRange )
   207         std::sort( colorBox.begin(), colorBox.end(), greenCompare );
   209       else if ( blueRange >= redRange && blueRange >= greenRange && blueRange >= alphaRange )
   211         std::sort( colorBox.begin(), colorBox.end(), blueCompare );
   215         std::sort( colorBox.begin(), colorBox.end(), alphaCompare );
   219       double halfSum = colorBoxMapIt.key() / 2.0;
   221       int currentListIndex = 0;
   223       auto colorBoxIt = colorBox.begin();
   224       for ( ; colorBoxIt != colorBox.end(); ++colorBoxIt )
   226         currentSum += colorBoxIt->second;
   227         if ( currentSum >= halfSum )
   234       if ( currentListIndex > ( colorBox.size() - 2 ) ) 
   237         currentSum -= colorBoxIt->second;
   245       QgsColorBox newColorBox1 = colorBox.mid( 0, currentListIndex + 1 );
   246       colorBoxMap.insert( currentSum, newColorBox1 );
   248       colorBox.erase( colorBox.begin(), colorBoxIt );
   249       QgsColorBox newColorBox2 = colorBox;
   250       colorBoxMap.erase( colorBoxMapIt );
   251       colorBoxMap.insert( halfSum * 2.0 - currentSum, newColorBox2 );
   256   void medianCut( QVector<QRgb> &colorTable, 
int nColors, 
const QImage &inputImage )
   258     QHash<QRgb, int> inputColors;
   259     imageColors( inputColors, inputImage );
   261     if ( inputColors.size() <= nColors ) 
   263       colorTable.resize( inputColors.size() );
   265       for ( 
auto inputColorIt = inputColors.constBegin(); inputColorIt != inputColors.constEnd(); ++inputColorIt )
   267         colorTable[index] = inputColorIt.key();
   274     QgsColorBox firstBox; 
   275     int firstBoxPixelSum = 0;
   276     for ( 
auto  inputColorIt = inputColors.constBegin(); inputColorIt != inputColors.constEnd(); ++inputColorIt )
   278       firstBox.push_back( qMakePair( inputColorIt.key(), inputColorIt.value() ) );
   279       firstBoxPixelSum += inputColorIt.value();
   282     QgsColorBoxMap colorBoxMap; 
   283     colorBoxMap.insert( firstBoxPixelSum, firstBox );
   284     QMap<int, QgsColorBox>::iterator colorBoxMapIt = colorBoxMap.end();
   287     bool allColorsMapped = 
false;
   288     while ( colorBoxMap.size() < nColors )
   291       colorBoxMapIt = colorBoxMap.end();
   295         if ( colorBoxMapIt.value().size() > 1 )
   297           splitColorBox( colorBoxMapIt.value(), colorBoxMap, colorBoxMapIt );
   300         if ( colorBoxMapIt == colorBoxMap.begin() )
   302           allColorsMapped = 
true;
   307       if ( allColorsMapped )
   315     colorTable.resize( colorBoxMap.size() );
   316     for ( 
auto colorBoxIt = colorBoxMap.constBegin(); colorBoxIt != colorBoxMap.constEnd(); ++colorBoxIt )
   318       colorTable[index] = boxColor( colorBoxIt.value(), colorBoxIt.key() );
 QList< QPair< QRgb, int > > QgsColorBox
Median cut implementation. 
void medianCut(QVector< QRgb > &colorTable, int nColors, const QImage &inputImage)
Median cut implementation used when reducing RGB colors to palletized colors. 
QMultiMap< int, QgsColorBox > QgsColorBoxMap