Skip to content
Katie Dektar edited this page Dec 14, 2020 · 4 revisions

Usage

image.h provides a Color class and an Image class. Images can be loaded from file or created. Users may access and set per-pixel color data. Image can be modified by manipulating them at the pixel level, as well as by drawing lines, circles, rectangles and text. Images can be displayed and saved as bitmaps (an uncompressed format).

image_event.h provides a MouseEvent and a MouseEventListener interface. Extend the MouseEventListener interface and implement OnMouseEvent. To begin receiving mouse events, use Image::AddMouseEventListener to register for mouse events, and enter the event loop with Image::ShowUntilClosed. Note you will need to use Image::Flush (and cout::flush) to ensure updates are noted after calling Image::ShowUntilClosed.

Development

image.cc is backed by CImg, an open-source C++ image processing library. To update CImg.h to the latest, run make update_cimg in graphics/.

It would be possible to back image.cc with some other implementation, for example Skia or OpenGL. CImg was chosen because it is relatively light-weight, as all the implementation is contained within the CImg.h header.

Writing graphical assignments

Graphical assignments can vary between instructors handling all the drawing / animation / event handling logic in starter code to having students implement the entire thing. The more graphical work the instructor's starter code does, the less unit tests need to concern themselves with checking the image.

Example graphical assignments from CPSC121-2020F:

Getting started

Make a new repository from the cppaudit-graphics-template to get a template lab, including a copy of cpputils, example unittest, and a github action to test the unittest is working.

Writing testable graphical assignments:

  • Try to avoid floating-point math that could impact graphical layout or coloring. For example, a recursive fractal tree might have floating point math that impacts how it is drawn many iterations deep, while a recursive sierpinski's carpet will not have that issue over an image that's sized to a power of 3. Future work may include improving unit testing to check for "almost-equal" images, but that is not currently available.
  • Unit tests cannot view the image in a window, but they can look at a .bmp file. I've tended to include a method graphics::Image& GetImageForTesting() to allow unit tests to inspect the image without saving it.
  • If Image::ShowUntilClosed is called it will cause the unit tests to hang. Ensure Image::ShowUntilClosed is only called by the main program but not unit tests. This might require separating an Initialize from a Start method.
  • Use graphics::AnimationEventListener instead of Image::ShowFor to create animations. This allows mock animation events to be sent.

Writing unit tests for graphical programs

Color tests

graphics::Color has equality and inequality operator overrides so you can do the following, as expected, in gtest:

graphics::Color red(255, 0, 0);
ASSERT_EQ(image.GetColor(0, 0), red);

Image tests

If you want to test image equality use methods from image_test_utils.h in cpputils/graphics/test. These generate a expected vs actual image file using overlay or side-by-side, or highlighting differing pixels in red.

Event tests

You must call Image::Show before generating mouse or animation events, and tests must be run on a machine with an x server. If running on a headless server you can use the following steps to get an X server for unit testing:

sudo apt-get install xvfb
Xvfb :99 &
export DISPLAY=:99

Animation: use TestEventGenerator in cpputils/graphics/test to SendAnimationEvent as many times as desired.

Mouse: use TestEventGenerator in cpputils/graphics/test to move the mouse, click it, drag it, and release it.

Clone this wiki locally