Termipankki
  1. A
    1. API
    2. ASAN
    3. Access specifiers
  2. C
    1. Constructor
    2. const
  3. G
    1. GDB
    2. g++
  4. M
    1. Make
    2. Memory Leak
  5. P
    1. Pointer
  6. R
    1. Recursion
  7. S
    1. std
  8. V
    1. Valgrind
Ratkaistu: / tehtävää

LAB7_PIXELMANCY: The Final Quest

Due date: 2026-04-27 23:59.

Pixelmancy

Pixelmancy is a C++ project that can generate GIF files, as shown below. It's designed as a practice exercise for C++ students and should not be treated as a template for optimal project structure. The project intentionally contains bugs for you to fix, starting with the Color Problem. If you are already familiar with CMake, you may begin with that task instead.
Snowing Tree
Snowing on the tree

Download The Provided Files

You can get the files from here: Pixelmancy_v1.0.1.zip
Few problems are fixed in v1.0.1.
- Library conflict with local installed libraries. eg: libfmt
- Not being able to diff file paths with spaces
Old version: Pixelmancy.zip

Project structure

This project comprises a standalone application and a test suite. The root CMakeLists.txt builds the Pixelmancy library and links it to the 'standalone' project. The standalone project generates an executable, PixelmancyExample, which executes the evaluation code for this assignment.

Dependencies

Libraries used

All libraries reside in libs folder and you don't have to install anything.

How to build and run

Recommended steps

    make config_debug
    make build
    ./build/standalone/PixelmancyExample -h
    make build
    ./build/standalone/PixelmancyExample -h
    make clean
    make forced_clean
    make config_debug
    make build
    ./build/standalone/PixelmancyExample -h

Using Makefile

To build, first use CMake to configure and generate the build system. The top-level Makefile provides various configuration options.
Once the build system is configured, use the following command to build the executables.
Note! : If you navigate into the build folder at this point or after configuring, you'll find another Makefile (build/Makefile) generated by CMake specifically for the project.
This Makefile within the build directory provides more granular build targets.
For example:

Executable targets

Depending on your configuration, one or two executables will be created.

cmake - Build system generator

CMake is essential for building this project. Please ensure it is installed on your system. We utilize CMake to generate the project's build system, which defaults to a Makefile on Linux. This section provides informational details about CMake; you don't need to read it to complete the basic build process.

Simple usage

  1. Create a build directory: Within the project's root directory, create a build directory (e.g., mybuild).
  2. Navigate to the build directory: Change your current directory to the newly created mybuild folder.
  3. Configure the build system: Execute the command cmake ... This command instructs CMake to use the CMakeLists.txt file located in the parent directory to generate the build system (typically a Makefile on Linux).
  4. Build the project: While still inside the mybuild folder, run the command make. This will compile the project.
The resulting executable, PixelmancyExample, will be located in ./standalone/ within the mybuild directory. It is built from the source file standalone/main.cpp.
mkdir mybuild
cd mybuild
cmake .. -DPIXELMANCY_BUILD_TESTS=OFF
make -j 4
./standalone/PixelmancyExample -h
You can delete the mybuild directory and repeat the process, optionally choosing a different name for the build directory. After making code changes, simply run make again from within the build folder to recompile. Re-running cmake .. is generally not necessary unless you have made significant modifications to the CMakeLists.txt files. In such cases, a clean build (deleting the mybuild directory and starting over) might be required.
You can also generate a Ninja build system in a similar manner:
mkdir mybuild
cd mybuild
cmake -G ninja ..
ninja
./standalone/PixelmancyExample -h

Some cmake magic

Examine the include directives in standalone/main.cpp. You'll notice the inclusion of "config.hpp". Locate this file within the build directory (mybuild in our example) where you executed cmake ... You can use the find command mentioned below if needed. Inspect the contents of config.hpp. This file is automatically generated during the CMake configuration step.
Now, open the template file standalone/config.hpp.in located in the source directory and add a line, for example: #define MY_DEBUG 1. After saving the changes to config.hpp.in, go back to your mybuild directory and run make. Did you need to run cmake .. again for this change to take effect? Verify if your newly added line (#define MY_DEBUG 1) now appears in the generated config.hpp file.
find . -name config.hpp

Color Problem

Color is a straightforward structure containing four 8-bit unsigned integer members: red, green, blue, and alpha. These members represent the RGBA color components for our Pixelmancy project, with each value ranging from 0 to 255.
The color functionality is specifically tested within the colorProblem function located in the standalone/main.cpp file.
To verify its correct operation, execute the PixelmancyExample executable with the -c flag:
Your task is to ensure that running this command produces no error messages related to color handling and that the colorProblem function confirms the successful addition of thirteen unique colors to a map, resulting in a map size of thirteen.

Submit Your Solution : Color problem

    ./standalone/PixelmancyExample -c

Sallitut tiedostojen nimet Color.hpp, ColorHash.hpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Distance problem

The ColorSpaceDistance class is designed to calculate the Euclidean distance of an RGB color from the origin within the 3D color space.
Running the PixelmancyExample executable with the -d flag will currently reveal some errors related to this calculation.
Your goal is to modify the ColorSpaceDistance class so that the distanceProblem function in standalone/main.cpp no longer outputs any error messages to the terminal. Please ensure that all previously identified issues have also been resolved before tackling this problem.

Submit Your Solution : Distance Problem

    ./build/standalone/PixelmancyExample -d

Sallitut tiedostojen nimet ColorSpaceDistance.hpp, ColorSpaceDistance.cpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Image problem

The Image class utilizes a ColorPalette to manage its colors. Instead of storing the full RGBA color for each pixel, the image data stores an index value. This index corresponds to a specific color entry within the ColorPalette. Therefore, to determine the actual color of a pixel, you look up the color at the pixel's stored index within the image's palette.
You can test the functionality related to the Image class and its ColorPalette by running the PixelmancyExample executable with the -i flag:
Two errors reported in the "image problem" log relate to how img and img2 are being handled when added to the images std::array. The code attempts to copy img and move img2. The errors indicate that img2 still appears to hold data after the move operation (even though a cleanup is intended to mark it as moved).
HINT: If you are stuck check the operator used for comparison.
HINT: Consider if a compiler-generated copy assignment operator would be suitable.

Submit Your Solution : Image problem

    ./build/standalone/PixelmancyExample -i

Sallitut tiedostojen nimet Image.cpp, Image.hpp, ColorPalette.hpp, ColorPalette.cpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Three PNG boxes problem

In this exercise, you will create three PNG images, which should consist of three boxes. To begin, run the PixelmancyExample executable with the -p flag:
Check why the images are not matching with reference images.

Submit Your Solution : Three PNG Boxes

    ./standalone/PixelmancyExample -p

Sallitut tiedostojen nimet Common.hpp, SquareObject.cpp, SquareObject.hpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

First GIF

In this exercise, you will create the first GIF animation using this project, which should consist of three frames. To begin, run the PixelmancyExample executable with the -t flag:
Three boxes GIF
Three frames
Start by addressing the segmentation fault that occurs when running the GIF generation. Once this crash is resolved, examine the threeBoxes function. Ensure the generated GIF output matches the reference GIF.
The generated GIF will be saved as data/output/three_boxes.gif, and the reference GIF for comparison is located at data/three_boxes.gif.
Hint: Ensure that you have successfully fixed the Color Problem exercise before attempting this one, as it might be a prerequisite.

Submit Your Solution : First GIF

    ./build/standalone/PixelmancyExample -t

Sallitut tiedostojen nimet Gif.cpp, CircleObject.cpp, CircleObject.hpp, Common.hpp, DrawableObject.cpp, Color.hpp, SquareObject.cpp, SquareObject.hpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Image Resize Problem

The GIF format we are working with has a limitation of supporting only 256 colors, defined by its color palette. One technique we employ to potentially reduce the number of distinct colors in an image is image resizing. For this resizing operation, we are using the nearest neighbor algorithm.
To begin, run the PixelmancyExample executable with the -r flag:
Your task is to correct the existing Image Image::resize(double percentage) const function. The goal is to ensure that when this function is used for downscaling, the program's output images closely match the expected reference images.
We will also explore another method of image manipulation, which involves directly modifying the image's color palette.
Ultimately, we aim to transform the image data/tree.png (which has dimensions of 400x400 pixels) into the following target image with dimensions of 200x200 pixels."
Tree reduced colors
Color reduced and palette changed

Submit Your Solution : Image Resize Problem

    ./build/standalone/PixelmancyExample -r

Sallitut tiedostojen nimet Image.hpp, Image.cpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Draw on image

Create any creative GIF you want. To begin, run the PixelmancyExample executable with the -g flag:
As far as your GIF does not match the given GIF you will get full marks for this.
Tree reduced colors GIF
Snowing on the tree with color changes

Submit Your GIF

    ./build/standalone/PixelmancyExample -g

Sallitut tiedostojen nimet Color.hpp, Gif.cpp

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Good luck!

Author

Rukshan Perrera
?
API stands for Application Programming Interface. In the context of this course, you can consider the header files to be such interfaces, as they determine what class functions and properties are public and thus accessible from anywhere.
AddressSanitizer (ASAN) is a memory error detector for C/C++. In this course, the makefiles will typically compile an executable that uses ASAN, with "-asan" at the end of its name.
The two notable access specifiers are:
  • public: class members defined after the public keyword are accessible from outside the class.
  • private: class members are generally private by default and thus not accessible from the outside
Constructor is a special non-static member function of a class that is used to initialize objects of its class type. A constructor is called upon initialization of an object. A constructor without arguments is a default constructor, but constructors that take arguments can be defined.
GDB, the GNU Project debugger, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed.
GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
  • Start your program, specifying anything that might affect its behavior.
  • Make your program stop on specified conditions.
  • Examine what has happened, when your program has stopped.
  • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.
GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files. Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files. When you write a program, you should write a makefile for it, so that it is possible to use Make to build and install the program.
Memory leak means that the program is not freeing up memory it reserves. The memory will be freed when the program terminates, but if a program keeps leaking more and more memory without terminating, it can become a huge issue!
A typical way for memory leaks to occur is reserving memory with new and not calling delete before the pointer goes out of scope.
Pointer variables store a memory address as their value. In other words, they point to some data. The data can be accessed by dereferencing the pointer. (Either like *p or p->...)
A recursive function calls itself from within it. The recursion call must be conditional or it would lead to an infinite loop.
Valgrind is another tool besides ASAN that you can use in this course. It can detect many memory-related errors that are common in C and C++ programs and that can lead to crashes and unpredictable behaviour.
const is a keyword meant to mark something as immutable
  • A const object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.
  • const keyword on an object's member function prevents the object from being modified in the function
  • Pointer declarations can have 2 const keywords, one to make the data that's pointed at unable to be modified and one to make the pointer itself unable to be modified
Using const improves code readability and prevents accidental modification of objects.
g++ is a C++ compiler that we primarily use for this course. It is the C++ compiler for the GNU compiler collection. You may sometimes see gcc being used instead of g++, which was originally the GNU C compiler, but calling gcc generally also compiles .cpp files as C++. However, calling g++ is preferred.
In C++, std stands for Standard Library, which is a collection of commonly useful classes and functions. Typically, these are defined in the std namespace.