// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- // // Example how to display an image, including animated images using // ImageMagick. For a full utility that does a few more things, have a look // at the led-image-viewer in ../utils // // Showing an image is not so complicated, essentially just copy all the // pixels to the canvas. How to get the pixels ? In this example we're using // the graphicsmagick library as universal image loader library that // can also deal with animated images. // You can of course do your own image loading or use some other library. // // This requires an external dependency, so install these first before you // can call `make image-example` // sudo apt-get update // sudo apt-get install libgraphicsmagick++-dev libwebp-dev -y // make image-example /* pour compiler: g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/imageScreen/test_image.cc -o /var/www/moduleair_pro_4g/matrix/imageScreen/test_image -lrgbmatrix g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/imageScreen/test_image.cc -o /var/www/moduleair_pro_4g/matrix/imageScreen/test_image -lrgbmatrix `GraphicsMagick++-config --cppflags --libs` pour lancer: sudo /var/www/moduleair_pro_4g/matrix/imageScreen/test_image /var/www/moduleair_pro_4g/matrix/imageScreen/ModuleAir128x64.png */ #include "led-matrix.h" #include #include #include #include #include #include #include using rgb_matrix::Canvas; using rgb_matrix::RGBMatrix; using rgb_matrix::FrameCanvas; // Make sure we can exit gracefully when Ctrl-C is pressed. volatile bool interrupt_received = false; static void InterruptHandler(int signo) { interrupt_received = true; } using ImageVector = std::vector; // Given the filename, load the image and scale to the size of the // matrix. // // If this is an animated image, the resutlting vector will contain multiple. static ImageVector LoadImageAndScaleImage(const char *filename, int target_width, int target_height) { ImageVector result; ImageVector frames; try { readImages(&frames, filename); } catch (std::exception &e) { if (e.what()) fprintf(stderr, "%s\n", e.what()); return result; } if (frames.empty()) { fprintf(stderr, "No image found."); return result; } // Animated images have partial frames that need to be put together if (frames.size() > 1) { Magick::coalesceImages(&result, frames.begin(), frames.end()); } else { result.push_back(frames[0]); // just a single still image. } for (Magick::Image &image : result) { image.scale(Magick::Geometry(target_width, target_height)); } return result; } // Copy an image to a Canvas. Note, the RGBMatrix is implementing the Canvas // interface as well as the FrameCanvas we use in the double-buffering of the // animted image. void CopyImageToCanvas(const Magick::Image &image, Canvas *canvas) { const int offset_x = 0, offset_y = 0; // If you want to move the image. // Copy all the pixels to the canvas. for (size_t y = 0; y < image.rows(); ++y) { for (size_t x = 0; x < image.columns(); ++x) { const Magick::Color &c = image.pixelColor(x, y); if (c.alphaQuantum() < 256) { canvas->SetPixel(x + offset_x, y + offset_y, ScaleQuantumToChar(c.redQuantum()), ScaleQuantumToChar(c.greenQuantum()), ScaleQuantumToChar(c.blueQuantum())); } } } } // An animated image has to constantly swap to the next frame. // We're using double-buffering and fill an offscreen buffer first, then show. void ShowAnimatedImage(const ImageVector &images, RGBMatrix *matrix) { FrameCanvas *offscreen_canvas = matrix->CreateFrameCanvas(); while (!interrupt_received) { for (const auto &image : images) { if (interrupt_received) break; CopyImageToCanvas(image, offscreen_canvas); offscreen_canvas = matrix->SwapOnVSync(offscreen_canvas); usleep(image.animationDelay() * 10000); // 1/100s converted to usec } } } int usage(const char *progname) { fprintf(stderr, "Usage: %s [led-matrix-options] \n", progname); rgb_matrix::PrintMatrixFlags(stderr); return 1; } int main(int argc, char *argv[]) { Magick::InitializeMagick(*argv); // Check if a filename was provided if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char *filename = argv[1]; // Initialize with hardcoded defaults for your specific hardware RGBMatrix::Options defaults; defaults.hardware_mapping = "moduleair_pinout"; defaults.rows = 64; defaults.cols = 128; defaults.chain_length = 1; defaults.parallel = 1; defaults.row_address_type = 3; defaults.show_refresh_rate = true; defaults.brightness = 100; defaults.pwm_bits = 1; defaults.panel_type = "FM6126A"; defaults.disable_hardware_pulsing = false; // Set up runtime options (still needed) rgb_matrix::RuntimeOptions runtime_opt; runtime_opt.gpio_slowdown = 4; // Adjust if needed for your Pi model runtime_opt.daemon = 0; runtime_opt.drop_privileges = 0; // Set to 1 if not running as root // Handle Ctrl+C to exit gracefully signal(SIGTERM, InterruptHandler); signal(SIGINT, InterruptHandler); // Create the matrix with our defaults RGBMatrix *matrix = RGBMatrix::CreateFromOptions(defaults, runtime_opt); if (matrix == NULL) { fprintf(stderr, "Failed to create matrix\n"); return 1; } // Load and process the image ImageVector images = LoadImageAndScaleImage(filename, matrix->width(), matrix->height()); // Display the image(s) switch (images.size()) { case 0: // failed to load image fprintf(stderr, "Failed to load image\n"); break; case 1: // single image to show CopyImageToCanvas(images[0], matrix); while (!interrupt_received) sleep(1); // Until Ctrl-C is pressed break; default: // animation with multiple frames ShowAnimatedImage(images, matrix); break; } // Clean up matrix->Clear(); delete matrix; return 0; }