Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

VGexp.cxx

Go to the documentation of this file.
00001 /*
00002  * @(#)src/VGexp.cxx  1.0  2002-09-07 09:52
00003  *
00004  * Copyright (C)  2002  Daniel Léonard
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019  */
00020 
00026 #include <utility>
00027 #include "Image.h"
00028 #include "SFCPath.h"
00029 #include "SFCPathFactory.h"
00030 #include "VGexp.h"
00031 #include "VGexpSpec.h"
00032 
00033 namespace halftoner
00034 {
00035 
00036 //---------------------------
00037 // Constructor
00038 //---------------------------
00039 
00040    VGexp::VGexp() throw()
00041    {
00042    // nothing
00043    }
00044 
00045 
00046 //---------------------------
00047 // Destructor
00048 //---------------------------
00049 
00050    VGexp::~VGexp()
00051    {
00052    // nothing
00053    }
00054 
00055 
00056 //---------------------------
00057 // Implemented method from Halftoner
00058 //---------------------------
00059 
00060    Image* VGexp::halftone(const Image& source, const HalftonerSpec* spec) throw (std::invalid_argument)
00061    {
00062    // dimensions
00063       const int width = source.getWidth();
00064       const int height = source.getHeight();
00065    // square check
00066       if (width != height)
00067       {
00068          string s("image is not square");
00069          throw std::invalid_argument(s);
00070       }
00071 
00072    // error diffusion parameters
00073       const VGexpSpec* vgspec = dynamic_cast<const VGexpSpec*>(spec);
00074       const int cluster = vgspec->getClusterSize();
00075       const float err1 = vgspec->getErr1();
00076       const float err2 = vgspec->getErr2();
00077       const float err3 = vgspec->getErr3();
00078       float acc[] = {0.0f, 0.0f, 0.0f};
00079 
00080    // getting the curve (can throw std::invalid_argument)
00081       const SFCPathFactory::SizeMnemonic& mnemonic = vgspec->getMnemonic();
00082       SFCPath* curve = SFCPathFactory::getInstance(mnemonic);
00083    // destination image
00084       Image* out = new Image(width, height);
00085    // needed variables
00086       int len = width * height;
00087       std::pair<int, int> maxblack; maxblack.first = 0; maxblack.second = 255;
00088       int grey;
00089       float accumulator = 0.0;
00090       std::pair<int, int> p;
00091       int black;
00092       int step;
00093    // here we go
00094       for (int i = 0; i < len; i += cluster)
00095       {
00096       // accumulator
00097          accumulator = acc[0];
00098          for (int n = 0; n < cluster; n++)
00099          {
00100             if (i + n < len)
00101             {
00102             // coordinates
00103                p = (*curve)[i + n];
00104             // colour
00105                grey = source.getColorAt(p.first, p.second);
00106             // accumulation
00107                accumulator += grey;
00108             // index
00109                if (maxblack.second > grey)
00110                {
00111                   maxblack.first = i + n;
00112                   maxblack.second = grey;
00113                }
00114             // all cluster pixels to white
00115                out->setColorAt(p.first, p.second, 1);
00116             }
00117          }
00118       // finding how many black pixels
00119          black = cluster;
00120          step = len - i;
00121          if (black > step) black = step;
00122          while (accumulator >= 255)
00123          {
00124             black--;
00125             accumulator -= 255;
00126          }
00127       // distributing error
00128          acc[0] = acc[1] + accumulator * err1;
00129          acc[1] = acc[2] + accumulator * err2;
00130          acc[2] = accumulator * err3;
00131       // distributing black pixels
00132          if (black > 0)
00133          {
00134             p = (*curve)[maxblack.first];
00135             out->setColorAt(p.first, p.second, 0);
00136             black--;
00137          }
00138          int pos;
00139          for (int n = 1; i + n < len; n++)
00140          {
00141          // checking invariants
00142             if (black == 0) break;
00143          // to the left
00144             pos = static_cast<int>(maxblack.first - n);
00145             if (pos >= static_cast<int>(i))
00146             {
00147                p = (*curve)[pos];
00148                out->setColorAt(p.first, p.second, 0);
00149                black--;
00150             }
00151             // we hit the edge of the cluster
00152             else
00153             {
00154                while (black > 0)
00155                {
00156                   pos = maxblack.first + n; n++;
00157                   p = (*curve)[pos];
00158                   out->setColorAt(p.first, p.second, 0);
00159                   black--;
00160                }
00161                break;
00162             }
00163          // checking invariants
00164             if (black == 0) break;
00165          // to the right
00166             pos = maxblack.first + n;
00167             if (pos < static_cast<int>(i + cluster))
00168             {
00169                p = (*curve)[pos];
00170                out->setColorAt(p.first, p.second, 0);
00171                black--;
00172             }
00173             // we hit the edge of the cluster
00174             else
00175             {
00176                while (black > 0)
00177                {
00178                   n++; pos = maxblack.first - n;
00179                   p = (*curve)[pos];
00180                   out->setColorAt(p.first, p.second, 0);
00181                   black--;
00182                }
00183                break;
00184             }
00185          }
00186       // reset index
00187          maxblack.first = 0; maxblack.second = 255;
00188       }
00189       delete curve;
00190       return out;
00191    }
00192 
00193 }

Generated on Sat Sep 7 16:31:41 2002 for Halftoning Library by doxygen1.2.17