[Libreoffice-commits] core.git: Branch 'private/bansan/chardraw' - 6 commits - config_host.mk.in configure.ac cui/Library_cui.mk cui/source download.lst RepositoryExternal.mk

Vincent Le Garrec legarrec.vincent at gmail.com
Tue Jan 16 21:18:13 UTC 2018


 RepositoryExternal.mk                        |   15 +
 config_host.mk.in                            |    2 
 configure.ac                                 |    6 
 cui/Library_cui.mk                           |    4 
 cui/source/dialogs/cuicharmap.cxx            |  386 ++++++++++++++++++++++++++-
 cui/source/factory/neuralnetwork.cxx         |   37 ++
 cui/source/factory/neuralnetworkfann.cxx     |  133 +++++++++
 cui/source/factory/neuralnetworkfann.hxx     |   58 ++++
 cui/source/factory/neuralnetworkinternal.cxx |  360 +++++++++++++++++++++++++
 cui/source/inc/cuicharmap.hxx                |   23 +
 cui/source/inc/neuralnetwork.hxx             |   55 +++
 download.lst                                 |    2 
 12 files changed, 1080 insertions(+), 1 deletion(-)

New commits:
commit 56bfe8ecdc5f3e41ea8ce84ef4e9b54c86f1e2ec
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:15:44 2018 +0100

    First try to make a NN implementation
    
    It doesn't work but a good work has been done.
    
    Change-Id: I09d9ed910ef8a905fa0f3e0a689b741006f6fd18

diff --git a/cui/source/factory/neuralnetwork.cxx b/cui/source/factory/neuralnetwork.cxx
index 5651b80b3ab8..cd08d084b7f4 100644
--- a/cui/source/factory/neuralnetwork.cxx
+++ b/cui/source/factory/neuralnetwork.cxx
@@ -20,15 +20,18 @@
 #include <neuralnetwork.hxx>
 
 #include "neuralnetworkfann.hxx"
+#include "neuralnetworkinternal.hxx"
 
 AbstractNeuralNetwork * AbstractNeuralNetwork::CreateFactory(sal_uInt32 nLayers, const sal_uInt32* nLayer)
 {
-    return new NeuralNetworkFann(nLayers, nLayer);
+//    return new NeuralNetworkFann(nLayers, nLayer);
+    return new NeuralNetworkInternal(nLayers, nLayer);
 }
 
 AbstractNeuralNetwork * AbstractNeuralNetwork::CreateFactory(const OUString& file)
 {
-    return new NeuralNetworkFann(file);
+//    return new NeuralNetworkFann(file);
+    return new NeuralNetworkInternal(file);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/factory/neuralnetworkfann.cxx b/cui/source/factory/neuralnetworkfann.cxx
index e622916c1ccf..2366989e7d8b 100644
--- a/cui/source/factory/neuralnetworkfann.cxx
+++ b/cui/source/factory/neuralnetworkfann.cxx
@@ -39,6 +39,11 @@ void NeuralNetworkFann::SetActivationFunction(ActivationFunction function)
     {
         case ActivationFunction::SIGMOID:
         {
+            func = FANN_SIGMOID;
+            break;
+        }
+        case ActivationFunction::SIGMOID_SYMMETRIC:
+        {
             func = FANN_SIGMOID_SYMMETRIC;
             break;
         }
@@ -75,8 +80,6 @@ void NeuralNetworkFann::SetLearningRate(float rate)
    fann_set_learning_rate(ann.get(), rate);
 }
 
-#include <iostream>
-
 void NeuralNetworkFann::InitTraining(sal_uInt32 nExamples)
 {
     data.reset(fann_create_train(nExamples, fann_get_num_input(ann.get()), fann_get_num_output(ann.get())));
@@ -108,9 +111,18 @@ float* NeuralNetworkFann::GetOutput(sal_uInt32 nIeme)
     return &data->output[nIeme][0];
 }
 
-float* NeuralNetworkFann::Run(float *data_input)
+void NeuralNetworkFann::Run(float *data_input, float *result)
 {
-    return fann_run(ann.get(), data_input);
+    float * fann_result = fann_run(ann.get(), data_input);
+
+    if (result == nullptr)
+    {
+        return;
+    }
+    for (sal_uInt32 i = 0; i < GetNumOutput(); i++)
+    {
+        result[i] = fann_result[i];
+    }
 }
 
 void NeuralNetworkFann::Train(sal_uInt32 nEpochs, float error)
diff --git a/cui/source/factory/neuralnetworkfann.hxx b/cui/source/factory/neuralnetworkfann.hxx
index 472f4640dde3..993d78c0f3d2 100644
--- a/cui/source/factory/neuralnetworkfann.hxx
+++ b/cui/source/factory/neuralnetworkfann.hxx
@@ -41,11 +41,13 @@ public:
     float* GetOutput(sal_uInt32 nIeme) override;
 
     void Train(sal_uInt32 nEpochs, float error) override;
-    float* Run(float *data_input) override;
+    void Run(float *data_input, float* result) override;
     void Save(const OUString& file) override;
 
     virtual ~NeuralNetworkFann(){}
 
+    virtual void * GetTrain(){return data.get();}
+
 private:
     std::unique_ptr<struct fann, void(*)(struct fann *)> ann;
     std::unique_ptr<struct fann_train_data, void(*)(struct fann_train_data *)> data;
diff --git a/cui/source/factory/neuralnetworkinternal.cxx b/cui/source/factory/neuralnetworkinternal.cxx
index 52597c57ca92..087f9c1c6d55 100644
--- a/cui/source/factory/neuralnetworkinternal.cxx
+++ b/cui/source/factory/neuralnetworkinternal.cxx
@@ -17,4 +17,344 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include "neuralnetworkinternal.hxx"
+
+#include <iostream>
+#include <fstream>
+
+NeuralNetworkInternal::NeuralNetworkInternal(sal_uInt32 nLayers, const sal_uInt32* nLayer) :
+    n(nLayers, std::vector<Neuron>()),
+    learning_rate(0.2),
+    learning_rate_alpha(0.4),
+    learning_input(),
+    learning_output()
+{
+    for (sal_uInt32 i = 0; i < nLayers; i++)
+    {
+        n[i].resize(nLayer[i]+1); // One neuron is biais.
+
+        if (i != nLayers-1)
+        {
+            for (sal_uInt32 j = 0; j < n[i].size() /*with biais*/; j++)
+            {
+                n[i][j].w.resize(nLayer[i+1]); /*no biais*/
+                n[i][j].dw.resize(nLayer[i+1]);
+                for (sal_uInt32 k = 0; k < nLayer[i+1]; k++)
+                {
+                    // Between [0;.1]
+                    n[i][j].w[k] = (float)std::rand() / (float)RAND_MAX *0.2 - 0.1;
+                }
+            }
+        }
+    }
+}
+
+NeuralNetworkInternal::NeuralNetworkInternal(const OUString& file) :
+    n(), learning_rate(0.), learning_rate_alpha(0.), learning_input(),
+    learning_output()
+{
+    OString o = OUStringToOString(file, RTL_TEXTENCODING_ASCII_US);
+    const char * o_str = o.pData->buffer;
+
+    std::ifstream infile (o_str, std::ifstream::binary);
+    sal_uInt32 tmpInt;
+
+    infile.read(reinterpret_cast<char *>(&learning_rate), sizeof(learning_rate));
+    infile.read(reinterpret_cast<char *>(&learning_rate_alpha), sizeof(learning_rate_alpha));
+    infile.read(reinterpret_cast<char *>(&tmpInt), sizeof(tmpInt));
+    n.resize(tmpInt);
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+    {
+        infile.read(reinterpret_cast<char *>(&tmpInt), sizeof(tmpInt));
+        n[i].resize(tmpInt);
+    }
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+    {
+        if (i != n.size()-1)
+        {
+            for (sal_uInt32 j = 0; j < n[i].size(); j++)
+            {
+                n[i][j].w.resize(n[i+1].size());
+                n[i][j].dw.resize(n[i+1].size());
+            }
+        }
+    }
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+        for (sal_uInt32 j = 0; j < n[i].size(); j++)
+        {
+            infile.read(reinterpret_cast<char *>(&n[i][j].w[0]), n[i][j].w.size()*sizeof(n[i][j].w[0]));
+            infile.read(reinterpret_cast<char *>(&n[i][j].dw[0]), n[i][j].dw.size()*sizeof(n[i][j].dw[0]));
+        }
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+        for (sal_uInt32 j = 0; j < n[i].size(); j++)
+        {
+            infile.read(reinterpret_cast<char *>(&n[i][j].f), sizeof(n[i][j].f));
+            infile.read(reinterpret_cast<char *>(&n[i][j].stp), sizeof(n[i][j].stp));
+        }
+}
+
+void NeuralNetworkInternal::SetActivationFunction(ActivationFunction function)
+{
+    FunctionTrans func;
+
+    switch (function)
+    {
+        case ActivationFunction::SIGMOID:
+        {
+            func = FunctionTrans::Sigmoid;
+            break;
+        }
+        case ActivationFunction::SIGMOID_SYMMETRIC:
+        {
+            func = FunctionTrans::SigmoidSymmetric;
+            break;
+        }
+        default:
+        {
+            return;
+        }
+    }
+
+    for (sal_uInt32 i = 1; i < n.size(); i++)
+    {
+        for (sal_uInt32 j = 0; j < n[i].size(); j++)
+        {
+            n[i][j].f = func;
+        }
+    }
+}
+
+void NeuralNetworkInternal::SetTrainingAlgorithm(TrainingAlgorithm algorithm)
+{
+    return;
+}
+
+void NeuralNetworkInternal::SetLearningRate(float rate)
+{
+    learning_rate = rate;
+}
+
+void NeuralNetworkInternal::InitTraining(sal_uInt32 nExamples)
+{
+    learning_input.resize(nExamples, std::vector<float>(n[0].size(), 0));
+    learning_output.resize(nExamples, std::vector<float>(n.back().size(), 0));
+}
+
+sal_uInt32 NeuralNetworkInternal::GetNumInput()
+{
+    return n[0].size();
+}
+
+float* NeuralNetworkInternal::GetInput(sal_uInt32 nIeme)
+{
+    if (nIeme >= learning_input.size())
+        return nullptr;
+    return &learning_input[nIeme][0];
+}
+
+sal_uInt32 NeuralNetworkInternal::GetNumOutput()
+{
+    return n.back().size();
+}
+
+float* NeuralNetworkInternal::GetOutput(sal_uInt32 nIeme)
+{
+    if (nIeme >= learning_output.size())
+        return nullptr;
+    return &learning_output[nIeme][0];
+}
+
+void NeuralNetworkInternal::Train(sal_uInt32 nEpochs, float error)
+{
+    for (sal_uInt32 l = 0; l < nEpochs; l++)
+    {
+        for (sal_uInt32 m = 0; m < learning_input.size(); m++)
+        {
+            Run(&learning_input[m][0], nullptr);
+
+            if (l == nEpochs-1)
+            {
+                for (sal_uInt32 i = 0; i < n.back().size(); i++)
+                    std::cout << n.back()[i].a << " ";
+                std::cout << std::endl;
+            }
+
+            // error
+            float errori = 0.f;
+            for (sal_uInt32 i = 0; i < n.back().size()-1 /*no biais*/; i++)
+            {
+                errori += (learning_input[m][i] - n.back()[i].a)*(learning_input[m][i] - n.back()[i].a);
+            }
+            errori = errori / (n.back().size()-1);
+            errori = sqrt(errori);
+            std::cout << "error " << l << "," << m << ":" << errori << std::endl;
+
+            // Calcul de sM
+            // s: ann->train_errors
+            for (sal_uInt32 i = 0; i < n.back().size()-1 /*no biais*/; i++)
+            {
+                float diff = learning_output[m][i] - n.back()[i].a;
+                switch (n.back()[i].f)
+                {
+                    case FunctionTrans::Sigmoid:
+                        {
+                            n.back()[i].s = 2.*n.back()[i].stp*n.back()[i].a*(1.-n.back()[i].a)*diff;
+                            break;
+                        }
+                    case FunctionTrans::SigmoidSymmetric:
+                        {
+                            // If Symmetric: diff/2.
+                            diff = diff / 2.;
+                            n.back()[i].s = n.back()[i].stp*(1.-n.back()[i].a*n.back()[i].a)*diff;
+                            break;
+                        }
+
+                        /*
+ftLineaire  : RNA.s[High(RNA.s)][I] := -2*(SortiesTest[I] - RNA.a[High(RNA.a)][I]);
+
+ftTanHyperb : RNA.s[High(RNA.s)][I] := -2*(1-RNA.a[High(RNA.a)][I]*RNA.a[High(RNA.a)][I])*
+
+(SortiesTest[I] - RNA.a[High(RNA.a)][I])
+*/
+                }
+            }
+
+            // Calcul des sk
+            // fann_activation_derived
+            for (sal_uInt32 i = n.size()-2 /*No Output layer*/; i > 0; i--)
+            {
+                for (sal_uInt32 j = 0; j < n[i].size() /*with biais*/; j++)
+                {
+                    float sum = 0.f;
+                    //connection_rate >= 1
+                    for (sal_uInt32 k = 0; k < n[i+1].size()-1 /*no biais*/; k++)
+                    {
+                        sum += n[i][j].w[k] * n[i+1][k].s;
+                    }
+                    switch (n[i][j].f)
+                    {
+                        case FunctionTrans::Sigmoid:
+                            {
+                                n[i][j].s = sum * 2. * n[i][j].stp * n[i][j].a * (1. - n[i][j].a);
+                                break;
+                            }
+                        case FunctionTrans::SigmoidSymmetric:
+                            {
+                                n[i][j].s = sum * n[i][j].stp * (1. - n[i][j].a*n[i][j].a);
+                                break;
+                            }
+                        default:
+                            {
+                                return;
+                            }
+
+                            // Cette ligne est volontairement commentée car pour une fonction linéaire,
+                            // il aurait fallu mettre RNA.s[I][J] := RNA.s[I][J] * 1, ce qui ne sert à rien
+                            //        ftLineaire : RNA.s[I][J] := RNA.s[I][J] * 1;
+
+                            //        ftTanHyperb : RNA.s[I][J] := RNA.s[I][J] * (1 - RNA.a[I][J]*RNA.a[I][J]);
+                    }
+                }
+            }
+
+            // Modifications des poids et des biais
+            for (sal_uInt32 i = n.size()-1 /*No input layer*/; i > 0; --i)
+            {
+                for (sal_uInt32 j = 0; j < n[i].size() - 1 /*no biais*/; j++)
+                {
+                    for (sal_uInt32 k = 0; k < n[i-1].size() /*with biais*/; k++)
+                    {
+                        float delta = learning_rate * n[i][j].s * n[i-1][k].a + learning_rate_alpha * n[i-1][k].dw[j];
+                        n[i-1][k].dw[j] = delta;
+                        n[i-1][k].w[j] += delta;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void NeuralNetworkInternal::Run(float *data_input, float *result)
+{
+    // Calcul de a0
+    for (sal_uInt32 i = 0; i < n[0].size(); i++)
+        n[0][i].a = data_input[i];
+
+    // Calcul des ak
+
+    for (sal_uInt32 i = 1; i < n.size(); i++)
+    {
+        for (sal_uInt32 j = 0; j < n[i].size()-1 /*no biais*/; j++)
+        {
+            n[i][j].sum = 0;
+            for (sal_uInt32 k = 0; k < n[i-1].size() /*with biais*/; k++)
+                n[i][j].sum += n[i-1][k].a * n[i-1][k].w[j];
+            n[i][j].sum *= n[i][j].stp;
+            switch (n[i][j].f)
+            {
+                case FunctionTrans::Sigmoid:
+                    {
+                        n[i][j].a = 1.f / (1.f + exp(-2.f*n[i][j].sum));
+                        break;
+                    }
+                case FunctionTrans::SigmoidSymmetric:
+                    {
+                        n[i][j].a = 2.f/(1.f + exp(-2.f/n[i][j].sum)) - 1.f;
+                        break;
+                    }
+                default:
+                    {
+                        return;
+                    }
+            }
+        }
+    }
+
+
+    if (result == nullptr)
+    {
+        return;
+    }
+    for (sal_uInt32 i = 0; i < n.back().size(); i++)
+        result[i] = n.back()[i].a;
+}
+
+void NeuralNetworkInternal::Save(const OUString& file)
+{
+    OString o = OUStringToOString(file, RTL_TEXTENCODING_ASCII_US);
+    const char * o_str = o.pData->buffer;
+
+    std::ofstream outfile (o_str, std::ofstream::binary);
+
+    outfile.write(reinterpret_cast<const char *>(&learning_rate), sizeof(learning_rate));
+    outfile.write(reinterpret_cast<const char *>(&learning_rate_alpha), sizeof(learning_rate_alpha));
+
+    sal_uInt32 tmpInt = n.size();
+    outfile.write(reinterpret_cast<const char *>(&tmpInt), sizeof(tmpInt));
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+    {
+        tmpInt = n[i].size();
+        outfile.write(reinterpret_cast<const char *>(&tmpInt), sizeof(tmpInt));
+    }
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+        for (sal_uInt32 j = 0; j < n[i].size(); j++)
+        {
+            outfile.write(reinterpret_cast<const char *>(&n[i][j].w[0]), n[i][j].w.size()*sizeof(n[i][j].w[0]));
+            outfile.write(reinterpret_cast<const char *>(&n[i][j].dw[0]), n[i][j].dw.size()*sizeof(n[i][j].dw[0]));
+        }
+
+    for (sal_uInt32 i = 0; i < n.size(); i++)
+        for (sal_uInt32 j = 0; j < n[i].size(); j++)
+        {
+            outfile.write(reinterpret_cast<const char *>(&n[i][j].f), sizeof(n[i][j].f));
+            outfile.write(reinterpret_cast<const char *>(&n[i][j].stp), sizeof(n[i][j].stp));
+        }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6bdd077f569a629965a4f1544d83606bf410f4fe
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:13:21 2018 +0100

    Use libfann through an abstract factory
    
    With this, libfann can easily replaced by internal implementation or
    other lib.
    
    Use memory instead of using a temporary file to train the neural
    network.
    
    Change-Id: I1ec207ec5674ebba112d50425d445e5f38ada666

diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index 449a44ea22d3..5933cae387f5 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -134,6 +134,9 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/factory/cuiresmgr \
     cui/source/factory/dlgfact \
     cui/source/factory/init \
+    cui/source/factory/neuralnetwork \
+    cui/source/factory/neuralnetworkfann \
+    cui/source/factory/neuralnetworkinternal \
     cui/source/options/certpath \
     cui/source/options/cfgchart \
     cui/source/options/connpoolconfig \
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index ecff74b6a6e0..a1fd1a8ee3c9 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -42,6 +42,7 @@
 
 #include <dialmgr.hxx>
 #include <cuicharmap.hxx>
+#include <neuralnetwork.hxx>
 #include <sfx2/request.hxx>
 #include <sfx2/sfxsids.hrc>
 #include <sfx2/app.hxx>
@@ -215,46 +216,6 @@ void Ocr::ScaleBitmap(long width, long height)
     h_ = height;
 }
 
-void Ocr::ToFile(std::ofstream &file)
-{
-    BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
-
-    std::cout << "2r->Width () != w_" << r->Width () << " vs " << w_ << std::endl;
-    std::cout << "2r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
-    for (long j = 0; j < h_; j++)
-    {
-        for (long i = 0; i < w_; i++)
-        {
-            if (i >= r->Width () || j >= r->Height())
-            {
-                file << "0 ";
-                std::cout << "-1 ";
-            }
-            else
-            {
-                Color c = r->GetPixel(j, i);
-                if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
-                {
-                    file << "0 ";
-                    std::cout << "-1 ";
-                }
-                else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
-                {
-                    file << " 1 ";
-                    std::cout << " 1 ";
-                }
-                else
-                {
-                    file << " 1 ";
-                    std::cout << " 1 ";
-                }
-            }
-        }
-        std::cout << std::endl;
-    }
-    file << std::endl;
-}
-
 void Ocr::ToFann(fann_type *out_data)
 {
     BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
@@ -269,7 +230,7 @@ void Ocr::ToFann(fann_type *out_data)
         {
             if (i >= r->Width () || j >= r->Height())
             {
-                out_data[idata] = 0;
+                out_data[idata] = 0.;
                 std::cout << "-1 ";
             }
             else
@@ -277,17 +238,17 @@ void Ocr::ToFann(fann_type *out_data)
                 Color c = r->GetPixel(j, i);
                 if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
                 {
-                    out_data[idata] = 0;
+                    out_data[idata] = 0.;
                     std::cout << "-1 ";
                 }
                 else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
                 {
-                    out_data[idata] = 1;
+                    out_data[idata] = 1.;
                     std::cout << " 1 ";
                 }
                 else
                 {
-                    out_data[idata] = 1;
+                    out_data[idata] = 1.;
                     std::cout << " 1 ";
                 }
             }
@@ -1224,8 +1185,6 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
         // Deep learning. Take about 30-60 minutes
         if (access( "/tmp/fann.net", F_OK ) == -1)
         {
-
-
             // One input for each pixel.
             const unsigned int num_input = Ocr::SIZE*Ocr::SIZE;
             // One ouput for each possible char.
@@ -1234,21 +1193,18 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
             const unsigned int num_layers = 6;
             // Number of neurons for each layer is usually between number of input and number on output.
             const unsigned int num_neurons_hidden = std::max(num_input, num_output);
-            const float desired_error = (const float) 0.001;
+            const float desired_error = (const float) 0.0001;
             const unsigned int max_epochs = 500;
             // To see progression. It's take time...
             const unsigned int epochs_between_reports = 1;
 
-            std::ofstream file;
-            // Write in /tmp/xor.data all database of example.
-            // TODO: MUST be replace by the memory stream.
-            file.open("/tmp/xor.data");
-
-            // First line of the file.
-            file << num_output << " " << num_input << " " << num_output << std::endl;
-            // Then, the current char :
-            //     - For each pixel : -1 if blank, 1 if not blank.
-            //     - For each possible char : -1 if not the current char, 1 if it is the current char.
+//          First possibility: fixed internal layer.
+            sal_uInt32 layers[num_layers] = {num_input, /*num_neurons_hidden, num_neurons_hidden, */num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_output};
+            AbstractNeuralNetwork * ann = AbstractNeuralNetwork::CreateFactory(num_layers, layers);
+            ann->SetActivationFunction(AbstractNeuralNetwork::ActivationFunction::SIGMOID);
+            ann->SetTrainingAlgorithm(AbstractNeuralNetwork::TrainingAlgorithm::INCREMENTAL);
+            ann->SetLearningRate(0.07);
+            ann->InitTraining(num_output);
 
             long i = 0;
             sal_UCS4 sChar = xFontCharMap->GetFirstChar();
@@ -1299,21 +1255,21 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
                 o2.CropBitmap();
                 o2.ScaleBitmap(Ocr::SIZE, Ocr::SIZE);
                 // Write the draw of the current char to the file.
-                o2.ToFile(file);
+                o2.ToFann(ann->GetInput(i));
 
                 // Write that the current char is the only one good.
+                fann_type *output = ann->GetOutput(i);
                 for (long j = 0; j < i; j++)
                 {
-                    file << "0 ";
+                    output[j] = 0;
                 }
 
-                file << "1 ";
+                output[i] = 1;
 
                 for (long j = i + 1; j < num_output; j++)
                 {
-                    file << "0 ";
+                    output[j] = 0;
                 }
-                file << std::endl;
 
                 sChar = xFontCharMap->GetNextChar(sChar);
                 i++;
@@ -1322,19 +1278,10 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
                     break;
             }
 
-            file.close();
             // Creating the database of example done.
             std::cout << "DONE" << std::endl;
 
-
-//          First possibility: fixed internal layer.
-            struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_output); // TODO
-            // Default function. Usually works well.
-            fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
-            fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
-            fann_set_training_algorithm(ann, FANN_TRAIN_INCREMENTAL);
-            fann_set_learning_rate(ann, 0.2);
-            fann_train_on_file(ann, "/tmp/xor.data", max_epochs, epochs_between_reports, desired_error);
+            ann->Train(max_epochs, desired_error);
 
 //          Second possibility: none predictive internal layer.
 //          Can't find convergence for Total error:900,0000. Start at iteration around 370.
@@ -1345,41 +1292,41 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
             // fann_set_cascade_max_cand_epochs(ann, std::max(2U*num_input, 150U));
             // fann_set_cascade_min_out_epochs(ann, std::max(num_input/5U, 150U/2));
             // fann_set_cascade_min_cand_epochs(ann, std::max(num_input/5U, 150U/2));
-            // fann_set_cascade_output_change_fraction(ann, 0.15);
-            // fann_set_cascade_candidate_change_fraction(ann, 0.15);
-            // fann_set_cascade_output_stagnation_epochs(ann, 5);
-            // fann_set_cascade_candidate_stagnation_epochs(ann, 5);
-            // fann_set_cascade_weight_multiplier(ann, 0.2);
+            fann_set_cascade_output_change_fraction(ann, 0.001);
+            fann_set_cascade_candidate_change_fraction(ann, 0.001);
+            fann_set_cascade_output_stagnation_epochs(ann, 3);
+            fann_set_cascade_candidate_stagnation_epochs(ann, 3);
+            fann_set_cascade_weight_multiplier(ann, 0.01);
+            fann_set_cascade_candidate_limit(ann, 1000000000.);
             fann_cascadetrain_on_file(ann, "/tmp/xor.data", 100000, epochs_between_reports, desired_error);
             */
 
             // Save the result. Huge !!!
-            fann_save(ann, "/tmp/fann.net");
-
-            fann_destroy(ann);
+            ann->Save("/tmp/fann.net");
+            delete ann;
         }
 
         fann_type *calc_out;
         fann_type input[Ocr::SIZE*Ocr::SIZE];
 
         std::cout << "Starting loading fann" << std::endl;
-        struct fann *ann = fann_create_from_file("/tmp/fann.net");
+        AbstractNeuralNetwork * ann = AbstractNeuralNetwork::CreateFactory("/tmp/fann.net");
 
         o.ToFann(&input[0]);
         std::cout << "Starting finding best result" << std::endl;
-        calc_out = fann_run(ann, input);
+        calc_out = ann->Run(input);
         std::cout << "End of fann" << std::endl;
 
         std::multimap<float, sal_UCS4> sorted_results;
-        std::cout << fann_get_num_output(ann) << std::endl;
-        for (long i = 0; i < fann_get_num_output(ann); i++)
+        std::cout << ann->GetNumOutput() << std::endl;
+        for (long i = 0; i < ann->GetNumOutput(); i++)
         {
             // -1.-x: the minimum will be at end.
             sorted_results.insert(std::pair<float, sal_UCS4>(-1.-calc_out[i], i));
             std::cout << static_cast<char>(xFontCharMap->GetCharFromIndex(i)) << " : " << calc_out[i] << " " << std::endl;
         }
 
-        fann_destroy(ann);
+        delete ann;
 
         // TODO : sort the output and write the better char at first.
         for (auto it = sorted_results.begin(); it != sorted_results.end(); ++it)
diff --git a/cui/source/factory/neuralnetwork.cxx b/cui/source/factory/neuralnetwork.cxx
new file mode 100644
index 000000000000..5651b80b3ab8
--- /dev/null
+++ b/cui/source/factory/neuralnetwork.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <neuralnetwork.hxx>
+
+#include "neuralnetworkfann.hxx"
+
+AbstractNeuralNetwork * AbstractNeuralNetwork::CreateFactory(sal_uInt32 nLayers, const sal_uInt32* nLayer)
+{
+    return new NeuralNetworkFann(nLayers, nLayer);
+}
+
+AbstractNeuralNetwork * AbstractNeuralNetwork::CreateFactory(const OUString& file)
+{
+    return new NeuralNetworkFann(file);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/factory/neuralnetworkfann.cxx b/cui/source/factory/neuralnetworkfann.cxx
new file mode 100644
index 000000000000..e622916c1ccf
--- /dev/null
+++ b/cui/source/factory/neuralnetworkfann.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "neuralnetworkfann.hxx"
+
+NeuralNetworkFann::NeuralNetworkFann(sal_uInt32 nLayers, const sal_uInt32* nLayer) :
+    ann(fann_create_standard_array(nLayers, nLayer), fann_destroy),
+    data(nullptr, fann_destroy_train)
+{
+}
+
+NeuralNetworkFann::NeuralNetworkFann(const OUString& file) :
+    ann(fann_create_from_file(OUStringToOString(file, RTL_TEXTENCODING_ASCII_US).pData->buffer), fann_destroy),
+    data(nullptr, fann_destroy_train)
+{
+}
+
+void NeuralNetworkFann::SetActivationFunction(ActivationFunction function)
+{
+    fann_activationfunc_enum func;
+
+    switch (function)
+    {
+        case ActivationFunction::SIGMOID:
+        {
+            func = FANN_SIGMOID_SYMMETRIC;
+            break;
+        }
+        default:
+        {
+            return;
+        }
+    }
+    fann_set_activation_function_hidden(ann.get(), func);
+    fann_set_activation_function_output(ann.get(), func);
+}
+
+void NeuralNetworkFann::SetTrainingAlgorithm(TrainingAlgorithm algorithm)
+{
+    fann_train_enum algo;
+
+    switch (algorithm)
+    {
+        case TrainingAlgorithm::INCREMENTAL:
+        {
+            algo = FANN_TRAIN_INCREMENTAL;
+            break;
+        }
+        default:
+        {
+            return;
+        }
+    }
+    fann_set_training_algorithm(ann.get(), algo);
+}
+
+void NeuralNetworkFann::SetLearningRate(float rate)
+{
+   fann_set_learning_rate(ann.get(), rate);
+}
+
+#include <iostream>
+
+void NeuralNetworkFann::InitTraining(sal_uInt32 nExamples)
+{
+    data.reset(fann_create_train(nExamples, fann_get_num_input(ann.get()), fann_get_num_output(ann.get())));
+}
+
+void NeuralNetworkFann::Save(const OUString& file)
+{
+    OString o = OUStringToOString(file, RTL_TEXTENCODING_ASCII_US);
+    fann_save(ann.get(), o.pData->buffer);
+}
+
+sal_uInt32 NeuralNetworkFann::GetNumInput()
+{
+    return fann_get_num_input(ann.get());
+}
+
+float* NeuralNetworkFann::GetInput(sal_uInt32 nIeme)
+{
+    return &data->input[nIeme][0];
+}
+
+sal_uInt32 NeuralNetworkFann::GetNumOutput()
+{
+    return fann_get_num_output(ann.get());
+}
+
+float* NeuralNetworkFann::GetOutput(sal_uInt32 nIeme)
+{
+    return &data->output[nIeme][0];
+}
+
+float* NeuralNetworkFann::Run(float *data_input)
+{
+    return fann_run(ann.get(), data_input);
+}
+
+void NeuralNetworkFann::Train(sal_uInt32 nEpochs, float error)
+{
+    fann_train_on_data(ann.get(), data.get(), nEpochs, 1, error);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/factory/neuralnetworkfann.hxx b/cui/source/factory/neuralnetworkfann.hxx
new file mode 100644
index 000000000000..472f4640dde3
--- /dev/null
+++ b/cui/source/factory/neuralnetworkfann.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CUI_SOURCE_FACTORY_NEURALNETWORKFANN_HXX
+#define INCLUDED_CUI_SOURCE_FACTORY_NEURALNETWORKFANN_HXX
+
+#include "neuralnetwork.hxx"
+
+#include <fann.h>
+#include <memory>
+
+class NeuralNetworkFann : public AbstractNeuralNetwork
+{
+public:
+    NeuralNetworkFann(sal_uInt32 nLayers, const sal_uInt32* nLayer);
+    NeuralNetworkFann(const OUString& file);
+
+    void SetActivationFunction(ActivationFunction function) override;
+    void SetTrainingAlgorithm(TrainingAlgorithm algorithm) override;
+    void SetLearningRate(float rate) override;
+
+    void InitTraining(sal_uInt32 nExamples) override;
+    virtual sal_uInt32 GetNumInput() override;
+    float* GetInput(sal_uInt32 nIeme) override;
+    virtual sal_uInt32 GetNumOutput() override;
+    float* GetOutput(sal_uInt32 nIeme) override;
+
+    void Train(sal_uInt32 nEpochs, float error) override;
+    float* Run(float *data_input) override;
+    void Save(const OUString& file) override;
+
+    virtual ~NeuralNetworkFann(){}
+
+private:
+    std::unique_ptr<struct fann, void(*)(struct fann *)> ann;
+    std::unique_ptr<struct fann_train_data, void(*)(struct fann_train_data *)> data;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/factory/neuralnetworkinternal.cxx b/cui/source/factory/neuralnetworkinternal.cxx
new file mode 100644
index 000000000000..52597c57ca92
--- /dev/null
+++ b/cui/source/factory/neuralnetworkinternal.cxx
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index d999d2f316a8..1c30cd404ec5 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -51,7 +51,6 @@ public:
     void ReadBitmap();
     void CropBitmap();
     void ScaleBitmap(long width, long height);
-    void ToFile(std::ofstream &file);
     void ToFann(fann_type *out_data);
 
     static const int SIZE = 20;
diff --git a/cui/source/inc/neuralnetwork.hxx b/cui/source/inc/neuralnetwork.hxx
new file mode 100644
index 000000000000..045909214de9
--- /dev/null
+++ b/cui/source/inc/neuralnetwork.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CUI_SOURCE_FACTORY_NEURALNETWORK_HXX
+#define INCLUDED_CUI_SOURCE_FACTORY_NEURALNETWORK_HXX
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+class AbstractNeuralNetwork
+{
+public:
+    enum class ActivationFunction {
+        SIGMOID
+    };
+    enum class TrainingAlgorithm {
+        INCREMENTAL
+    };
+    static AbstractNeuralNetwork * CreateFactory(sal_uInt32 nLayers, const sal_uInt32* nLayer);
+    static AbstractNeuralNetwork * CreateFactory(const OUString& file);
+    virtual void SetActivationFunction(ActivationFunction function) = 0;
+    virtual void SetTrainingAlgorithm(TrainingAlgorithm algorithm) = 0;
+    virtual void SetLearningRate(float rate) = 0;
+
+    virtual void InitTraining(sal_uInt32 nExamples) = 0;
+    virtual sal_uInt32 GetNumInput() = 0;
+    virtual float* GetInput(sal_uInt32 nIeme) = 0;
+    virtual sal_uInt32 GetNumOutput() = 0;
+    virtual float* GetOutput(sal_uInt32 nIeme) = 0;
+
+    virtual void Train(sal_uInt32 nEpochs, float error) = 0;
+    virtual float* Run(float *data_input) = 0;
+    virtual void Save(const OUString& file) = 0;
+
+    virtual ~AbstractNeuralNetwork(){}
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit b421a9e3183fd6ee8901f0f42787039499c3e201
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:09:00 2018 +0100

    Show the result of the neural network in the UI.
    
    And reduce the number of char that can be recognized to start with a
    small subset.
    
    Change-Id: I41d0861f39ff4ba16c1fbebd892ce7f0e6f8043f

diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index b571fdeaf073..ecff74b6a6e0 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -184,8 +184,8 @@ void Ocr::CropBitmap()
 
     long right = j;
 
-    w_ = right-left+1;
-    h_ = bottom-top+1;
+    w_ = right - left + 1;
+    h_ = bottom - top + 1;
     tools::Rectangle r_src(left, top, right, bottom);
     tools::Rectangle r_dst(0, 0, w_, h_);
     Size s(w_, h_);
@@ -223,31 +223,34 @@ void Ocr::ToFile(std::ofstream &file)
     std::cout << "2r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
     for (long j = 0; j < h_; j++)
     {
-        std::cout << j << std::endl;
         for (long i = 0; i < w_; i++)
         {
-            std::cout << i << std::endl;
             if (i >= r->Width () || j >= r->Height())
             {
-                file << "-1 ";
+                file << "0 ";
+                std::cout << "-1 ";
             }
             else
             {
                 Color c = r->GetPixel(j, i);
                 if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
                 {
-                    file << "-1 ";
+                    file << "0 ";
+                    std::cout << "-1 ";
                 }
                 else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
                 {
-                    file << "1 ";
+                    file << " 1 ";
+                    std::cout << " 1 ";
                 }
                 else
                 {
-                    file << "1 ";
+                    file << " 1 ";
+                    std::cout << " 1 ";
                 }
             }
         }
+        std::cout << std::endl;
     }
     file << std::endl;
 }
@@ -266,7 +269,7 @@ void Ocr::ToFann(fann_type *out_data)
         {
             if (i >= r->Width () || j >= r->Height())
             {
-                out_data[idata] = -1;
+                out_data[idata] = 0;
                 std::cout << "-1 ";
             }
             else
@@ -274,22 +277,23 @@ void Ocr::ToFann(fann_type *out_data)
                 Color c = r->GetPixel(j, i);
                 if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
                 {
-                    out_data[idata] = -1;
+                    out_data[idata] = 0;
                     std::cout << "-1 ";
                 }
                 else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
                 {
                     out_data[idata] = 1;
-                    std::cout << "1 ";
+                    std::cout << " 1 ";
                 }
                 else
                 {
                     out_data[idata] = 1;
-                    std::cout << "1 ";
+                    std::cout << " 1 ";
                 }
             }
             idata++;
         }
+        std::cout << std::endl;
     }
     std::cout << std::endl;
 }
@@ -1213,33 +1217,28 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
         o.ScaleBitmap(Ocr::SIZE, Ocr::SIZE);
 
         m_pSearchSet->ClearPreviousData();
+        toggleSearchView(true);
 
+        FontCharMapRef xFontCharMap(new FontCharMap());
+        m_pSearchSet->GetFontCharMap(xFontCharMap);
         // Deep learning. Take about 30-60 minutes
         if (access( "/tmp/fann.net", F_OK ) == -1)
         {
-            FontCharMapRef xFontCharMap(new FontCharMap());
-            m_pSearchSet->GetFontCharMap(xFontCharMap);
 
 
             // One input for each pixel.
             const unsigned int num_input = Ocr::SIZE*Ocr::SIZE;
             // One ouput for each possible char.
-            const unsigned int num_output = xFontCharMap->GetCharCount()-1;
-            // 4 layers (one input, one output and two is recommended for OCR).
-            const unsigned int num_layers = 4;
+            const unsigned int num_output = 2*16/*xFontCharMap->GetCharCount()-1*/;
+            // 6 layers (one input, one output and the others).
+            const unsigned int num_layers = 6;
             // Number of neurons for each layer is usually between number of input and number on output.
             const unsigned int num_neurons_hidden = std::max(num_input, num_output);
             const float desired_error = (const float) 0.001;
-            const unsigned int max_epochs = 500000;
+            const unsigned int max_epochs = 500;
             // To see progression. It's take time...
             const unsigned int epochs_between_reports = 1;
 
-            struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_neurons_hidden, num_output);
-
-            // Default function. Usually works well.
-            fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
-            fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
-
             std::ofstream file;
             // Write in /tmp/xor.data all database of example.
             // TODO: MUST be replace by the memory stream.
@@ -1305,20 +1304,22 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
                 // Write that the current char is the only one good.
                 for (long j = 0; j < i; j++)
                 {
-                    file << "-1 ";
+                    file << "0 ";
                 }
 
                 file << "1 ";
 
                 for (long j = i + 1; j < num_output; j++)
                 {
-                    file << "-1 ";
+                    file << "0 ";
                 }
                 file << std::endl;
 
                 sChar = xFontCharMap->GetNextChar(sChar);
-                m_pSearchSet->AppendCharToList(sChar);
                 i++;
+
+                if (i == num_output)
+                    break;
             }
 
             file.close();
@@ -1326,9 +1327,32 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
             std::cout << "DONE" << std::endl;
 
 
-            // Training the network. Take age !!!
+//          First possibility: fixed internal layer.
+            struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_neurons_hidden, num_output); // TODO
+            // Default function. Usually works well.
+            fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
+            fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
+            fann_set_training_algorithm(ann, FANN_TRAIN_INCREMENTAL);
+            fann_set_learning_rate(ann, 0.2);
             fann_train_on_file(ann, "/tmp/xor.data", max_epochs, epochs_between_reports, desired_error);
 
+//          Second possibility: none predictive internal layer.
+//          Can't find convergence for Total error:900,0000. Start at iteration around 370.
+            /*
+            struct fann *ann = fann_create_shortcut(2, num_input, num_output);
+            // Useful???
+            // fann_set_cascade_max_out_epochs(ann, std::max(2U*num_input, 150U));
+            // fann_set_cascade_max_cand_epochs(ann, std::max(2U*num_input, 150U));
+            // fann_set_cascade_min_out_epochs(ann, std::max(num_input/5U, 150U/2));
+            // fann_set_cascade_min_cand_epochs(ann, std::max(num_input/5U, 150U/2));
+            // fann_set_cascade_output_change_fraction(ann, 0.15);
+            // fann_set_cascade_candidate_change_fraction(ann, 0.15);
+            // fann_set_cascade_output_stagnation_epochs(ann, 5);
+            // fann_set_cascade_candidate_stagnation_epochs(ann, 5);
+            // fann_set_cascade_weight_multiplier(ann, 0.2);
+            fann_cascadetrain_on_file(ann, "/tmp/xor.data", 100000, epochs_between_reports, desired_error);
+            */
+
             // Save the result. Huge !!!
             fann_save(ann, "/tmp/fann.net");
 
@@ -1346,13 +1370,28 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
         calc_out = fann_run(ann, input);
         std::cout << "End of fann" << std::endl;
 
-        for (long i = 0; i < 2294; i++)
-            std::cout << calc_out[i] << " ";
+        std::multimap<float, sal_UCS4> sorted_results;
+        std::cout << fann_get_num_output(ann) << std::endl;
+        for (long i = 0; i < fann_get_num_output(ann); i++)
+        {
+            // -1.-x: the minimum will be at end.
+            sorted_results.insert(std::pair<float, sal_UCS4>(-1.-calc_out[i], i));
+            std::cout << static_cast<char>(xFontCharMap->GetCharFromIndex(i)) << " : " << calc_out[i] << " " << std::endl;
+        }
 
         fann_destroy(ann);
 
         // TODO : sort the output and write the better char at first.
-//        m_pSearchSet->AppendCharToList(sChar);
+        for (auto it = sorted_results.begin(); it != sorted_results.end(); ++it)
+        {
+        /*
+            if ((*it).first == -1)
+                break;
+                */
+            m_pSearchSet->AppendCharToList(xFontCharMap->GetCharFromIndex((*it).second));
+            std::cout << (*it).second << " ";
+        }
+        std::cout << std::endl;
         m_pSearchSet->Resize();
 
     }
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index 0e80d4002c1a..d999d2f316a8 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -54,7 +54,7 @@ public:
     void ToFile(std::ofstream &file);
     void ToFann(fann_type *out_data);
 
-    static const int SIZE = 15;
+    static const int SIZE = 20;
 
 private:
     Bitmap m_bitmap;
commit 85188af850f4e7ea252df6202215c328b63bb115
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:05:50 2018 +0100

    Recognize char by using lib fann network
    
    Read all char, train the neural network with these char then apply
    the draw to get recognition.
    
    Change-Id: Ie48a173703f599b054f0c6edfa38acfdfb25ec71

diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index 8bf4d7166801..b571fdeaf073 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -52,6 +52,9 @@
 #include <unicode/uchar.h>
 #include <unicode/utypes.h>
 
+#include <fann.h>
+#include <floatfann.h>
+
 using namespace css;
 
 Ocr::Ocr(const Bitmap& b, long w, long h) : m_bitmap(b), w_(w), h_(h), data()
@@ -67,18 +70,25 @@ void Ocr::ReadBitmap()
     {
         for (long i = 0; i < w_; i++)
         {
-            Color c = r->GetPixel (j, i);
-            if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
-            {
-                data[j*w_+i] = 1;
-            }
-            else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+            if (i >= r->Width () || j >= r->Height())
             {
                 data[j*w_+i] = 0;
             }
             else
             {
-                data[j*w_+i] = 2;
+                Color c = r->GetPixel (j, i);
+                if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+                {
+                    data[j*w_+i] = 1;
+                }
+                else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+                {
+                    data[j*w_+i] = 0;
+                }
+                else
+                {
+                    data[j*w_+i] = 2;
+                }
             }
         }
     }
@@ -200,6 +210,88 @@ void Ocr::ScaleBitmap(long width, long height)
     }
 
     m_bitmap.Scale(new_size, new_size, BmpScaleFlag::Fast);
+
+    w_ = width;
+    h_ = height;
+}
+
+void Ocr::ToFile(std::ofstream &file)
+{
+    BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
+
+    std::cout << "2r->Width () != w_" << r->Width () << " vs " << w_ << std::endl;
+    std::cout << "2r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
+    for (long j = 0; j < h_; j++)
+    {
+        std::cout << j << std::endl;
+        for (long i = 0; i < w_; i++)
+        {
+            std::cout << i << std::endl;
+            if (i >= r->Width () || j >= r->Height())
+            {
+                file << "-1 ";
+            }
+            else
+            {
+                Color c = r->GetPixel(j, i);
+                if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+                {
+                    file << "-1 ";
+                }
+                else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+                {
+                    file << "1 ";
+                }
+                else
+                {
+                    file << "1 ";
+                }
+            }
+        }
+    }
+    file << std::endl;
+}
+
+void Ocr::ToFann(fann_type *out_data)
+{
+    BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
+    long idata = 0;
+
+    std::cout << "3r->Width () != w_" << r->Width () << " vs " << w_ << std::endl;
+    std::cout << "3r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
+
+    for (long j = 0; j < h_; j++)
+    {
+        for (long i = 0; i < w_; i++)
+        {
+            if (i >= r->Width () || j >= r->Height())
+            {
+                out_data[idata] = -1;
+                std::cout << "-1 ";
+            }
+            else
+            {
+                Color c = r->GetPixel(j, i);
+                if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+                {
+                    out_data[idata] = -1;
+                    std::cout << "-1 ";
+                }
+                else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+                {
+                    out_data[idata] = 1;
+                    std::cout << "1 ";
+                }
+                else
+                {
+                    out_data[idata] = 1;
+                    std::cout << "1 ";
+                }
+            }
+            idata++;
+        }
+    }
+    std::cout << std::endl;
 }
 
 // class SvxCharacterMap =================================================
@@ -1095,6 +1187,8 @@ IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, Button*, void)
    EndDialog(RET_OK);
 }
 
+#include <iostream>
+
 IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
 {
     if (m_pDrawChk->IsChecked())
@@ -1120,57 +1214,145 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
 
         m_pSearchSet->ClearPreviousData();
 
-        sal_UCS4 *range = new sal_UCS4[2];
-        range[0] = 0;
-        range[1] = 1114111;
-        CmapResult rCR (true, range, 1);
-        FontCharMapRef xFontCharMap(new FontCharMap(rCR));
-        m_pSearchSet->GetFontCharMap(xFontCharMap);
-
-        sal_UCS4 sChar = xFontCharMap->GetFirstChar();
-        while(sChar != xFontCharMap->GetLastChar())
+        // Deep learning. Take about 30-60 minutes
+        if (access( "/tmp/fann.net", F_OK ) == -1)
         {
-            VirtualDevice od;
-            OUString aOUStr( &sChar, 1 );
-            Size s50(Ocr::SIZE, Ocr::SIZE);
-            od.SetOutputSize( s50 );
-            vcl::Font aFontBis(aFont);
-            aFontBis.SetFontHeight(Ocr::SIZE);
-            od.SetFont( aFontBis );
-            od.DrawText( p, aOUStr );
-            w = od.GetOutputWidthPixel ();
-            h = od.GetOutputHeightPixel ();
-
-            Size s2(w, h);
-            b = od.GetBitmap (p, s2);
-
-            BitmapReadAccess* r = b.AcquireReadAccess ();
-
-            for (long j = 0; j < h; j++)
+            FontCharMapRef xFontCharMap(new FontCharMap());
+            m_pSearchSet->GetFontCharMap(xFontCharMap);
+
+
+            // One input for each pixel.
+            const unsigned int num_input = Ocr::SIZE*Ocr::SIZE;
+            // One ouput for each possible char.
+            const unsigned int num_output = xFontCharMap->GetCharCount()-1;
+            // 4 layers (one input, one output and two is recommended for OCR).
+            const unsigned int num_layers = 4;
+            // Number of neurons for each layer is usually between number of input and number on output.
+            const unsigned int num_neurons_hidden = std::max(num_input, num_output);
+            const float desired_error = (const float) 0.001;
+            const unsigned int max_epochs = 500000;
+            // To see progression. It's take time...
+            const unsigned int epochs_between_reports = 1;
+
+            struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_neurons_hidden, num_output);
+
+            // Default function. Usually works well.
+            fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
+            fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
+
+            std::ofstream file;
+            // Write in /tmp/xor.data all database of example.
+            // TODO: MUST be replace by the memory stream.
+            file.open("/tmp/xor.data");
+
+            // First line of the file.
+            file << num_output << " " << num_input << " " << num_output << std::endl;
+            // Then, the current char :
+            //     - For each pixel : -1 if blank, 1 if not blank.
+            //     - For each possible char : -1 if not the current char, 1 if it is the current char.
+
+            long i = 0;
+            sal_UCS4 sChar = xFontCharMap->GetFirstChar();
+            while(sChar != xFontCharMap->GetLastChar())
             {
-                for (long i = 0; i < w; i++)
+                // Draw the current char.
+                VirtualDevice od;
+                OUString aOUStr( &sChar, 1 );
+                Size s50(Ocr::SIZE, Ocr::SIZE);
+                od.SetOutputSize( s50 );
+                vcl::Font aFontBis(aFont);
+                aFontBis.SetFontHeight(Ocr::SIZE);
+                od.SetFont( aFontBis );
+                od.DrawText( p, aOUStr );
+
+                w = od.GetOutputWidthPixel ();
+                h = od.GetOutputHeightPixel ();
+                Size s2(w, h);
+                Bitmap b2 = od.GetBitmap (p, s2);
+
+                BitmapReadAccess* r = b2.AcquireReadAccess ();
+
+                // Show every pixel of the current char.
+                for (long j = 0; j < h; j++)
                 {
-                    Color c = r->GetPixel(j, i);
-                    if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
-                    {
-                        std::cout << "1";
-                    }
-                    else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
-                    {
-                        std::cout << "0";
-                    }
-                    else
+                    for (long k = 0; k < w; k++)
                     {
-                        std::cout << "2";
+                        Color c = r->GetPixel(j, k);
+                        if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+                        {
+                            std::cout << "1";
+                        }
+                        else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+                        {
+                            std::cout << "0";
+                        }
+                        else
+                        {
+                            std::cout << "2";
+                        }
                     }
+                    std::cout << std::endl;
                 }
-                std::cout << std::endl;
+
+                // Resize the bitmap of the current char.
+                Ocr o2(b2, w, h);
+                o2.ReadBitmap();
+                o2.CropBitmap();
+                o2.ScaleBitmap(Ocr::SIZE, Ocr::SIZE);
+                // Write the draw of the current char to the file.
+                o2.ToFile(file);
+
+                // Write that the current char is the only one good.
+                for (long j = 0; j < i; j++)
+                {
+                    file << "-1 ";
+                }
+
+                file << "1 ";
+
+                for (long j = i + 1; j < num_output; j++)
+                {
+                    file << "-1 ";
+                }
+                file << std::endl;
+
+                sChar = xFontCharMap->GetNextChar(sChar);
+                m_pSearchSet->AppendCharToList(sChar);
+                i++;
             }
 
-            sChar = xFontCharMap->GetNextChar(sChar);
-            m_pSearchSet->AppendCharToList(sChar);
+            file.close();
+            // Creating the database of example done.
+            std::cout << "DONE" << std::endl;
+
+
+            // Training the network. Take age !!!
+            fann_train_on_file(ann, "/tmp/xor.data", max_epochs, epochs_between_reports, desired_error);
+
+            // Save the result. Huge !!!
+            fann_save(ann, "/tmp/fann.net");
+
+            fann_destroy(ann);
         }
-        m_pSearchSet->AppendCharToList(sChar);
+
+        fann_type *calc_out;
+        fann_type input[Ocr::SIZE*Ocr::SIZE];
+
+        std::cout << "Starting loading fann" << std::endl;
+        struct fann *ann = fann_create_from_file("/tmp/fann.net");
+
+        o.ToFann(&input[0]);
+        std::cout << "Starting finding best result" << std::endl;
+        calc_out = fann_run(ann, input);
+        std::cout << "End of fann" << std::endl;
+
+        for (long i = 0; i < 2294; i++)
+            std::cout << calc_out[i] << " ";
+
+        fann_destroy(ann);
+
+        // TODO : sort the output and write the better char at first.
+//        m_pSearchSet->AppendCharToList(sChar);
         m_pSearchSet->Resize();
 
     }
@@ -1530,7 +1712,6 @@ void DrawingAreaOcr::MouseMove( const MouseEvent &rMEvt )
 
     Invalidate();
     Update();
-    std::cout << static_cast<int>(state) << std::endl;
 }
 
 void DrawingAreaOcr::MouseButtonUp (const MouseEvent &rMEvt)
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index 10b7dc956c03..0e80d4002c1a 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -28,6 +28,10 @@
 #include <svx/charmap.hxx>
 #include <svx/searchcharmap.hxx>
 #include <sfx2/charwin.hxx>
+#include <iostream>
+#include <fstream>
+
+#include <floatfann.h>
 
 using namespace ::com::sun::star;
 class SubsetMap;
@@ -47,8 +51,10 @@ public:
     void ReadBitmap();
     void CropBitmap();
     void ScaleBitmap(long width, long height);
+    void ToFile(std::ofstream &file);
+    void ToFann(fann_type *out_data);
 
-    static const int SIZE = 25;
+    static const int SIZE = 15;
 
 private:
     Bitmap m_bitmap;
commit 63e2b57bb5ea4286e196b224fecc157c248d7c04
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:03:04 2018 +0100

    Add fann dependency
    
    Change-Id: I508ecd58abcd779219c4275d804ec8a268d0ccd8

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 30709792c010..9539ce05f31d 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -2548,6 +2548,21 @@ endef
 
 endif # ENABLE_GIO
 
+define gb_LinkTarget__use_fann
+$(call gb_LinkTarget_set_include,$(1),\
+       $$(INCLUDE) \
+       $(FANN_CFLAGS) \
+)
+
+$(call gb_LinkTarget_add_libs,$(1),$(FANN_LIBS))
+
+endef
+
+define gb_ExternalProject__use_fann
+$(call gb_ExternalProject_use_package,$(1),fann)
+endef
+
+
 ifeq ($(ENABLE_AVAHI),TRUE)
 
 define gb_LinkTarget__use_avahi
diff --git a/config_host.mk.in b/config_host.mk.in
index 0cc343cd351d..a46d6da90e24 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -197,6 +197,8 @@ export GIT_LINK_SRC=@GIT_LINK_SRC@
 export GIT_NEEDED_SUBMODULES=@GIT_NEEDED_SUBMODULES@
 export EPOXY_CFLAGS=$(gb_SPACE)@EPOXY_CFLAGS@
 export EPOXY_LIBS=$(gb_SPACE)@EPOXY_LIBS@
+export FANN_CFLAGS=$(gb_SPACE)@FANN_CFLAGS@
+export FANN_LIBS=$(gb_SPACE)@FANN_LIBS@
 export GLM_CFLAGS=$(gb_SPACE)@GLM_CFLAGS@
 export GPG_ERROR_CFLAGS=$(gb_SPACE)@GPG_ERROR_CFLAGS@
 export GPG_ERROR_LIBS=$(gb_SPACE)@GPG_ERROR_LIBS@
diff --git a/configure.ac b/configure.ac
index 7ef4a6c6a334..11ecf94d6658 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7736,6 +7736,12 @@ libo_CHECK_SYSTEM_MODULE([libstaroffice],[STAROFFICE],[libstaroffice-0.0])
 libo_PKG_VERSION([STAROFFICE], [libstaroffice-0.0], [0.0.4])
 
 dnl ===================================================================
+dnl Neuronal network fann
+dnl ===================================================================
+libo_CHECK_SYSTEM_MODULE([fann], [FANN], [fann >= 2.0])
+
+
+dnl ===================================================================
 dnl Check for system lcms2
 dnl ===================================================================
 if test "$with_system_lcms2" != "yes"; then
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index c6dc353f59b4..449a44ea22d3 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -66,6 +66,7 @@ $(eval $(call gb_Library_use_externals,cui,\
 	boost_headers \
 	$(call gb_Helper_optional,OPENCL,\
 		clew) \
+    fann \
     icuuc \
     icu_headers \
 ))
diff --git a/download.lst b/download.lst
index f574617147c9..ca2bf915d38b 100644
--- a/download.lst
+++ b/download.lst
@@ -44,6 +44,8 @@ export ETONYEK_VERSION_MICRO := 7
 export ETONYEK_TARBALL := libetonyek-0.1.$(ETONYEK_VERSION_MICRO).tar.xz
 export EXPAT_SHA256SUM := d9dc32efba7e74f788fcc4f212a43216fc37cf5f23f4c2339664d473353aedf6
 export EXPAT_TARBALL := expat-2.2.5.tar.bz2
+export FANN_SHA256SUM := 434b85fce60701c4e0066c442d60110d8e649f278e4edb814f0c0e7a1e0929fd
+export FANN_TARBALL := FANN-2.2.0-Source.zip
 export FIREBIRD_SHA256SUM := 6994be3555e23226630c587444be19d309b25b0fcf1f87df3b4e3f88943e5860
 export FIREBIRD_TARBALL := Firebird-3.0.0.32483-0.tar.bz2
 export FONTCONFIG_SHA256SUM := cf0c30807d08f6a28ab46c61b8dbd55c97d2f292cf88f3a07d3384687f31f017
commit 99d95dd1bfbe248086850660f000d5b32c545722
Author: Vincent Le Garrec <legarrec.vincent at gmail.com>
Date:   Tue Jan 16 22:00:29 2018 +0100

    Read the draw and resize it
    
    Convert a char to an image.
    VirtualDevice od must be convert to VclPtr<VirtualDevice>.
    
    Change-Id: I2b53c6f2bde12109c56ce1b4d139af6ddc901718

diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index 7ca01ffba5b1..8bf4d7166801 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -32,6 +32,8 @@
 #include <vcl/settings.hxx>
 #include <vcl/builderfactory.hxx>
 #include <vcl/fontcharmap.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/bitmapaccess.hxx>
 #include <svl/stritem.hxx>
 #include <officecfg/Office/Common.hxx>
 #include <comphelper/processfactory.hxx>
@@ -52,6 +54,154 @@
 
 using namespace css;
 
+Ocr::Ocr(const Bitmap& b, long w, long h) : m_bitmap(b), w_(w), h_(h), data()
+{
+}
+
+void Ocr::ReadBitmap()
+{
+    BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
+    data.resize(h_*w_);
+
+    for (long j = 0; j < h_; j++)
+    {
+        for (long i = 0; i < w_; i++)
+        {
+            Color c = r->GetPixel (j, i);
+            if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+            {
+                data[j*w_+i] = 1;
+            }
+            else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+            {
+                data[j*w_+i] = 0;
+            }
+            else
+            {
+                data[j*w_+i] = 2;
+            }
+        }
+    }
+}
+
+void Ocr::CropBitmap()
+{
+    // Remove useless bottom row.
+    long j;
+    for (j = h_ - 1; j >= 0; j--)
+    {
+        long i;
+        for (i = 0; i < w_; i++)
+        {
+            if (data[j*w_+i] != 0)
+            {
+                break;
+            }
+        }
+        if (i != w_)
+        {
+            break;
+        }
+    }
+
+    // All image is empty.
+    if (j == -1)
+    {
+        w_ = 1;
+        h_ = 1;
+        tools::Rectangle r(0, 0, 1, 1);
+        m_bitmap.Crop(r);
+        data.resize(1);
+        return;
+    }
+
+    long bottom = j;
+
+    // Remove useless top row.
+    for (j = 0; j < h_; j++)
+    {
+        long i;
+        for (i = 0; i < w_; i++)
+        {
+            if (data[j*w_+i] != 0)
+            {
+                break;
+            }
+        }
+        if (i != w_)
+        {
+            break;
+        }
+    }
+
+    long top = j;
+
+    // Remove useless left col.
+    for (j = 0; j < w_; j++)
+    {
+        long i;
+        for (i = 0; i < h_; i++)
+        {
+            if (data[i*w_+j] != 0)
+            {
+                break;
+            }
+        }
+        if (i != h_)
+        {
+            break;
+        }
+    }
+
+    long left = j;
+
+    // Remove useless right col.
+    for (j = w_-1; j >= 0; j--)
+    {
+        long i;
+        for (i = 0; i < h_; i++)
+        {
+            if (data[i*w_+j] != 0)
+            {
+                break;
+            }
+        }
+        if (i != h_)
+        {
+            break;
+        }
+    }
+
+    long right = j;
+
+    w_ = right-left+1;
+    h_ = bottom-top+1;
+    tools::Rectangle r_src(left, top, right, bottom);
+    tools::Rectangle r_dst(0, 0, w_, h_);
+    Size s(w_, h_);
+    Bitmap b_dst(s, 1);
+    b_dst.CopyPixel(r_dst, r_src, &m_bitmap);
+    m_bitmap = b_dst;
+}
+
+void Ocr::ScaleBitmap(long width, long height)
+{
+    double new_ratio = (double)width / height;
+    double ratio = (double)w_ / h_;
+
+    double new_size;
+    if (ratio > new_ratio)
+    {
+        new_size = (double)width / w_;
+    }
+    else
+    {
+        new_size = (double)height / h_;
+    }
+
+    m_bitmap.Scale(new_size, new_size, BmpScaleFlag::Fast);
+}
+
 // class SvxCharacterMap =================================================
 
 SvxCharacterMap::SvxCharacterMap( vcl::Window* pParent, const SfxItemSet* pSet, bool bInsert )
@@ -956,6 +1106,73 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
     {
         m_pDrawingArea->Hide();
         m_pShowChar->Show();
+
+        Point p(0, 0);
+        long w = m_pDrawingArea->GetOutputWidthPixel ();
+        long h = m_pDrawingArea->GetOutputHeightPixel ();
+        Size s(w, h);
+        Bitmap b = m_pDrawingArea->GetBitmap (p, s);
+
+        Ocr o(b, w, h);
+        o.ReadBitmap();
+        o.CropBitmap();
+        o.ScaleBitmap(Ocr::SIZE, Ocr::SIZE);
+
+        m_pSearchSet->ClearPreviousData();
+
+        sal_UCS4 *range = new sal_UCS4[2];
+        range[0] = 0;
+        range[1] = 1114111;
+        CmapResult rCR (true, range, 1);
+        FontCharMapRef xFontCharMap(new FontCharMap(rCR));
+        m_pSearchSet->GetFontCharMap(xFontCharMap);
+
+        sal_UCS4 sChar = xFontCharMap->GetFirstChar();
+        while(sChar != xFontCharMap->GetLastChar())
+        {
+            VirtualDevice od;
+            OUString aOUStr( &sChar, 1 );
+            Size s50(Ocr::SIZE, Ocr::SIZE);
+            od.SetOutputSize( s50 );
+            vcl::Font aFontBis(aFont);
+            aFontBis.SetFontHeight(Ocr::SIZE);
+            od.SetFont( aFontBis );
+            od.DrawText( p, aOUStr );
+            w = od.GetOutputWidthPixel ();
+            h = od.GetOutputHeightPixel ();
+
+            Size s2(w, h);
+            b = od.GetBitmap (p, s2);
+
+            BitmapReadAccess* r = b.AcquireReadAccess ();
+
+            for (long j = 0; j < h; j++)
+            {
+                for (long i = 0; i < w; i++)
+                {
+                    Color c = r->GetPixel(j, i);
+                    if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+                    {
+                        std::cout << "1";
+                    }
+                    else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+                    {
+                        std::cout << "0";
+                    }
+                    else
+                    {
+                        std::cout << "2";
+                    }
+                }
+                std::cout << std::endl;
+            }
+
+            sChar = xFontCharMap->GetNextChar(sChar);
+            m_pSearchSet->AppendCharToList(sChar);
+        }
+        m_pSearchSet->AppendCharToList(sChar);
+        m_pSearchSet->Resize();
+
     }
 }
 
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index 752678e1ad91..10b7dc956c03 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -39,6 +39,24 @@ namespace svx
     struct SvxShowCharSetItem;
 }
 
+class Ocr
+{
+public:
+    Ocr(const Bitmap& b, long w, long h);
+
+    void ReadBitmap();
+    void CropBitmap();
+    void ScaleBitmap(long width, long height);
+
+    static const int SIZE = 25;
+
+private:
+    Bitmap m_bitmap;
+    long w_;
+    long h_;
+    std::vector<char> data;
+};
+
 class DrawingAreaOcr : public Control
 {
 public:


More information about the Libreoffice-commits mailing list