Table Of Contents

Previous topic

2. First steps with subversion (svn)

Next topic

4. Managing a graphical interface with Qt

Download

3. Reading an image from a file

spot

This exercize describes in a step-by-step fashion how to write a program reading an image from a file.

You should strive for systematically using all the tools you’ve learned so far:

  • CMT
  • svn

Do not forget to also systematically test (many times) and after each step the behaviour of your program. Do not hesitate to decompose a step into smaller intermediate ones.

This section should allow you to remember the basics of object oriented programming and of C++ before tackling the DrawQt project. All the steps should be rigorously followed, if, however, some detail is escaping you, do not hesitate to call for help.

Note

Concerning the compilation errors, remember to head toward the page listing the main and usual issues.


3.1. Step 1: environment configuration (20 min)

This first step -a variant of hello world- installs, tests and validates the projects within your development environment. In our case, the project Image is managed with CMT and subversion.

We’ll start with configuring our svn environment:

$> cd ~/Project
$> svn mkdir https://svn.lal.in2p3.fr/projects/Etudiants/ens<n>/Image -m "Added Image project"
$> svn mkdir https://svn.lal.in2p3.fr/projects/Etudiants/ens<n>/Image/trunk -m "Added Image project"
$> svn mkdir https://svn.lal.in2p3.fr/projects/Etudiants/ens<n>/Image/branches -m "Added Image project"
$> svn mkdir https://svn.lal.in2p3.fr/projects/Etudiants/ens<n>/Image/tags -m "Added Image project"
             -m "Added Image project"

We’ll need the Interfaces package to access and use the system libraries. Fetch it from the svn repository called Enseignement:

$> cd ~/Project
$> svn export https://svn.lal.in2p3.fr/projects/Enseignement/LAL-Info/tags/head/Interfaces \
              Interfaces

Now, create your new CMT package:

$> cmt create Image v1
$> svn co https://svn.lal.in2p3.fr/projects/Etudiants/ens<n>/Image/trunk Image
$> cd Image

Edit the requirements file like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package Image

# for basics system libraries
use Platform v1r* ${HOME}/Project/Interfaces

# to build an application readImage.exe
application readImage readImage.cpp

# define an action 'read' to execute readImage.exe
action read $(bin)/readImage.exe

Then, edit the file src/readImage.cpp along these lines:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * @file   readImage.cpp
 * @author LAL ens <ens@lal.in2p3.fr>
 * @date   February 2006
 * 
 * @brief  Read an image from a file image.txt
 * 
 * 
 */
#include <iostream>

int main (int argc, char **argv)
{
  // print an informative message on the screen
  // ...

  return (0);
}

Now we are left with building and running/testing the application:

$> cmt make
$> cmt read

At this point, you can commit and save your first version of the program in svn, after having removed the not-important files (history-wise, i.e. the files you do not wish to track in svn):

$> rm -r ../Darwin
$> rm ../cmt/Makefile ../cmt/*.csh ../cmt/*.sh
$> cd ..

Note

You can also instruct svn to ignore certain files or directories by editing the svn configuration file ~/.subversion/config along the section [miscellany] :

  • uncomment the global-ignores variable (has to be defined on one line)
  • add in it definition all patterns describing the files you won’t track in svn; i.e. those generated by CMT:
    • Makefile, setup.* and cleanup.*, the Darwin directory

Finally, add the current tree to svn, save and synchronize your workarea and the repository:

$> svn add cmt src
$> svn commit -m "Added Image package"
$> svn update

You can check the repository is up-to-date using the by now well known svn status command in the correct directory.

_images/validate-step.jpg

Validate this step


3.2. Step 2: Accessing a data file (20 min)

Create a directory to hold the input data:

$> mkdir ./data

Retrieve the Image file with Ctrl-click (and then Save the link or Enregistrer la cible or Telecharger le fichier...). Save the file under the ../data directory.

The structure and format of this file is described over there.

Commit the data file in svn:

$> svn add data
$> svn commit -m "adding data directory" ./data

Here are the snippets of code which deal with opening the data file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
...
#include <fstream>
...

const std::string filename = "../data/image.txt";
  
std::ifstream f;
f.open(filename.c_str());

if (!f.is_open()) {
  std::cout << "error. file [" << filename << "] could not be found."
            << std::endl;
  f.close();
  return (0);
 }

std::cout << "file: [" << filename << "] open." << std::endl;
f.close();
...
return (0);

More detailed informations about input/output functions can be found there.

Now, we can build and test our application like so:

$> cmt make
$> cmt read

Eventually, we commit and save into svn.

Note

remember we work in the src directory...

_images/validate-step.jpg

Validate this step


3.3. Step 3: reading the data file token-by-token (30 min)

The following snippet of code shows how to loop over the content of a file, simply reading it word by word:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <fstream>
#include <string>
   
int main (int argc, char **argv)
{
  std::cout << "Application readImage." << std::endl;
     
  const std::string filename = "../data/image.txt";
  std::ifstream f;
  f.open( filename.c_str() );

  if (!f.is_open()) {
    std::cout << "error. file [" << filename << "] could not be found."
              << std::endl;
    f.close();
    return (0);
  }
  
  std::string word;
  std::cout << "file: [" << filename << "] open." << std::endl;
  
  // put the word-by-word reading loop here and 
  // print out the word which has been read
  
  while (!f.eof()) {
    //...
  }
   
     
  return (0);
}
   

Warning

The reading function will only return a word back to you as long as the end of the file is not reached. Ergo, you shouldn’t forget to test for that edge case.

Build this application, test it and commit your changes in svn once everything is behaving correctly.

_images/validate-step.jpg

Validate this step


3.4. Step 4: creating a class named Image (15 min)

Before going further in the implementation of our reading application, we’ll create a C++ class Image. This class will allow us to properly isolate the data members from the operations associated with or applied on our images. This is one of the pillars of object-oriented programming.

A presentation on C++ classes is available here.

In order to cleanly separate the structure of the class itself from its implementation, we’ll create 2 files:

  • the header file include/image.h (create the include directory):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/** 
 * @file  image.h
 * @brief File holding the description of the class Image
 * @author LAL ens <ens@lal.in2p3.fr>
 * @date   February 2009
 */
          
#ifndef PROJECT_IMAGE_H
#define PROJECT_IMAGE_H 1
          
/**
 * @brief
 */
class <Enter the name of your class>
{
public:
  /** @brief ...
   */
  Image();

  /** ...
   */
  ~Image();  
};

#endif // !PROJECT_IMAGE_H
  • the implementation file src/image.cpp:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/** 
 * @file  image.cpp
 * @brief ...
 * @date   February 2009
 */

#include "image.h"

Image::Image()
{
}

Image::~Image()
{
}

You need to modify the cmt/requirements file for the build system to be aware of these new files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package Image

# add the 'include' directory to the list of directories
# the compiler should know about
include_dirs $(IMAGEROOT)/include

# for basics system libraries
use Platform v1r* ${HOME}/Project/Interfaces

# to build an application readImage.exe
application readImage readImage.cpp image.cpp

# define an action 'read' to execute readImage.exe
action read $(bin)/readImage.exe

Rebuild everything, test and commit in svn.

_images/validate-step.jpg

Validate this step


3.5. Step 5: isolate the reading of a file in a dedicated method (1h)

In this step, we’ll isolate the reading proper of a file into a method of the class Image. (Don’t forget to add all #include if necessary) This method will later on be integrated and leveraged during the hands-on session on DrawQt.

You shall add the method ReadFile() with the following signature:

bool ReadFile(const std::string& filename)

to your new class Image; the method ReadFile() will return a boolean in order to indicate whether the file scan ran into an error or not.

When this work is completed, the main() function of your program readImage should only contain:

  • the instantiation of an object of the class Image
  • the call to the method ReadFile()

Note that the error handling is not mandatory yet (this will be for a later step.)

Build, test and commit in svn.

_images/validate-step.jpg

Validate this step


3.6. Step 6: interpreting the data from the image file (1h)

Using the informations about the image file format documentation, we’ll re-implement the reading of the file. Previously, in step 3 we were reading the input file ‘word by word’ (or ‘token by token’.)

But now that the format of the image file and its grammar is known, we build upon it to greatly simplify the reading of such files.

  1. there won’t be any need for the while loop anymore
  2. the loop will be replaced by a serie of:
read a word
if not an expected word:
   return an error
read next word
  1. memorize the values of HEIGHT and WIDTH in new data member variables called, respectively, m_nX and m_nY
  2. iterate through the content of pixels of this image and display on screen the values, in a line-by-line fashion in a new method Image::Print().
_images/validate-step.jpg

Validate this step

Note

To read next token into a word you have already seen the f >> my_word method; if you want to read the next token into an int, you could also use the same method f >> my_int


3.7. Step 7: data storage (45 min)

  1. store the data in a one-dimension private array you’d call m_data. you should use the std::vector class.
  2. then, change to a 2-D array (use a std::vector of std::vector)
_images/validate-step.jpg

Validate this step


3.8. Step 8: documenting the package Image (45 min)

This exercize will ask you to go back to your Image package and comment it as best as possible with the tool Doxygen.

We will now improve our application with some documentation generated with doxygen. In order to ease the process of documenting the code, we’ll first add a few rules to CMT so it can steer doxygen.

Open the cmt/requirements file and add the following lines at the end:

1
2
# define an action to generate the documentation
document doxygen doc -group=documentation TO=../doc

Now, we have to tell CMT that it has to read is requirement file :

$> cmt config

We’ll also have to create a doc directory to store this documentation. Create it as: image/doc.

Now, we have to configure doxygen thanks to a dedicated file named Doxyfile. This file is available here, save it under this new doc directory.

We can build and browse the documentation like so:

$> cmt make doc
$> open ../doc/html/index.html

We can now modify the documentation of our code and inspect these modifications once the documentation has been regenerated. Once the result looks satisfying, save and commit the modifications.

Note

It isn’t necessary to add ALL the documentation files to svn. Indeed, these output files can be automatically generated from the Doxyfile. It is thus sufficient to just add that file to the repository.

$> svn add ../doc
$> svn revert --depth infinity ../doc/html
$> svn commit -m "added the doc generation with Doxygen management"

You could also update your ~/.subversion/config file in order to definitely ignore the html directory.

_images/validate-step.jpg

Validate this step